<a target="_blank" href="http://www.pyspider.cn/book/pyspider/pyspider-quickstart-2.html">pyspider 中文文檔</a>
1. 抓取、更新排程多站點的特定的頁面
2. 需要對頁面進行結構化資訊提取
3. 靈活可擴充,穩定可監控
而這也是絕大多數python爬蟲的需求 —— 定向抓取,結構化化解析。但是面對結構迥異的各種網站,單一的抓取模式并不一定能滿足,靈活的抓取控制是必須的。為了達到這個目的,單純的配置檔案往往不夠靈活,于是,通過腳本去控制抓取是最後的選擇。
而去重排程,隊列,抓取,異常處理,監控等功能作為架構,提供給抓取腳本,并保證靈活性。最後加上web的編輯調試環境,以及web任務監控,即成為了這套架構。
pyspider的設計基礎是:以python腳本驅動的抓取環模型爬蟲
1. 通過python腳本進行結構化資訊的提取,follow連結排程抓取控制,實作最大的靈活性
2. 通過web化的腳本編寫、調試環境。web展現排程狀态
3. 抓取環模型成熟穩定,子產品間互相獨立,通過消息隊列連接配接,從單程序到多機分布式靈活拓展
pyspider的架構主要分為 scheduler(排程器), fetcher(抓取器), processor(腳本執行):
1. 各個元件間使用消息隊列連接配接,除了scheduler是單點的,fetcher 和 processor 都是可以多執行個體分布式部署的。 scheduler 負責整體的排程控制
2. 任務由 scheduler 發起排程,fetcher 抓取網頁内容, processor 執行預先編寫的python腳本,輸出結果或産生新的提鍊任務(發往 scheduler),形成閉環。
3. 每個腳本可以靈活使用各種python庫對頁面進行解析,使用架構api控制下一步抓取動作,通過設定回調控制解析動作。
爬蟲pyspider提供一個異常強大的網頁界面(web ui),它允許你編輯和調試你的腳本,管理整個抓取過程,監控正在進行的任務,并最終輸出結果。
項目和任務
代碼結構分析
根目錄:在根目錄中可以找到的檔案夾有:
這裡重點介紹一些重要的檔案:
分析完項目的根目錄了,僅根目錄就能說明該項目是以一種非常專業的方式進行開發的。如果你正在開發任何的開源程式,希望你能達到這樣的水準。
檔案夾pyspider
檔案run.py
函數cli()
函數all()
函數all()決定是否運作子程序或者線程,然後調用不同的線程或子程序裡的所有的必要函數。這時pyspider将産生包括webui在内的,爬蟲的所有邏輯子產品所需要的,足夠數量的線程。當我們完成項目并關閉webui時,我們将幹淨漂亮地關閉每一個程序。
現在我們的爬蟲就開始運作了,讓我們進行更深入一點兒的探索。
排程程式
排程程式從兩個不同的隊列中擷取任務(newtask_queue和status_queue),并把任務加入到另外一個隊列(out_queue),這個隊列稍後會被抓取程式讀取。
排程程式做的第一件事情是從資料庫中加載所需要完成的所有的任務。之後,它開始一個無限循環。在這個循環中會調用幾個方法:
循環也會檢查運作過程中的異常,或者我們是否要求python停止處理。
抓取程式
抓取程式的目的是檢索網絡資源。
pyspider能夠處理普通html文本頁面和基于ajax的頁面。隻有抓取程式能意識到這種差異,了解這一點非常重要。我們将僅專注于普通的html文本抓取,然而大部分的想法可以很容易地移植到ajax抓取器。
這裡的想法在某種形式上類似于排程程式,我們有分别用于輸入和輸出的兩個隊列,以及一個大的循環。對于輸入隊列中的所有元素,抓取程式生成一個請求,并将結果放入輸出隊列中。
它聽起來簡單但有一個大問題。網絡通常是極其緩慢的,如果因為等待一個網頁而阻止了所有的計算,那麼整個過程将會運作的極其緩慢。解決方法非常的簡單,即不要在等待網絡的時候阻塞所有的計算。這個想法即在網絡上發送大量消息,并且相當一部分消息是同時發送的,然後異步等待響應的傳回。一旦我們收回一個響應,我們将會調用另外的回調函數,回調函數将會以最适合的方式管理這樣的響應。
現在我們的腦海裡已經有了極好的想法了,讓我們更深入地探索這是如何實作的。
函數run()是抓取程式fetcher中的一個大的循環程式。
函數run()中定義了另外一個函數queue_loop(),該函數接收輸入隊列中的所有任務,并抓取它們。同時該函數也監聽中斷信号。函數queue_loop()作為參數傳遞給tornado的類periodiccallback,如你所猜,periodiccallback會每隔一段具體的時間調用一次queue_loop()函數。函數queue_loop()也會調用另一個能使我們更接近于實際檢索web資源操作的函數:fetch()。
函數fetch(self, task, callback=none)
網絡上的資源必須使用函數phantomjs_fetch()或簡單的http_fetch()函數檢索,函數fetch()隻決定檢索該資源的正确方法是什麼。接下來我們看一下函數http_fetch()。
函數http_fetch(self, url, task, callback)
終于,這裡才是完成真正工作的地方。這個函數的代碼有點長,但有清晰的結構,容易閱讀。
在函數的開始部分,它設定了抓取請求的header,比如user-agent、逾時timeout等等。然後定義一個處理響應response的函數:handle_response(),後邊我們會分析這個函數。最後我們得到一個tornado的請求對象request,并發送這個請求對象。請注意在異步和非異步的情況下,是如何使用相同的函數來處理響應response的。
讓我們往回看一下,分析一下函數handle_response()做了什麼。
函數handle_response(response)
這個函數以字典的形式儲存一個response的所有相關資訊,例如url,狀态碼和實際響應等,然後調用回調函數。這裡的回調函數是一個小方法:send_result()。
函數send_result(self, type, task, result)
這個最後的函數将結果放入到輸出隊列中,等待内容處理程式processor的讀取。
内容處理程式processor
内容處理程式的目的是分析已經抓取回來的頁面。它的過程同樣也是一個大循環,但輸出中有三個隊列(status_queue, newtask_queue 以及result_queue)而輸入中隻有一個隊列(inqueue)。
讓我們稍微深入地分析一下函數run()中的循環過程。
函數run(self)
這個函數的代碼比較少,易于了解,它簡單地從隊列中得到需要被分析的下一個任務,并利用on_task(task, response)函數對其進行分析。這個循環監聽中斷信号,隻要我們給python發送這樣的信号,這個循環就會終止。最後這個循環統計它引發的異常的數量,異常數量過多會終止這個循環。
函數on_task(self, task, response)
函數on_task()是真正幹活的方法。
它嘗試利用輸入的任務找到任務所屬的項目。然後它運作項目中的定制腳本。最後它分析定制腳本傳回的響應response。如果一切順利,将會建立一個包含所有我們從網頁上得到的資訊的字典。最後将字典放到隊列status_queue中,稍後它會被排程程式重新使用。
如果在分析的頁面中有一些新的連結需要處理,新連結會被放入到隊列newtask_queue中,并在稍後被排程程式使用。
現在,如果有需要的話,pyspider會将結果發送給其他項目。
最後如果發生了一些錯誤,像頁面傳回錯誤,錯誤資訊會被添加到日志中。
scrapy是一個為了爬取網站資料,提取結構性資料而編寫的應用架構。 可以應用在包括資料挖掘,資訊處理或存儲曆史資料等一系列的程式中。
其最初是為了頁面抓取 (更确切來說, 網絡抓取 )所設計的, 也可以應用在擷取api所傳回的資料(例如 amazon associates web services
) 或者通用的網絡爬蟲。scrapy用途廣泛,可以用于資料挖掘、監測和自動化測試
scrapy 使用了 twisted 異步網絡庫來處理網絡通訊。整體架構大緻如下
scrapy主要包括了以下元件:
1. 引擎(scrapy): 用來處理整個系統的資料流處理, 觸發事務(架構核心)
2. 排程器(scheduler): 用來接受引擎發過來的請求, 壓入隊列中, 并在引擎再次請求的時候傳回. 可以想像成一個url(抓取網頁的網址或者說是連結)的優先隊列, 由它來決定下一個要抓取的網址是什麼, 同時去除重複的網址
3. 下載下傳器(downloader): 用于下載下傳網頁内容, 并将網頁内容傳回給蜘蛛(scrapy下載下傳器是建立在twisted這個高效的異步模型上的)
4. 爬蟲(spiders): 爬蟲是主要幹活的, 用于從特定的網頁中提取自己需要的資訊, 即所謂的實體(item)。使用者也可以從中提取對外連結接,讓scrapy繼續抓取下一個頁面
5. 項目管道(pipeline): 負責處理爬蟲從網頁中抽取的實體,主要的功能是持久化實體、驗證明體的有效性、清除不需要的資訊。當頁面被爬蟲解析後,将被發送到項目管道,并經過幾個特定的次序處理資料。
6. 下載下傳器中間件(downloader middlewares): 位于scrapy引擎和下載下傳器之間的架構,主要是處理scrapy引擎與下載下傳器之間的請求及響應。
7. 爬蟲中間件(spider middlewares): 介于scrapy引擎和爬蟲之間的架構,主要工作是處理蜘蛛的響應輸入和請求輸出。
8. 排程中間件(scheduler middewares): 介于scrapy引擎和排程之間的中間件,從scrapy引擎發送到排程的請求和響應。
scrapy運作流程大概如下:
1. 首先,引擎從排程器中取出一個連結(url)用于接下來的抓取
2. 引擎把url封裝成一個請求(request)傳給下載下傳器,下載下傳器把資源下載下傳下來,并封裝成應答包(response)
3. 然後,爬蟲解析response
4. 若是解析出實體(item),則交給實體管道進行進一步的處理。
5. 若是解析出的是連結(url),則把url交給scheduler等待抓取
1. pip。首先確定你已經安裝了pip,若沒有安裝,請參照
<a target="_blank" href="http://pip-cn.readthedocs.io/en/latest/installing.html">pip安裝</a>
3. pyspider。直接利用 pip 安裝即可:pip install pyspider。如果你是 ubuntu 使用者,請提前安裝好以下支援類庫
4. 測試。如果安裝過程沒有提示任何錯誤,那就證明一些ok。指令行輸入:pyspider all (這句指令的意思是,運作 pyspider 并 啟動它的所有元件。)。然後浏覽器通路 http://localhost:5000 觀察一下效果,如果可以正常出現 pyspider 的頁面,那證明一切ok,在此附圖一張,這是我寫了幾個爬蟲之後的界面。
接下來我會進一步介紹這個架構的使用。
pyspider 是一個非常友善并且功能強大的爬蟲架構,支援多線程爬取、js動态解析,提供了可操作界面、出錯重試、定時爬取等等的功能,使用非常人性化。
爬取目标網站:https://mm.taobao.com/json/request_top_list.htm?page=1,大家打開之後可以看到許多淘寶mm的清單。
清單有多少?
https://mm.taobao.com/json/request_top_list.htm?page=10000,第10000頁都有,看你想要多少。我什麼也不知道。
随機點選一位 mm 的姓名,可以看到她的基本資料。
可以看到圖中有一個個性域名,我們複制到浏覽器打開。mm.taobao.com/tyy6160
嗯,往下拖,海量的 mm 圖檔都在這裡了,怎麼辦你懂得,我們要把她們的照片和個人資訊都存下來。
p.s. 注意圖中進度條!你猜有多少圖檔~
安裝成功之後,跟我一步步地完成一個網站的抓取,你就會明白 pyspider 的基本用法了。
指令行下執行:pyspider all。這句指令的意思是,運作 pyspider 并 啟動它的所有元件。
可以發現程式已經正常啟動,并在 5000 這個端口運作。接下來在浏覽器中輸入 http://localhost:5000,可以看到 pyspider 的主界面,點選右下角的 create,命名為 taobaomm,當然名稱你可以随意取,繼續點選 create。
這樣我們會進入到一個爬取操作的頁面。
整個頁面分為兩欄,左邊是爬取頁面預覽區域,右邊是代碼編寫區域。下面對區塊進行說明:
左側綠色區域:這個請求對應的 json 變量,在 pyspider 中,其實每個請求都有與之對應的 json 變量,包括回調函數,方法名,請求連結,請求資料等等。
綠色區域右上角run:點選右上角的 run 按鈕,就會執行這個請求,可以在左邊的白色區域出現請求的結果。
左側 enable css selector helper: 抓取頁面之後,點選此按鈕,可以友善地擷取頁面中某個元素的 css 選擇器。
左側 web: 即抓取的頁面的實時預覽圖。
左側 html: 抓取頁面的 html 代碼。
左側 follows: 如果目前抓取方法中又建立了爬取請求,那麼接下來的請求就會出現在 follows 裡。
左側 messages: 爬取過程中輸出的一些資訊。
右側代碼區域: 你可以在右側區域書寫代碼,并點選右上角的 save 按鈕儲存。
右側 webdav mode: 打開調試模式,左側最大化,便于觀察調試。
依然是上面那個網址,https://mm.taobao.com/json/request_top_list.htm?page=1,其中 page 參數代表頁碼。是以我們暫時抓取前 30 頁。頁碼到最後可以随意調整。
首先我們定義基位址,然後定義爬取的頁碼和總頁碼。
點選 save 儲存代碼,然後點選左邊的 run,運作代碼。
運作後我們會發現 follows 出現了 30 這個數字,說明我們接下來有 30 個新請求,點選可檢視所有爬取清單。另外控制台也有輸出,将所有要爬取的 url 列印了出來。
然後我們點選左側任意一個綠色箭頭,可以繼續爬取這個頁面。例如點選第一個 url,來爬取這個 url
點選之後,再檢視下方的 web 頁面,可以預覽實時頁面,這個頁面被我們爬取了下來,并且回調到 index_page 函數來處理,目前 index_page 函數我們還沒有處理,是以是繼續構件了所有的連結請求。
好,接下來我們怎麼辦?當然是進入到 mm 到個人頁面去爬取了。
爬取到了 mm 的清單,接下來就要進入到 mm 詳情頁了,修改 index_page 方法。
其中 response 就是剛才爬取的清單頁,response 其實就相當于清單頁的 html 代碼,利用 doc 函數,其實是調用了 pyquery,用 css 選擇器得到每一個mm的連結,然後重新發起新的請求。比如,我們這裡拿到的 each.attr.href 可能是 mm.taobao.com/self/model_card.htm?user_id=687471686,在這裡繼續調用了 crawl 方法,代表繼續抓取這個連結的詳情。
然後回調函數就是 detail_page,爬取的結果會作為 response 變量傳過去。detail_page 接到這個變量繼續下面的分析。
好,我們繼續點選 run 按鈕,開始下一個頁面的爬取。得到的結果是這樣的。
哦,有些頁面沒有加載出來,這是為什麼?在之前的文章說過,這個頁面比較特殊,右邊的頁面使用 js 渲染生成的,而普通的抓取是不能得到 js 渲染後的頁面的,這可麻煩了。然而,幸運的是,pyspider 提供了動态解析 js 的機制。
如果已經裝好了 phantomjs,這時候就輪到它來出場了。在最開始運作 pyspider 的時候,使用了pyspider all指令,這個指令是把 pyspider 所有的元件啟動起來,其中也包括 phantomjs。
是以我們代碼怎麼改呢?很簡單。
隻是簡單地加了一個 fetch_type=’js’,點選綠色的傳回箭頭,重新運作一下。可以發現,頁面已經被我們成功加載出來了,簡直不能更帥!
看下面的個性域名,所有我們需要的 mm 圖檔都在那裡面了,是以我們需要繼續抓取這個頁面。
好,繼續修改 detail_page 方法,然後增加一個 domain_page 方法,用來處理每個 mm 的個性域名。
好,繼續重新 run,預覽一下頁面,終于,我們看到了 mm 的所有圖檔。
照片都有了,那麼我們就偷偷地下載下傳下來吧~。完善 domain_page 代碼,實作儲存簡介和周遊儲存圖檔的方法。
在這裡,pyspider 有一個特點,所有的 request 都會儲存到一個隊列中,并具有去重和自動重試機制。是以,我們最好的解決方法是,把每張圖檔的請求都寫成一個 request,然後成功後用檔案寫入即可,這樣會避免圖檔加載不全的問題。
曾經在之前文章寫過圖檔下載下傳和檔案夾建立的過程,在這裡就不多贅述原理了,直接上寫好的工具類,後面會有完整代碼。
這裡面包含了四個方法。
然後在 domain_page 中具體實作如下
以上方法首先擷取了頁面的所有文字,然後調用了 savebrief 方法存儲簡介。
然後周遊了 mm 所有的圖檔,并通過連結擷取字尾名,和 mm 的姓名以及自增計數組合成一個新的檔案名,調用 saveimg 方法儲存圖檔。
基本的東西都寫好了。接下來。繼續完善一下代碼。第一版本完成。
版本一功能:按照淘寶mm姓名分檔案夾,存儲mm的 txt 文本簡介以及所有美圖至本地。
可配置項:
粘貼到你的 pyspider 中運作吧~。其中有一些知識點,我會在後面作詳細的用法總結。大家可以先體會一下代碼。
儲存之後,點選下方的 run,你會發現,海量的 mm 圖檔已經湧入你的電腦啦~
項目代碼:
<a target="_blank" href="https://github.com/cqcre/taobaomm">taobaomm – github</a>
開始之前
你還應該至少對網際網路是什麼有一個簡單的認識:
是以,爬網頁實際上就是:
找到包含我們需要的資訊的網址(url)清單
通過 http 協定把頁面下載下傳回來
從頁面的 html 中解析出需要的資訊
找到更多這個的 url,回到 2 繼續
選取一個開始網址
既然我們要爬所有的電影,首先我們需要抓一個電影清單,一個好的清單應該:
包含足夠多的電影的 url
通過翻頁,可以周遊到所有的電影
一個按照更新時間排序的清單,可以更快抓到最新更新的電影
建立一個項目
在 pyspider 的 dashboard 的右下角,點選 "create" 按鈕
替換 <code>on_start</code> 函數的 <code>self.crawl</code> 的
url:
<code>self.crawl</code> 告訴 pyspider 抓取指定頁面,然後使用 <code>callback</code> 函數對結果進行解析。
點選綠色的 <code>run</code> 執行,你會看到 <code>follows</code> 上面有一個紅色的
1,切換到 <code>follows</code> 面闆,點選綠色的播放按鈕:
tag 清單頁
url 的方法就是用正則從中過濾出來:
由于 電影清單頁和 tag清單頁長的并不一樣,在這裡建立了一個 <code>callback</code> 為 <code>self.list_page</code>
<code>@config(age=10 * 24 * 60 * 60)</code> 在這表示我們認為
10 天内頁面有效,不會再次進行更新抓取
由于 pyspider 是純 python 環境,你可以使用 python 強大的内置庫,或者你熟悉的第三方庫對頁面進行解析。不過更推薦使用 css選擇器。
電影清單頁
再次點選 <code>run</code> 讓我們進入一個電影清單頁(<code>list_page</code>)。在這個頁面中我們需要提取:
下一頁的連結,用來翻頁
css選擇器
css selector helper
在 pyspider 中,還内置了一個 <code>css selector helper</code>,當你點選頁面上的元素的時候,可以幫你生成它的 css選擇器 表達式。你可以點選 <code>enable css selector helper</code> 按鈕,然後切換到 <code>web</code> 頁面:
開啟後,滑鼠放在元素上,會被黃色高亮,點選後,所有擁有相同 css選擇器 表達式的元素會被高亮。表達式會被插入到 python 代碼目前光标位置。建立下面的代碼,将光标停留在單引号中間:
點選一個電影的連結,css選擇器 表達式将會插入到你的代碼中,如此重複,插入翻頁的連結:
翻頁是一個到自己的 <code>callback</code> 回調
電影詳情頁
再次點選 <code>run</code>,follow
到詳情頁。使用 <code>css selector helper</code> 分别添加電影标題,打分和導演:
右鍵點選需要提取的元素,點選審查元素。你并不需要像自動生成的表達式那樣寫出所有的祖先節點,隻要寫出那些能區分你不需要的元素的關鍵節點的屬性就可以了。不過這需要抓取和網頁前端的經驗。是以,學習抓取的最好方法就是學會這個頁面/網站是怎麼寫的。
你也可以在 chrome dev tools 的 javascript console 中,使用 <code>$$(a[rel="v:directedby"])</code> 測試
css selector。
開始抓取
使用 <code>run</code> 單步調試你的代碼,對于用一個 <code>callback</code> 最好使用多個頁面類型進行測試。然後儲存。
回到 dashboard,找到你的項目
将 <code>status</code> 修改為 <code>debug</code> 或 <code>running</code>
按 <code>run</code> 按鈕
在上面教程中,用 <code>self.crawl</code> api
html 代碼中。
ajax
通過使用原有的 web 标準元件,實作了在不重新加載整個頁面的情況下,與伺服器進行資料互動。例如在新浪微網誌中,你可以展開一條微網誌的評論,而不需要重新加載,或者打開一個新的頁面。但是這些内容并不是一開始就在頁面中的(這樣頁面就太大了),而是在你點選的時候被加載進來的。這就導緻了你抓取這個頁面的時候,并不能獲得這些評論資訊(因為你沒有『展開』)。
html 更容易解析。
你會發現電影是『載入中...』
找到真實的請求
打開一個新視窗
按 <code>ctrl</code>+<code>shift</code>+<code>i</code> (在
mac 上請按 <code>cmd</code>+<code>opt</code>+<code>i</code>)
打開開發者工具。
切換到網絡( netwotk 面闆)
在頁面加載的過程中,你會在面闆中看到所有的資源請求。
在豆瓣這個例子中,xhr 請求并不多,可以挨個檢視來确認。但在 xhr 請求較多的時候,可能需要結合觸發動作的時間,請求的路徑等資訊幫助在大量的請求中找到包含資訊的關鍵請求。這需要抓取或者前端的相關經驗。是以,有一個我一直在提的觀點,學習抓取的最好方法是:學會寫網站。
你可以使用 <code>response.json</code> 将結果轉為一個 python 的 <code>dict</code> 對象
http
url 進行了抓取。這些抓取就是通過 http 協定傳輸的。
在抓取過程中,你可能會遇到類似 <code>403 forbidden</code>,或者需要登入的情況,這時候你就需要正确的 http 參數進行抓取了。
請求的第一行包含 <code>method</code>, <code>path</code> 和
http 協定的版本資訊
餘下的行被稱為 header,是以 <code>key: value</code> 的形式呈現的
如果是 post 請求,在請求結尾可能還會有 <code>body</code> 内容
在大多數時候,使用正确的 <code>method</code>, <code>path</code>, <code>headers</code> 和 <code>body</code> 總是能抓取到你需要的資訊的。
http method
get 方式,而在送出資料的時候一般使用 post。
todo: need example here
http headers
headers 清單。一些常用的需要注意的有:
user-agent
ua 是辨別你使用的浏覽器,或抓取程式的一段字元串。pyspider 使用的預設 ua 是 <code>pyspider/version (+http://pyspider.org/)</code>。網站常用這個字元串來區分使用者的作業系統和浏覽器,以及判斷對方是否是爬蟲。是以在抓取的時候,常常會對
ua 進行僞裝。
referer
referer 用于告訴伺服器,你通路的上一個網頁是什麼。常常被用于防盜鍊,在抓取圖檔的時候可能會用到。
x-requested-with
帶有 <code>headers={'x-requested-with': 'xmlhttprequest'}</code> 才能抓取到内容。
http cookie
雖然 <code>cookie</code> 隻是
http header 中的一個,但是因為非常重要,但是拿出來說一下。<code>cookie</code> 被
http 請求用來區分、追蹤使用者的身份,當你在一個網站登入的時候,就是通過寫入 <code>cookie</code> 字段來記錄登入狀态的。
當遇到需要登入的網站,你需要通過設定 cookie 參數,來請求需要登入的内容。cookie 可以通過開發者工具的請求面闆,或者是資源面闆中獲得。在
pyspider 中,你也可以使用 <code>response.cookies</code> 獲得傳回的
cookie,并使用 <code>self.crawl(url, cookie={'key': 'value'})</code> 來設定請求的
cookie 參數。
使用 phantomjs
當 pyspider 連上 phantomjs 代理後,你就能通過在 <code>self.crawl</code> 中添加 <code>fetch_type='js'</code> 的參數,開啟使用
phantomjs 直接抓取:
在頁面上執行自定義腳本
20 條。當你點選『加載更多』時,能獲得更多的熱門電影。為了獲得更多的電影,我們可以使用 <code>self.crawl</code> 的 <code>js_script</code> 參數,在頁面上執行一段腳本,點選加載更多:
由于是 ajax 異步加載的,在頁面加載完成時,第一頁的電影可能還沒有加載完,是以我們用 <code>settimeout</code> 延遲
1 秒執行。
你可以間隔一定時間,多次點選,這樣可以加載更多頁。
由于相同 url (實際是相同 taskid) 的任務會被去重,是以這裡為 url 加了一個 <code>#more</code>
<a target="_blank" href="https://www.figotan.org/2016/08/10/pyspider-as-a-web-crawler-system/?utm_source=tuicool&utm_medium=referral">轉載位址</a>
為什麼是python
寫網絡爬蟲的語言有很多,程式設計的語言更多。個人認為python是一種工具型的語言,上手快,文法簡單(相比于c/c++/java族),各種功能庫豐富而且小巧單一(每個獨立的庫隻做一件事情),是以程式設計就像是在玩樂高積木,照着自己設計好的流程,拼接就行了。當然,這是筆者個人的經驗和喜好。如果你有自己擅長并喜歡的,大可用自己的去實作一個網絡爬蟲系統,這個不在本文的讨論範圍之類了。
為什麼是pyspider
很多推薦用requests做請求,query/soup做頁面資料(html/xml)解析,看起來很靈活,然而,一個比較完善的網絡爬蟲系統,所需要提供的功能可能遠遠不止這些。也有推薦scrapy的,雖然看起來功能非常強大,但是這個架構上手需要一些時間,有一定的學習成本,相對于新手來說,很難快速專注爬蟲業務的開發。
目标網站上的内容元素的解析,而且隻需要關注解析什麼,解析架構也有提供,并且提供了可視化工具輔助從目标頁面摳取需要解析的元素css屬性
解析出來的内容元素如何儲存,你隻需要關注資料庫表字段的設計,然後把解析出來的頁面元素内容儲存到資料庫表中
那麼,剩下的幾乎所有事情,就交給pyspider吧
簡單的爬取看官方文檔就可以了,不過,實踐過程中總會遇到各種問題,那麼,看看這些如何解決的吧。
如何模拟登陸
有些網站内容的展示需要使用者登入,那麼如果需要爬取這樣的頁面内容,我們的爬蟲就需要模拟使用者登陸。網站一般在頁面跳轉或者重新整理的時候,也需要擷取登入資訊以确定這個頁面的通路使用者是登陸過的。如果每次都需要使用者重新登入,那麼這種體驗就太爛了,需要一種機制把之前使用者登陸的資訊儲存起來,而且一定是儲存在浏覽器可以通路的本地存儲上,這樣,使用者在頁面跳轉或者頁面重新整理的時候,登入資訊被網站自動讀取,就不需要使用者頻繁登入了。而這個儲存的地方,叫做cookie。
爬蟲需要做的事情,一是模拟登陸,拿到cookie資料,然後儲存下來,二是每次去通路網頁的時候,将cookie資訊傳遞給請求,這樣就可以正常爬到需要使用者登入的資料了。
我們先設計一個登入類,用來管理登入的請求和資料
代碼解釋
使用者名username, 密碼password, 目标網站的登入頁面位址login_url, 目标網站的主域名post_url_prefix,這些參數從外部傳入,目标網站的登入頁面位址也有可能就是網站的首頁位址。
getpostdata首先向目标網站的登入頁面位址發起一個請求,然後解析這個頁面的資料,解析出登入請求的目标位址和post請求的資料(登入請求一般為post請求),然後傳回這兩個參數
設計一個方法,這個方法用來擷取爬取網頁請求需要的cookie資料。
user_name password login_url post_url_prefix 分别定義了使用者名/密碼/登入頁面位址/目标網頁字首
如果從cookies_file讀取出的cookie資訊為空,那麼就調用login做登入流程,并且把擷取到的結果儲存,如果cookie不為空,就傳回cookie資訊到字典cookiesdict中
pyspider每次爬取請求都帶上cookie字典,這樣,向目标位址發請求就可以擷取到需要登入才能通路到的資料了。
如何解析爬取下來的内容
爬取的内容通過回調的參數response傳回,response有多種解析方式
如果傳回的資料是json,則可以通過response.json通路
response.doc傳回的是pyquery對象
response.etree傳回的是lxml對象
response.text傳回的是unicode文本
response.content傳回的是位元組碼
是以傳回資料可以是5種形式,unicode和位元組碼不是結構化的資料,很難解析,這裡就不贅述了,json需要特定的條件,而且解析相對簡單,也不必說。
xpath選擇器參考
選擇器
示例
示例說明
nodename
bookstore
選擇所有名稱叫做”bookstore”的節點
/
bookstore/book
選擇”bookstore”的節點的所有”book”子節點
//
//book
選擇文檔中所有名稱叫做”book”的節點,不管它們的父節點叫做什麼
.
選擇目前的節點
..
選擇目前節點的父節點
@
//@lang
選擇所有名稱叫做”lang”的屬性
bookstore//book
選擇節點”bookstore”所有叫做”book”的子孫節點,bookstore不一定是book的父節點
/bookstore/book[1]
選擇節點”bookstore”的第一個叫做”book”的子節點
/bookstore/book[last()]
選擇節點”bookstore”的最後一個叫做”book”的子節點
//title[@lang]
選擇所有有一個屬性名叫做”lang”的title節點
//title[@lang=’en’]
選擇所有有一個屬性”lang”的值為”en”的title節點
*
/bookstore/*
選擇”bookstore”節點的所有子節點
//*
選擇文檔中所有的節點
@*
//title[@*]
選擇所有的”title”節點至少含有一個屬性,屬性名稱不限
pyquery可以采用css選擇器作為參數對網頁進行解析。
類似這樣
或者這樣
.class
.intro
selects all elements with class=”intro”
#id
#firstname
selects the element with id=”firstname”
element
p
selects all <p> elements
element,element
div, p
selects all <div> elements and all <p> elements
element element
div p
selects all <p> elements inside <div> elements
element>element
div > p
selects all <p> elements where the parent is a <div> element
[attribute]
[target]
selects all elements with a target attribute
[attribute=value]
[target=_blank]
selects all elements with target=”_blank”
[attribute^=value]
a[href^=”https”]
selects every <a> element whose href attribute value begins with “https”
[attribute$=value]
a[href$=”.pdf”]
selects every <a> element whose href attribute value ends with “.pdf”
[attribute*=value]
a[href*=”w3schools”]
selects every <a> element whose href attribute value contains the substring “w3schools”
:checked
input:checked
selects every checked <input> element
如何将資料儲存到mysql中
将mysql的資料庫通路封裝成一個類
在處理爬取結果的回調中儲存到資料庫
如何在爬蟲腳本更新後重新運作之前執行過的任務
比如這種場景,爬取了一些資料,發現沒有寫儲存到資料庫的邏輯,然後加上了這段邏輯,卻發現之前跑過的任務不會在執行了。那麼如何做到在爬蟲腳本改動後,之前的任務重新自動再跑一遍呢。
在crawl_config中使用itag來标示爬蟲腳本的版本号,如果這個值發生改變,那麼所有的任務都會重新再跑一遍。示例代碼如下
如何解析javascript代碼
具體如何使用的可以看官方文檔,這裡列舉出一些可供參考的javascript解析器
<a target="_blank" href="http://www.nightmarejs.org/">nightmare</a>
<a target="_blank" href="http://www.seleniumhq.org/">selenium</a>
<a target="_blank" href="https://github.com/makinacorpus/spynner">spynner</a>
<a target="_blank" href="https://github.com/jeanphix/ghost.py">ghost.py</a>
參考資料
<a target="_blank" href="https://github.com/binux/pyspider">binux/pyspider</a>
<a target="_blank" href="http://docs.pyspider.org/en/latest/">pyspider官方文檔</a>
<a target="_blank" href="http://blog.binux.me/2014/02/pyspider-architecture/">pyspider架構設計</a>
<a target="_blank" href="http://www.jishubu.net/yunwei/python/411.html">pyspider中文腳本編寫指南</a>
<a target="_blank" href="http://www.cnblogs.com/panliu/p/4524157.html">pyspider爬蟲教程</a>
<a target="_blank" href="http://www.jishubu.net/yunwei/python/424.html">把 pyspider的結果存入自定義的mysql資料庫中</a>
<a target="_blank" href="http://blog.csdn.net/u012293522/article/details/44222207">pyspider的mysql資料存儲接口</a>
<a target="_blank" href="https://pythonhosted.org/pyquery/api.html">pyquery complete api</a>
<a target="_blank" href="http://www.w3schools.com/cssref/css_selectors.asp">css selector reference</a>
收集的一些其它網絡爬蟲的資料
java
<a target="_blank" href="https://github.com/decaywood/xueqiusuperspider">雪球股票資訊超級爬蟲</a>
<a target="_blank" href="https://github.com/mrjiao/spiderjackson">一個簡單易用的爬蟲架構,内置代理管理子產品,靈活設定多線程爬取</a>
<a target="_blank" href="https://github.com/code4craft/webmagic">a scalable web crawler framework for java</a>
<a target="_blank" href="https://git.oschina.net/l-weiwei/spiderman2">強力 java 爬蟲,清單分頁、詳細頁分頁、ajax、微核心高擴充、配置靈活</a>
python
<a target="_blank" href="http://scrapy.org/">scrapy</a>
<a target="_blank" href="https://github.com/ferventdesert/etlpy">a smart stream-like crawler & etl python library</a>
<a target="_blank" href="https://you-get.org/">爬視訊音頻神器you-get</a>
<a target="_blank" href="https://github.com/rg3/youtube-dl">另一款視訊下載下傳神器youtube-dl</a>
<a target="_blank" href="https://github.com/mrs0m30n3/youtube-dl-gui">youtube-dl圖形界面版</a>
<a target="_blank" href="https://github.com/thoxvi/mycar_python">自動抓取tumblr指定使用者視訊分享</a>
<a target="_blank" href="https://github.com/jmg/crawley">crawley</a>
<a target="_blank" href="https://github.com/hanc00l/wooyun_public">烏雲公開漏洞、知識庫爬蟲和搜尋</a>
<a target="_blank" href="https://github.com/dixudx/tumblr-crawler">下載下傳指定的 tumblr 部落格中的圖檔,視訊</a>
<a target="_blank" href="https://github.com/xuanhun/tumblr-crawler">下載下傳指定的 tumblr 部落格中的圖檔,視訊,玄魂修改版</a>
<a target="_blank" href="https://github.com/78/ssbc">dht網絡爬蟲</a>
<a target="_blank" href="https://github.com/dontcontactme/doubanspiders">豆瓣電影、書籍、小組、相冊、東西等爬蟲集 writen in python</a>
<a target="_blank" href="http://zpz.name/2378/">如何不用用戶端下載下傳 youku 視訊-youku 實作下載下傳 python3 實作</a>
<a target="_blank" href="https://github.com/yijingping/unicrawler">一個可配置的、分布式的爬蟲架構</a>
<a target="_blank" href="https://github.com/scrapinghub">cloud-based web crawling platform</a>
<a target="_blank" href="https://github.com/x-spiders/baiduyun-spider">百度雲爬蟲-爬取百度雲/百度網盤所有的分享檔案</a>
<a target="_blank" href="https://github.com/x-spiders/aiss-spider">愛絲app圖檔爬蟲,以及免支付破解vip看圖</a>
<a target="_blank" href="https://github.com/bowenpay/wechat-spider">微信公衆号爬蟲</a>
<a target="_blank" href="https://github.com/whatsghost/lagou_spider">拉勾網爬蟲</a>
<a target="_blank" href="https://www.v2ex.com/t/348731#reply7">百度網盤爬蟲(如何爬取百度網盤)</a>
php
<a target="_blank" href="https://sourceforge.net/projects/php-crawler/">php crawler</a>
<a target="_blank" href="https://sourceforge.net/projects/phpcrawl/">phpcrawl</a>
<a target="_blank" href="https://github.com/fanfank/phpfetcher">phpfetcher</a>
<a target="_blank" href="https://github.com/hirudy/tspider">php spider framework</a>
<a target="_blank" href="https://github.com/owner888/phpspider">我用爬蟲一天時間“偷了”知乎一百萬使用者,隻為證明php是世界上最好的語言</a>
<a target="_blank" href="https://github.com/slince/spider">爬蟲元件</a>
<a target="_blank" href="http://simplehtmldom.sourceforge.net/">php simple html dom parser</a>
<a target="_blank" href="https://querylist.cc/">querylist</a>
<a target="_blank" href="https://github.com/friendsofphp/goutte">goutte, a simple php web scraper</a>
nodejs
<a target="_blank" href="https://github.com/xwartz/spider">nodejs 編寫的爬蟲工具</a>
<a target="_blank" href="https://github.com/raawaa/jav-scrapy">批量抓取av磁鍊或封面的苦勞力</a>
<a target="_blank" href="https://github.com/leeiio/tumblr-downloader">easily download all the photos from a tumblr blog.</a>
<a target="_blank" href="https://github.com/dontcontactme/p2pspider">dht spider + bittorrent client = p2p spider</a>
<a target="_blank" href="https://github.com/callmelanmao/btspider">p2p spider修改版,添加了babel,eslint,gulp等工具來支援es6代碼</a>
<a target="_blank" href="https://github.com/nieheyong/hanhandespider">一個node.js福利圖網站爬蟲程式</a>
<a target="_blank" href="https://github.com/beilunyang/dhtcrawler">一個簡單的dht爬蟲,用于搜集infohash</a>
<a target="_blank" href="https://github.com/callmelanmao/yunshare">百度雲分享爬蟲項目</a>
ruby
<a target="_blank" href="https://github.com/dontcontactme/rbdht">a simple dht crawler, written in ruby</a>
c sharp
<a target="_blank" href="https://github.com/ferventdesert/hawk">visualized crawler & etl ide written with c#/wpf</a>
erlang
<a target="_blank" href="https://github.com/kevinlynx/dhtcrawler2">使用erlang實作p2p磁力搜尋</a>
c++
<a target="_blank" href="https://github.com/yangyangwithgnu/hardseed">給不了你夢中情人,至少還有硬碟女神:hardseed</a>
golang
<a target="_blank" href="https://github.com/henrylee2cn/pholcus">a distributed, high concurrency and powerful web crawler software</a>
網絡爬蟲專題
<a target="_blank" href="http://www.open-open.com/lib/list/96">open-open 網絡爬蟲專題</a>
<a target="_blank" href="https://github.com/x-spiders">你想要的爬蟲,都在這裡</a>