如何用一行代碼讓gevent爬蟲提速100%
用python做網(wǎng)絡(luò)開發(fā)的人估計都聽說過gevent這個庫,gevent是一個第三方的python協(xié)程庫,其是在微線程庫greenlet的基礎(chǔ)上構(gòu)建而成,并且使用了epoll事件監(jiān)聽機制,這讓gevent具有很好的性能并且比greenlet更好用。根據(jù)gevent官方的資料(網(wǎng)址:http://www.gevent.org),gevent具有以下特點:
筆者總結(jié)一下,gevent大致原理就是當一個greenlet遇到需要等待的操作時(多為IO操作),比如網(wǎng)絡(luò)IO/睡眠等待,這時就會自動切換到其他的greenlet,等上述操作完成后,再在適當?shù)臅r候切換回來繼續(xù)執(zhí)行。在這個過程中其實仍然只有一個線程在執(zhí)行,但因為我們在等待某些IO操作時,切換到了其他操作,避免了無用的等待,這就為我們大大節(jié)省了時間,提高了效率。
筆者也是在看了gevent這么多的優(yōu)點之后,感覺有必要上手試一試,但起初效果非常不理想,速度提升并不大,后來在仔細研究了gevent的用法之后,發(fā)現(xiàn)gevent的高效率是有條件的,而其中一個重要條件就是monkey patch的使用,也就是我們常說的猴子補丁。
monkey patch就是在不改變源代碼的情況下,對程序進行更改和優(yōu)化,其主要適用于動態(tài)語言。通過monkey patch,gevent替換了標準庫里面大部分的阻塞式系統(tǒng)調(diào)用,比如socket、ssl、threading和select等,而變?yōu)閰f(xié)作式運行。下面筆者還是通過代碼來演示一下monkey patch的用法以及使用條件。筆者展示的這個程序是一個小型的爬 蟲程序,程序代碼量少,便于閱讀和運行,同時也能較好地測試出monkey patch的提升程度。主要思路是從Box Office Mojo網(wǎng)站抓取北美電影市場今年第二季度上映的電影,然后從每部電影的信息頁面提取出每部電影的電影分級,然后把每部電影的名稱和其對應(yīng)分級保存在一個字典當中,再測試一下整個過程的時間。在這里,我們主要測試三種情況下的程序完成時間,分別是普通不使用gevent的爬 蟲,使用gevent但不用monkey patch的爬 蟲,以及使用gevent和monkey patch的爬 蟲。
首先看普通不使用gevent的爬 蟲。
先導(dǎo)入需要的庫。
然后讀取第二季度上映電影的頁面。
上述代碼中變量url就是第二季度上映電影的網(wǎng)頁地址,其頁面截圖如圖1所示。headers是爬蟲模擬瀏覽器的頭部信息,每部電影的信息頁面就是圖1中表格頭一行列名Release下面每部電影名稱所包含的網(wǎng)址,點擊每部電影名稱就可進入其對應(yīng)頁面。因為這個網(wǎng)址是相對地址,所以要轉(zhuǎn)換成絕對地址。
圖1. 第二季度上映電影的頁面
接下來是每部電影的信息頁面的讀取。
這個函數(shù)就是為了讀取每部電影信息頁面的信息,其功能和上面讀取url頁面的功能類似,都非常簡單,沒有過多可說的。在每部電影頁面中,我們要讀取的每部電影的分級信息就在Genres這一行,比如圖2中電影The Wretched,其Genres信息就是Horror。
圖2. 示例電影信息頁面
接下來是時間測算。
我們測算時間用time.time()方法,用結(jié)束時間減去開始時間就是程序運行時間,這里我們主要測試spider這個函數(shù)多次運行的時間。結(jié)果顯示,該過程耗時59.6188秒。
第二個爬蟲是使用gevent但不用monkey patch的爬蟲。其完整代碼如下。
這里絕大部分代碼和前面爬蟲代碼相同,但多了一個task_list變量,其是用于存放協(xié)程的列表,我們從gevent_start = time.time()這行開始看,因為前面的代碼都和之前的爬蟲相同。task = gevent.spawn(spider, u)是生成gevent中生成協(xié)程的方法,task_list.append(task)是把每個協(xié)程放入這個列表中,而gevent.joinall(task_list)就是運行所有協(xié)程。上面這些過程和我們運行多線程的方式非常相似。運行結(jié)果是59.1744秒。
最后一個爬蟲就是同時使用gevent和monkey patch的爬蟲,在這里筆者不再粘貼代碼,因為其代碼和第二個爬蟲幾乎一模一樣,只有一個區(qū)別,就是多了一行代碼from gevent import monkey; monkey.patch_all(),注意這是一行代碼,不過包含兩個語句,用分號放在了一起。最重要的是,這行代碼要放在所有代碼的前面,切記?。?!
這個爬蟲的運行結(jié)果是26.9184秒。
筆者把這里三個爬蟲分別放在三個文件中,分別命名為normal_spider.py、gevent_spider_no.py和gevent_spider.py,分別表示普通不用gevent的爬蟲、使用gevent但不用monkey patch的爬蟲、使用gevent和monkey patch的爬蟲。這里有一點要注意,monkey patch暫不支持jupyter notebook,所以這三個程序要在命令行中使用,不能在notebook中使用。
最后把三種爬蟲的結(jié)果總結(jié)如下。
圖3. 三種爬蟲的結(jié)果對比
可以看出使用了gevent但不用monkey patch的爬蟲和普通爬蟲的運行時間幾乎完全相等,而在用了monkey patch以后,運行時間只有前面程序的一半不到,速度提升了大約120%,僅僅一行代碼就帶來如此大的速度提升,可見monkey patch的作用還是很大的。而對于前兩個爬蟲的速度幾乎完全一樣,筆者認為原因在于這兩個程序都是單線程運行,本質(zhì)上沒有太大區(qū)別,同時網(wǎng)頁讀取數(shù)量較?。ㄖ挥?8個網(wǎng)頁),也很難看出gevent的效果。
從本例中可以看出monkey patch還是有不小提升的,但gevent目前只對常見庫尤其是官方標準庫有patch作用,其他第三方庫的效果還不得而知,所以對monkey patch的使用還是要視情況而定。本文的代碼筆者放在gitee代碼網(wǎng)站上,網(wǎng)址是https://gitee.com/leonmovie/speed-up-gevent-spider-with-monkey-patch,如有需要可以自行下載。
聲明:免責聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻自行上傳,本網(wǎng)站不擁有所有權(quán),也不承認相關(guān)法律責任。如果您發(fā)現(xiàn)本社區(qū)中有涉嫌抄襲的內(nèi)容,請發(fā)
送郵件至:operations@xinnet.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,本站將立刻刪除涉嫌侵權(quán)內(nèi)容。本站原創(chuàng)內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時
需注明出處:新網(wǎng)idc知識百科