Python 函數(shù)式編程可以讓程序的思路更加清晰、易懂
定義相應(yīng)的函數(shù),通過(guò)調(diào)用函數(shù)來(lái)執(zhí)行爬蟲程序
from urllib import request from urllib import parse # 拼接URL地址 def get_url(word): url = 'http://www.baidu.com/s?{}' #此處使用urlencode()進(jìn)行編碼 params = parse.urlencode({'wd':word}) url = url.format(params) return url # 發(fā)請(qǐng)求,保存本地文件 def request_url(url,filename): headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0'} # 請(qǐng)求對(duì)象 + 響應(yīng)對(duì)象 + 提取內(nèi)容 req = request.Request(url=url,headers=headers) res = request.urlopen(req) html = res.read().decode('utf-8') # 保存文件至本地 with open(filename,'w',encoding='utf-8') as f: f.write(html) # 主程序入口 if __name__ == '__main__': word = input('請(qǐng)輸入搜索內(nèi)容:') url = get_url(word) filename = word + '.html' request_url(url,filename)
下面以類的形式編寫爬蟲程序,并在類下編寫不同的功能函數(shù),代碼如下所示:
from urllib import request,parse import time import random from ua_info import ua_list #使用自定義的ua池 #定義一個(gè)爬蟲類 class TiebaSpider(object): #初始化url屬性 def __init__(self): self.url='http://tieba.baidu.com/f?{}' # 1.請(qǐng)求函數(shù),得到頁(yè)面,傳統(tǒng)三步 def get_html(self,url): req=request.Request(url=url,headers={'User-Agent':random.choice(ua_list)}) res=request.urlopen(req) #windows會(huì)存在亂碼問題,需要使用 gbk解碼,并使用ignore忽略不能處理的字節(jié) #linux不會(huì)存在上述問題,可以直接使用decode('utf-8')解碼 html=res.read().decode("gbk","ignore") return html # 2.解析函數(shù),此處代碼暫時(shí)省略,還沒介紹解析模塊 def parse_html(self): pass # 3.保存文件函數(shù) def save_html(self,filename,html): with open(filename,'w') as f: f.write(html) # 4.入口函數(shù) def run(self): name=input('輸入貼吧名:') begin=int(input('輸入起始頁(yè):')) stop=int(input('輸入終止頁(yè):')) # +1 操作保證能夠取到整數(shù) for page in range(begin,stop+1): pn=(page-1)*50 params={ 'kw':name, 'pn':str(pn) } #拼接URL地址 params=parse.urlencode(params) url=self.url.format(params) #發(fā)請(qǐng)求 html=self.get_html(url) #定義路徑 filename='{}-{}頁(yè).html'.format(name,page) self.save_html(filename,html) #提示 print('第%d頁(yè)抓取成功'%page) #每爬取一個(gè)頁(yè)面隨機(jī)休眠1-2秒鐘的時(shí)間 time.sleep(random.randint(1,2)) #以腳本的形式啟動(dòng)爬蟲 if __name__=='__main__': start=time.time() spider=TiebaSpider() #實(shí)例化一個(gè)對(duì)象spider spider.run() #調(diào)用入口函數(shù) end=time.time() #查看程序執(zhí)行時(shí)間 print('執(zhí)行時(shí)間:%.2f'%(end-start)) #爬蟲執(zhí)行時(shí)間
以面向?qū)ο蠓椒ň帉懪老x程序時(shí),思路簡(jiǎn)單、邏輯清楚,非常容易理解,上述代碼主要包含了四個(gè)功能函數(shù),它們分別負(fù)責(zé)了不同的功能,總結(jié)如下:
1) 請(qǐng)求函數(shù)
請(qǐng)求函數(shù)最終的結(jié)果是返回一個(gè) HTML 對(duì)象,以方便后續(xù)的函數(shù)調(diào)用它。
2) 解析函數(shù)
解析函數(shù)用來(lái)解析 HTML 頁(yè)面,常用的解析模塊有正則解析模塊、bs4 解析模塊。通過(guò)分析頁(yè)面,提取出所需的數(shù)據(jù),在后續(xù)內(nèi)容會(huì)做詳細(xì)介紹。
3) 保存數(shù)據(jù)函數(shù)
該函數(shù)負(fù)責(zé)將抓取下來(lái)的數(shù)據(jù)保至數(shù)據(jù)庫(kù)中,比如 MySQL、MongoDB 等,或者將其保存為文件格式,比如 csv、txt、excel 等。
4) 入口函數(shù)
入口函數(shù)充當(dāng)整個(gè)爬蟲程序的橋梁,通過(guò)調(diào)用不同的功能函數(shù),實(shí)現(xiàn)數(shù)據(jù)的最終抓取。入口函數(shù)的主要任務(wù)是組織數(shù)據(jù),比如要搜索的貼吧名、編碼 url 參數(shù)、拼接 url 地址、定義文件保存路徑。
爬蟲程序結(jié)構(gòu)
用面向?qū)ο蟮姆椒ň帉懪老x程序時(shí),邏輯結(jié)構(gòu)較為固定,總結(jié)如下:
# 程序結(jié)構(gòu) class xxxSpider(object): def __init__(self): # 定義常用變量,比如url或計(jì)數(shù)變量等 def get_html(self): # 獲取響應(yīng)內(nèi)容函數(shù),使用隨機(jī)User-Agent def parse_html(self): # 使用正則表達(dá)式來(lái)解析頁(yè)面,提取數(shù)據(jù) def write_html(self): # 將提取的數(shù)據(jù)按要求保存,csv、MySQL數(shù)據(jù)庫(kù)等 def run(self): # 主函數(shù),用來(lái)控制整體邏輯 if __name__ == '__main__': # 程序開始運(yùn)行時(shí)間 spider = xxxSpider() spider.run()
爬蟲程序隨機(jī)休眠
在入口函數(shù)代碼中,包含了以下代碼:
#每爬取一個(gè)頁(yè)面隨機(jī)休眠1-2秒鐘的時(shí)間 time.sleep(random.randint(1,2))
爬蟲程序訪問網(wǎng)站會(huì)非常快,這與正常人類的點(diǎn)擊行為非常不符。因此,通過(guò)隨機(jī)休眠可以使爬蟲程序模仿成人類的樣子點(diǎn)擊網(wǎng)站,從而讓網(wǎng)站不易察覺是爬蟲訪問網(wǎng)站,但這樣做的代價(jià)就是影響程序的執(zhí)行效率