日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
如何用一行代碼讓gevent爬蟲(chóng)提速100%

用python做網(wǎng)絡(luò)開(kāi)發(fā)的人估計(jì)都聽(tīng)說(shuō)過(guò)gevent這個(gè)庫(kù),gevent是一個(gè)第三方的python協(xié)程庫(kù),其是在微線程庫(kù)greenlet的基礎(chǔ)上構(gòu)建而成,并且使用了epoll事件監(jiān)聽(tīng)機(jī)制,這讓gevent具有很好的性能并且比greenlet更好用。根據(jù)gevent官方的資料(網(wǎng)址:http://www.gevent.org),gevent具有以下特點(diǎn):

創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),遂溪企業(yè)網(wǎng)站建設(shè),遂溪品牌網(wǎng)站建設(shè),網(wǎng)站定制,遂溪網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營(yíng)銷,網(wǎng)絡(luò)優(yōu)化,遂溪網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競(jìng)爭(zhēng)力。可充分滿足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶成長(zhǎng)自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。

  1.  基于libev或libuv的快速事件循環(huán)。
  2.  基于greenlet的輕量級(jí)執(zhí)行單元。
  3.  重復(fù)使用Python標(biāo)準(zhǔn)庫(kù)中的概念的API(例如,有event和 queues)。
  4.  具有SSL支持的協(xié)作套接字
  5.  通過(guò)線程池,dnspython或c-ares執(zhí)行的合作DNS查詢。
  6.  猴子修補(bǔ)實(shí)用程序,使第三方模塊能夠合作
  7.  TCP / UDP / HTTP服務(wù)器
  8.  子流程支持(通過(guò)gevent.subprocess)
  9.  線程池

筆者總結(jié)一下,gevent大致原理就是當(dāng)一個(gè)greenlet遇到需要等待的操作時(shí)(多為IO操作),比如網(wǎng)絡(luò)IO/睡眠等待,這時(shí)就會(huì)自動(dòng)切換到其他的greenlet,等上述操作完成后,再在適當(dāng)?shù)臅r(shí)候切換回來(lái)繼續(xù)執(zhí)行。在這個(gè)過(guò)程中其實(shí)仍然只有一個(gè)線程在執(zhí)行,但因?yàn)槲覀冊(cè)诘却承㊣O操作時(shí),切換到了其他操作,避免了無(wú)用的等待,這就為我們大大節(jié)省了時(shí)間,提高了效率。

筆者也是在看了gevent這么多的優(yōu)點(diǎn)之后,感覺(jué)有必要上手試一試,但起初效果非常不理想,速度提升并不大,后來(lái)在仔細(xì)研究了gevent的用法之后,發(fā)現(xiàn)gevent的高效率是有條件的,而其中一個(gè)重要條件就是monkey patch的使用,也就是我們常說(shuō)的猴子補(bǔ)丁。

monkey patch就是在不改變?cè)创a的情況下,對(duì)程序進(jìn)行更改和優(yōu)化,其主要適用于動(dòng)態(tài)語(yǔ)言。通過(guò)monkey patch,gevent替換了標(biāo)準(zhǔn)庫(kù)里面大部分的阻塞式系統(tǒng)調(diào)用,比如socket、ssl、threading和select等,而變?yōu)閰f(xié)作式運(yùn)行。下面筆者還是通過(guò)代碼來(lái)演示一下monkey patch的用法以及使用條件。筆者展示的這個(gè)程序是一個(gè)小型的爬蟲(chóng)程序,程序代碼量少,便于閱讀和運(yùn)行,同時(shí)也能較好地測(cè)試出monkey patch的提升程度。主要思路是從Box Office Mojo網(wǎng)站抓取北美電影市場(chǎng)今年第二季度上映的電影,然后從每部電影的信息頁(yè)面提取出每部電影的電影分級(jí),然后把每部電影的名稱和其對(duì)應(yīng)分級(jí)保存在一個(gè)字典當(dāng)中,再測(cè)試一下整個(gè)過(guò)程的時(shí)間。在這里,我們主要測(cè)試三種情況下的程序完成時(shí)間,分別是普通不使用gevent的爬蟲(chóng),使用gevent但不用monkey patch的爬蟲(chóng),以及使用gevent和monkey patch的爬蟲(chóng)。

首先看普通不使用gevent的爬蟲(chóng)。

先導(dǎo)入需要的庫(kù)。

 
 
 
 
  1. import time  
  2. import requests  
  3. from lxml import etree 

然后讀取第二季度上映電影的頁(yè)面。

 
 
 
 
  1. url = r'https://www.boxofficemojo.com/quarter/q2/2020/?grossesOption=totalGrosses' #第二季度上映電影的網(wǎng)址  
  2. headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'} #爬蟲(chóng)頭部  
  3. rsp = requests.get(url, headersheaders=headers) #讀取網(wǎng)頁(yè)  
  4. text = rsp.text #獲取網(wǎng)頁(yè)源碼  
  5. html = etree.HTML(text)  
  6. movie_relative_urls =  html.xpath(r'//td[@class="a-text-left mojo-field-type-release mojo-cell-wide"]/a/@href') #獲取每部電影的信息頁(yè)面的相對(duì)地址  
  7. movie_urls = [r'https://www.boxofficemojo.com'+u for u in movie_relative_urls] #把每部電影的相對(duì)地址換成絕對(duì)地址  
  8. genres_dict = {} #用于保存信息的字典 

上述代碼中變量url就是第二季度上映電影的網(wǎng)頁(yè)地址,其頁(yè)面截圖如圖1所示。headers是爬蟲(chóng)模擬瀏覽器的頭部信息,每部電影的信息頁(yè)面就是圖1中表格頭一行列名Release下面每部電影名稱所包含的網(wǎng)址,點(diǎn)擊每部電影名稱就可進(jìn)入其對(duì)應(yīng)頁(yè)面。因?yàn)檫@個(gè)網(wǎng)址是相對(duì)地址,所以要轉(zhuǎn)換成絕對(duì)地址。

圖1. 第二季度上映電影的頁(yè)面

接下來(lái)是每部電影的信息頁(yè)面的讀取。

 
 
 
 
  1. def spider(url): #這個(gè)函數(shù)主要用于讀取每部電影頁(yè)面中的電影分級(jí)信息  
  2.     rsp = requests.get(url, headersheaders=headers) #讀取每部電影的網(wǎng)頁(yè)  
  3.     text = rsp.text #獲取頁(yè)面代碼  
  4.     html = etree.HTML(text)  
  5.     genre = html.xpath(r'//div/span[text()="Genres"]/following-sibling::span[1]/text()')[0] #讀取電影分級(jí)信息  
  6.     title = html.xpath(r'//div/h1/text()')[0] #讀取電影名稱  
  7. genres_dict[title] = genre #把每部電影的名稱和分級(jí)信息存入字典 

這個(gè)函數(shù)就是為了讀取每部電影信息頁(yè)面的信息,其功能和上面讀取url頁(yè)面的功能類似,都非常簡(jiǎn)單,沒(méi)有過(guò)多可說(shuō)的。在每部電影頁(yè)面中,我們要讀取的每部電影的分級(jí)信息就在Genres這一行,比如圖2中電影The Wretched,其Genres信息就是Horror。

圖2. 示例電影信息頁(yè)面

接下來(lái)是時(shí)間測(cè)算。

 
 
 
 
  1. normal_start = time.time() #程序開(kāi)始時(shí)間  
  2. for u in movie_urls:  
  3.     spider(u)  
  4. normal_end = time.time() #程序結(jié)束時(shí)間  
  5. normal_elapse = normal_end - normal_start #程序運(yùn)行時(shí)間  
  6. print('The normal procedure costs %s seconds' % normal_elapse) 

我們測(cè)算時(shí)間用time.time()方法,用結(jié)束時(shí)間減去開(kāi)始時(shí)間就是程序運(yùn)行時(shí)間,這里我們主要測(cè)試spider這個(gè)函數(shù)多次運(yùn)行的時(shí)間。結(jié)果顯示,該過(guò)程耗時(shí)59.6188秒。

第二個(gè)爬蟲(chóng)是使用gevent但不用monkey patch的爬蟲(chóng)。其完整代碼如下。

 
 
 
 
  1. import time  
  2. from lxml import etree  
  3. import gevent  
  4. import requests  
  5. url = r'https://www.boxofficemojo.com/quarter/q2/2020/?grossesOption=totalGrosses'  
  6. headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'}  
  7. rsp = requests.get(url, headersheaders=headers)  
  8. text = rsp.text  
  9. html = etree.HTML(text)  
  10. movie_relative_urls =  html.xpath(r'//td[@class="a-text-left mojo-field-type-release mojo-cell-wide"]/a/@href')  
  11. movie_urls = [r'https://www.boxofficemojo.com'+u for u in movie_relative_urls]  
  12. genres_dict = {}  
  13. task_list = [] #用于存放協(xié)程的列表  
  14. def spider(url): 
  15.     rsp = requests.get(url, headersheaders=headers)  
  16.     text = rsp.text  
  17.     html = etree.HTML(text)  
  18.     genre = html.xpath(r'//div/span[text()="Genres"]/following-sibling::span[1]/text()')[0]  
  19.     title = html.xpath(r'//div/h1/text()')[0]  
  20.     genres_dict[title] = genre    
  21. gevent_start = time.time()  
  22. for u in movie_urls:  
  23.     task = gevent.spawn(spider, u) #生成協(xié)程  
  24.     task_list.append(task) #把協(xié)程放入這個(gè)列表    
  25. gevent.joinall(task_list) #運(yùn)行所有協(xié)程  
  26. gevent_end = time.time() 
  27. gevent_elapse = gevent_end - gevent_start  
  28. print('The gevent spider costs %s seconds' % gevent_elapse) 

這里絕大部分代碼和前面爬蟲(chóng)代碼相同,但多了一個(gè)task_list變量,其是用于存放協(xié)程的列表,我們從gevent_start = time.time()這行開(kāi)始看,因?yàn)榍懊娴拇a都和之前的爬蟲(chóng)相同。task = gevent.spawn(spider, u)是生成gevent中生成協(xié)程的方法,task_list.append(task)是把每個(gè)協(xié)程放入這個(gè)列表中,而gevent.joinall(task_list)就是運(yùn)行所有協(xié)程。上面這些過(guò)程和我們運(yùn)行多線程的方式非常相似。運(yùn)行結(jié)果是59.1744秒。

最后一個(gè)爬蟲(chóng)就是同時(shí)使用gevent和monkey patch的爬蟲(chóng),在這里筆者不再粘貼代碼,因?yàn)槠浯a和第二個(gè)爬蟲(chóng)幾乎一模一樣,只有一個(gè)區(qū)別,就是多了一行代碼from gevent import monkey; monkey.patch_all(),注意這是一行代碼,不過(guò)包含兩個(gè)語(yǔ)句,用分號(hào)放在了一起。最重要的是,這行代碼要放在所有代碼的前面,切記?。?!

這個(gè)爬蟲(chóng)的運(yùn)行結(jié)果是26.9184秒。

筆者把這里三個(gè)爬蟲(chóng)分別放在三個(gè)文件中,分別命名為normal_spider.py、gevent_spider_no.py和gevent_spider.py,分別表示普通不用gevent的爬蟲(chóng)、使用gevent但不用monkey patch的爬蟲(chóng)、使用gevent和monkey patch的爬蟲(chóng)。這里有一點(diǎn)要注意,monkey patch暫不支持jupyter notebook,所以這三個(gè)程序要在命令行中使用,不能在notebook中使用。

最后把三種爬蟲(chóng)的結(jié)果總結(jié)如下。

圖3. 三種爬蟲(chóng)的結(jié)果對(duì)比

可以看出使用了gevent但不用monkey patch的爬蟲(chóng)和普通爬蟲(chóng)的運(yùn)行時(shí)間幾乎完全相等,而在用了monkey patch以后,運(yùn)行時(shí)間只有前面程序的一半不到,速度提升了大約120%,僅僅一行代碼就帶來(lái)如此大的速度提升,可見(jiàn)monkey patch的作用還是很大的。而對(duì)于前兩個(gè)爬蟲(chóng)的速度幾乎完全一樣,筆者認(rèn)為原因在于這兩個(gè)程序都是單線程運(yùn)行,本質(zhì)上沒(méi)有太大區(qū)別,同時(shí)網(wǎng)頁(yè)讀取數(shù)量較?。ㄖ挥?8個(gè)網(wǎng)頁(yè)),也很難看出gevent的效果。

從本例中可以看出monkey patch還是有不小提升的,但gevent目前只對(duì)常見(jiàn)庫(kù)尤其是官方標(biāo)準(zhǔn)庫(kù)有patch作用,其他第三方庫(kù)的效果還不得而知,所以對(duì)monkey patch的使用還是要視情況而定。本文的代碼筆者放在gitee代碼網(wǎng)站上,網(wǎng)址是https://gitee.com/leonmovie/speed-up-gevent-spider-with-monkey-patch,如有需要可以自行下載。


本文標(biāo)題:如何用一行代碼讓gevent爬蟲(chóng)提速100%
文章轉(zhuǎn)載:http://m.5511xx.com/article/ccdhjhj.html