一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

標準爬蟲初探,來自Python之父的大餐!

 dinghj 2014-11-17

首先不得不承認自己做了標題黨,本文實質(zhì)是分析500lines or less的crawl工程,這個工程的地址是https://github.com/aosabook/500lines,有興趣的同學可以看看,是一個非常高質(zhì)量的開源工程集合,據(jù)說要寫一本書,不過看著代碼提交記錄,這本書面世時間應該不會很快。這篇文章寫得很渣,錯誤一定要提啊。。。

網(wǎng)絡爬蟲從一個或若干初始網(wǎng)頁的URL開始,獲得初始網(wǎng)頁上的URL,在抓取網(wǎng)頁的過程中,不斷從當前頁面上抽取新的URL放入隊列,直到滿足系統(tǒng)的一定停止條件。簡單的可以將網(wǎng)絡爬蟲理解為一個帶有終止條件的while循環(huán),在條件不觸發(fā)的情況下,爬蟲就不斷的從每個以及獲取的url發(fā)送請求獲取頁面數(shù)據(jù),然后解析當前頁面的url,不斷迭代下去。在crawl工程當中,完成這一過程的是crawler類,他并未采用廣度優(yōu)先或是深度優(yōu)先的爬蟲,在當前請求失敗的時候就通過python掛起當前任務,然后在之后再進行調(diào)度,這可以勉強理解為基于網(wǎng)絡連通性的A*搜索,其運行方式如下所示:

對一個初始化后的crawler對象,其中存在一個url,一個todo集合,存儲尚未繼續(xù)呢爬蟲操作的url;一個busy集合,保存等待其他爬蟲數(shù)據(jù)的url集合;一個done集合,保存完成頁面爬取的url集合。爬蟲的核心就是這個死循環(huán),首先爬蟲從todo集合當中獲取一個url,然后初始化fetch對象用于獲取頁面上的url,最后進行任務調(diào)度執(zhí)行一個url請求任務。這段流程的代碼如下所示。

  1. @asyncio.coroutine 
  2. def crawl(self): 
  3.         """Run the crawler until all finished.""" 
  4.         with (yield from self.termination): 
  5.             while self.todo or self.busy: 
  6.                 if self.todo: 
  7.                     url, max_redirect = self.todo.popitem() 
  8.                     fetcher = Fetcher(url, 
  9.                                       crawler=self, 
  10.                                       max_redirect=max_redirect, 
  11.                                       max_tries=self.max_tries, 
  12.                                       ) 
  13.                     self.busy[url] = fetcher 
  14.                     fetcher.task = asyncio.Task(self.fetch(fetcher)) 
  15.                 else: 
  16.                     yield from self.termination.wait() 
  17.         self.t1 = time.time() 

一個爬蟲很明顯不會僅僅由一個死循環(huán)構(gòu)成,在crawl外層需要其他模塊支持其操作,包括網(wǎng)絡連接,url獲取,任務調(diào)度等任務,整個crawl工程的調(diào)度框架如下所示:

在crawl創(chuàng)建初始化時候首先創(chuàng)建一個ConnectionPool:

  1. self.pool = ConnectionPool(max_pool, max_tasks) 

其中保留屬性connections和queue,分別保存連接的集合和隊列,用于后續(xù)調(diào)度;而connection中存儲host和端口號并支持ssl,通過asyncio.open_connection()獲取連接。

  1. self.connections = {} # {(host, port, ssl): [Connection, ...], ...} 
  2. self.queue = [] # [Connection, ...] 

任務執(zhí)行時crawl方法首先通過loop.run_until_complete(crawler.crawl())加載到event loop當中,然后用上述語句構(gòu)建的鏈接池ConnectionPool中保存connection對象,獲取連接對象然后通過fetcher對象的fetch方法進行數(shù)據(jù)爬取。對于一個url請求任務,使用fetcher進行處理,調(diào)度則是用asyncio.Task方法進行的調(diào)度。其中fetch方法獲取被掛起的generator,交給asyncio.Task執(zhí)行。

通過yield from和asynico.coroutine語句,將這個方法變?yōu)閳?zhí)行過程中的generator,在執(zhí)行fetcher.fetch()方法時候如果被掛起,則通過調(diào)度程序進行處理。

fetcher.fetch()方法是網(wǎng)絡爬蟲的核心方法,負責從網(wǎng)絡上獲取頁面數(shù)據(jù)并將其中的url加載到todo集合當中,該方法嘗試獲取頁面數(shù)據(jù)當嘗試次數(shù)達到上限時停止操作,獲取成功的html數(shù)據(jù)和外部鏈接以及重定向鏈接都將被存儲。在url鏈接次數(shù)到達上限的情況下,將停止這個url的鏈接操作,輸出出錯日志。之后針對頁面的不同狀態(tài),采取不同的處理方式。

下面的代碼是crawling.py文件從333行開始(crawling.py)到對應方法結(jié)束的區(qū)域,通過對頁面status的判斷選擇不同的處理方式。其中通過正則表達式,獲取頁面上的url信息,這里選擇為href開頭的字符串,核心url提取的代碼在下面: 

  1. # Replace href with (?:href|src) to follow image links. 
  2. self.urls = set(re.findall(r'(?i)href=["\']?([^\s"\'<>]+)',body)) 
  3. if self.urls: 
  4.     logger.warn('got %r distinct urls from %r',len(self.urls), self.url) 
  5.     self.new_urls = set() 
  6.     for url in self.urls: 
  7.         url = unescape(url) 
  8.         url = urllib.parse.urljoin(self.url, url) 
  9.         url, frag = urllib.parse.urldefrag(url) 
  10.         if self.crawler.add_url(url): 
  11.             self.new_urls.add(url) 

通過代碼,很明顯就可以看出正則匹配結(jié)果存儲在urls集合當中并通過for循環(huán)依次進行處理,加入到當前fetcher的crawler對象的todo集合當中。

在之前分析的基礎上對主文件crawl.py進行進一步分析,可以得到整體爬蟲的架構(gòu):

在主文件當中首先通過argparse.ArgumentParser進行解析,設置控制臺的數(shù)據(jù)讀取和控制,其中選擇了IOCP作為windows環(huán)境下的event loop對象。主方法,首先通過parse_args返回存儲命令行數(shù)據(jù)的字典,如果沒有root屬性,則給出提示。然后配置日志級別,指示日志的輸出級別,低于最低級別的不輸出。

通過入口函數(shù)main方法進入程序的時候,首先根據(jù)來自命令行參數(shù)對Crawler進行初始化,同時獲取使用asyncio的loop event對象,執(zhí)行run_until_complete方法,會一直執(zhí)行到這個程序結(jié)束運行。

除此之外reporting.py用于打印當前任務執(zhí)行情況。其中fetcher_report(fetcher, stats, file=None)打印這個url的工作狀態(tài),url就是fetcher的url屬性;report(crawler, file=None)打印整個工程所有完成的url工作狀態(tài)。

至此,crawl的基本框架就展現(xiàn)在眼前了。至于在這個程序中出現(xiàn)的一些不容易理解的python語言特性,某些應用到的核心模塊,將在下一篇博客《標準爬蟲分析,精簡不簡單!》中進行闡述。

【編輯推薦】

【責任編輯:張偉 TEL:(010)68476606】

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    日本人妻免费一区二区三区| 亚洲精品国产福利在线| 日韩精品综合免费视频| 国产亚洲二区精品美女久久| 久热青青草视频在线观看| 日韩中文字幕狠狠人妻| 少妇一区二区三区精品| 欧美多人疯狂性战派对| 日本欧美一区二区三区在线播| 色婷婷久久五月中文字幕| 久久精品a毛片看国产成人| 免费在线成人激情视频| 欧美日韩国产免费看黄片| 亚洲欧洲在线一区二区三区| 欧美一区二区三区性视频| 东京热男人的天堂社区| 91香蕉国产观看免费人人| 女人精品内射国产99| 亚洲熟女熟妇乱色一区| 国产色第一区不卡高清| 国产高清视频一区不卡| 亚洲国产精品无遮挡羞羞| 色哟哟哟在线观看视频| 美女被啪的视频在线观看| 国产不卡视频一区在线| 成人午夜爽爽爽免费视频| 亚洲欧美日本成人在线| 欧美日韩国产精品第五页| 精品香蕉一区二区在线| 国产三级黄片在线免费看| 国产亚洲欧美日韩国亚语| 99久久精品国产麻豆| 中文字幕日韩欧美一区| 亚洲av一区二区三区精品| 五月综合婷婷在线伊人| 国产成人亚洲综合色就色| 日本熟妇五十一区二区三区| 色婷婷亚洲精品综合网| 欧美乱妇日本乱码特黄大片| 久久亚洲午夜精品毛片| 日韩成人h视频在线观看|