完整的爬蟲:
反扒機制,自動登入,代理IP等等
複制
示例爬蟲:
簡單的資料抓取,簡單的資料處理
複制
目的:
不使用爬蟲架構完成資料爬取
鞏固知識、合理程式設計、内部原理
複制
示例内容:
内容:
爬取直播網站
确定工作:
确定爬取資料:某個分類下各主播人氣的資料
确定實作結果:将人氣進行排序
準備:
分析網站結構
尋找包含爬取資訊的頁面
F12檢查網頁,定位資訊(主播姓名,人氣資料)
原理:
對html檔案進行文本分析并從中提取資訊
使用技術
正規表達式
具體步驟:
模拟HTTP請求,向伺服器發送請求,擷取到伺服器傳回的HTML
用正規表達式處理網頁文本,過濾出有用資料
找到相關常量标簽,作為正則的定位邊界
定位标簽:
盡量選擇具有唯一辨別的辨別的标簽
盡量選擇與目标資料相近的标簽
盡量選擇将所有目标資料都包含的标簽(閉合的标簽),比如包含姓名+人氣的标簽
上述即盡量選父标簽,不選兄弟标簽,為了易于構造正則提取内容
注意:
構造正則不是難點,難點是應對反爬蟲的措施
整體書寫規範
每行代碼不要過長
推薦書寫一個入口程式
推薦在入口中平行的調用邏輯代碼
每個方法中代碼盡量少
注意塊注釋和行級注釋的書寫格式
代碼結構:
複制
'''
類注釋
'''
class spider():
#抓取頁面内容(行注釋)
def __fetch_content(self):
'''
方法注釋
'''
pass
#資料抽取
def __analysis(self, htmls):
pass
#資料精煉
def __refine(self, pairs):
pass
#排序
def __sort(self, pairs):
pass
#排序的算子
def __seed(self, pairs):
pass
#資料展現
def __show(self, pairs):
pass
#函數入口
def go(self):
調用
s = spider()
s.go()
```
書寫代碼:
抓取頁面:
url = 'http://www.huya.com/g/lol'
分析原網頁:
複制
<li class="game-live-item" gid="1">
<a href="http://www.huya.com/yanmie" class="video-info new-clickstat" target="_blank" report='{"eid":"click/position","position":"lol/0/1/5","game_id":"1","ayyuid":"380335691"}'>
<img class="pic" data-original="//screenshot.msstatic.com/yysnapshot/1711a622dc4d670fe32de2018f78a2d030fcde37cfe8?imageview/4/0/w/338/h/190/blur/1" src="//a.msstatic.com/huya/main/assets/img/default/338x190.jpg" onerror="this.onerror=null; this.src='//a.msstatic.com/huya/main/assets/img/default/338x190.jpg';" alt="最強趙信折翼的直播" title="最強趙信折翼的直播">
<div class="item-mask"></div>
<i class="btn-link__hover_i"></i>
<em class="tag tag-blue">藍光</em> </a>
<a href="http://www.huya.com/yanmie" class="title new-clickstat" report='{"eid":"click/position","position":"lol/0/1/5","game_id":"1","ayyuid":"380335691"}' title="可以用趙信上王者第一的男人" target="_blank">可以用趙信上王者第一的男人</a>
<span class="txt">
<span class="avatar fl">
<img data-original="//huyaimg.msstatic.com/avatar/1081/63/c83bdc0701b64646c86065e273fd05_180_135.jpg" src="//a.msstatic.com/huya/main/assets/img/default/84x84.jpg" onerror="this.onerror=null; this.src='//a.msstatic.com/huya/main/assets/img/default/84x84.jpg';" alt="最強趙信折翼" title="最強趙信折翼">
<i class="nick" title="最強趙信折翼">最強趙信折翼</i>
</span>
<span class="num"><i class="num-icon"></i><i class="js-num">1.5萬</i></span>
</span>
</li>
複制
1 | 找到含目标資料的最小公約子集: |
---|
<span class="txt">
<span class="avatar fl">
<img data-original="//huyaimg.msstatic.com/avatar/1081/63/c83bdc0701b64646c86065e273fd05_180_135.jpg" src="//a.msstatic.com/huya/main/assets/img/default/84x84.jpg" onerror="this.onerror=null; this.src='//a.msstatic.com/huya/main/assets/img/default/84x84.jpg';" alt="最強趙信折翼" title="最強趙信折翼">
<i class="nick" title="最強趙信折翼">最強趙信折翼</i>
</span>
<span class="num"><i class="num-icon"></i><i class="js-num">1.5萬</i></span>
</span>
複制
目标資料:
最強趙信折翼,1.5萬
構造正規表達式:
選出上面的最小公約子集:
root_pattern = '<span class="txt">([\s\S]*?)\r\n</li>'
注意:
要加問号,聲明是非貪婪的比對
然後選出,姓名:
name_pattern = '<i class="nick" title="([\s\S]*?)">'
然後選出,人氣:
num_pattern = '<i class="js-num">([\s\S]*?)</i>'
注意:
上述正則的邊界并不一定是完整的html标簽,因為使用正則即對字元進行比對,是以可以随意拆分。
幾個重要功能:
擷取頁面内容:
from urllib import request
tmp = request.urlopen(spider.url)
htmls = tmp.read()
注意:此處的結果是位元組碼:bytes
必須要進行轉化:bytes->str
htmls = str(htmls,encoding='utf-8')
注意:不推薦列印出頁面内容,會出現解碼問題,可以加斷點調試
循環:
此處的循環需要擷取到下标,而直接for i in list,擷取不到下标
此時應該使用for index in range(0,len(list))這種形式
代碼:
for rank in range(0, len(pairs)):
print('第',rank,'名:',pairs[rank]['name'],':',pairs[rank]['number'])
排序:
此處使用内置函數sorted(iterable, cmp=None, key=None, reverse=False)
注意:
key = 函數名,此函數應該傳回排序的比較值
cmp = 函數名,此函數可以重寫排序規則
reverse=False,從小到大正序排列
代碼:
sorted(pairs,key = seed,reverse = True)
def seed(self, pairs):
tmp = pairs['number'].replace('萬','')
if('萬' in pairs['number']):
tmp = float(tmp) * 10000
return int(tmp)
完整的爬蟲代碼:
複制
from urllib import request
import re
class spider():
url = 'http://www.huya.com/g/lol'
root_pattern = '<span class="txt">([\s\S]*?)\r\n</li>' #父級目錄比對
# 使用概括字元集 [\d] [\w] [\s] [.]
#注意:要加問号,聲明是非貪婪的比對
name_pattern = '<i class="nick" title="([\s\S]*?)">'
num_pattern = '<i class="js-num">([\s\S]*?)</i>'
def __fetch_content(self): #加__的函數:私有方法
tmp = request.urlopen(spider.url)
htmls = tmp.read() #此處的結果是位元組碼:bytes
# bytes->str
htmls = str(htmls,encoding='utf-8')
a = 1#如果不添加這一句,htmls指派發生在最後一句
#那麼斷點停止時會得不到htmls的值,這時要人為多餘的添加一條語句并将斷點放到這裡即可
#print(htmls)不推薦列印,會出現解碼問題
return htmls
def __sort(self, pairs):
#def sorted(iterable, cmp=None, key=None, reverse=False)
#注意要指定key值
return sorted(pairs,key=self.__seed,reverse=True)
def __show(self, pairs):
#for循環中需要拿到序号,直接使用range形式的for循環
for rank in range(0, len(pairs)):
print('第',rank,'名:',pairs[rank]['name'],':',pairs[rank]['number'])
def __seed(self, pairs):
tmp = pairs['number'].replace('萬','')
if('萬' in pairs['number']):
tmp = float(tmp) * 10000
return int(tmp)
def __refine(self, pairs):
f = lambda p: {
'name':p['name'][0].strip(),
'number':p['number'][0]
}
return map(f, pairs)
def __analysis(self, htmls):
root_htm = re.findall(spider.root_pattern,htmls)
pairs = []
for item in root_htm:
name = re.findall(spider.name_pattern,item)
num = re.findall(spider.num_pattern,item)
pair = {'name':name,'number':num}
pairs.append(pair)
return pairs
#設定入口函數,這是一個主方法,裡面都是平級函數,推薦這種寫法
def go(self):
htmls = self.__fetch_content() #抓取頁面内容
pairs = self.__analysis(htmls) #抽取所需資料
pairs = list(self.__refine(pairs)) #資料精煉
pairs = self.__sort(pairs) #資料排序
self.__show(pairs) #資料顯示,或後續處理(入庫等)
複制
#執行個體化并調用入口函數
s = spider()
s.go()
```
注意事項:
如果需要調試,不推薦站樁print,推薦使用斷點調試
調試方法:
啟動應用程式 F5
單步執行F10
跳到下一個斷點 F5
調到函數内部 F11
例如在 html = tmp.read() 處打斷點
在目前斷點處,懸停滑鼠會顯示變量值,也可以在vscode左側的甲殼蟲選項中檢視變量的值
缺陷:
雖然通過類進行了封裝,但是其實最基礎的封裝
但是,複用性差,抵禦需求變化的能力太差,違反開閉原則
進階:
可以使用更加面向對象的設計來完成功能
借助構造函數__init__來對類進行帶參數的執行個體化:
代碼:
class Spider():
'''
This is a class
'''
url = ''
root_pattern = ''
name_pattern = ''
num_pattern = ''
def __init__(self,url,root_pattern,name_pattern,num_pattern):
Spider.url = url
Spider.root_pattern = root_pattern
Spider.name_pattern = name_pattern
Spider.num_pattern = num_pattern
s = Spider(
'http://www.huya.com/g/4',
'<span class="txt">([\s\S]*?)\r\n</li>',
'<i class="nick" title="([\s\S]*?)">',
'<i class="js-num">([\s\S]*?)</i>'
)
s.go()
類封裝的意義:
這樣封裝可以完成一個主播人氣排序的爬蟲類,參數有四個:
爬取的直播網站;
爬取的名稱人氣的父元素的正則
爬取名稱的正則
爬取人氣的正則
展望:
爬蟲子產品或架構:
BeautifulSoup子產品
Scrapy架構(多線程、分布式、較臃腫,看需求謹慎使用)
反反爬蟲技術:
頻繁爬取會使IP被封,需要使用定時器!切記!!
尋找代理IP庫,應對封IP
整個流程的核心:
爬取的原始資料如何處理,精煉
處理的結果如何存儲,分析
複制