大師兄的Python學(xué)習(xí)筆記(二十七): 爬蟲(八)
大師兄的Python學(xué)習(xí)筆記(二十九): 爬蟲(十)
十、Pyspider框架
- Pyspider是由國人binux編寫的強(qiáng)大網(wǎng)絡(luò)爬蟲框架。
- 點(diǎn)擊查看Pyspider官方文檔。
1. 安裝Pyspider
- 可以直接通過
pip install pyspider安裝。 - 安裝后,使用
pyspider all啟動驗證安裝結(jié)果。 -
如果發(fā)生async=True錯誤,則是因為你的Python版本高于3.7,在3.7后async成為關(guān)鍵字。
-
解決辦法是將以下三個文件中的async關(guān)鍵字替換為其他變量
Lib\site-packages\pyspider\run.py
Lib\site-packages\pyspider\webui\app.py
Lib\site-packages\pyspider\fetcher\tornado_fetcher.py
- 如果發(fā)生
- Deprecated option 'domaincontroller': use 'http_authenticator.domain_controller' instead.錯誤,則修改Lib\site-packages\pyspider\webui\webdav.py文件.
將'domaincontroller': NeedAuthController(app),
修改為
'http_authenticator': {
'HTTPAuthenticator': NeedAuthController(app),
},
再使用python -m pip install wsgidav==2.4.1指令將wsgidav版本降為2.4.1
- 如果發(fā)生
phantomjs not found, continue running without it.錯誤,則下載phantomjs.exe并和python.exe放到同一個文件夾下。 -
如果一切順利,則啟動一個web服務(wù)。
-
瀏覽器打開本地5000端口,如果打開Pyspider webUI頁面,則表示安裝成功。
2. Pyspider的基本功能
- 方便易用的WebUI系統(tǒng),能夠可視化地編寫和調(diào)試爬蟲。
- 能夠監(jiān)控爬取進(jìn)度、查看爬取結(jié)果、管理爬蟲項目等。
- 支持多種數(shù)據(jù)庫。
- 支持多種消息隊列。
- 具備優(yōu)先級控制、失敗重試、定時爬取等功能。
- 對接了PhantomJs,可以抓取js渲染的頁面。
- 支持淡季和分布式部署,支持docker部署。
3. 與Scrapy對比
| 維度 | Pyspider | Scrapy |
|---|---|---|
| 可視化 | 支持WebUI | 源生不具備WebUI,需要對接Prtia實現(xiàn)。 |
| 調(diào)試 | 使用WebUI調(diào)試,非常方便 | 使用parse命令調(diào)試,相對復(fù)雜 |
| JS頁面采集 | 支持PhantomJs進(jìn)行Js渲染頁面的采集 | 需要對接Scrapy-Splash組件 |
| 選擇器 | 內(nèi)置了pyquery選擇器 | 對接了Xpath、css選擇器以及正則匹配 |
| 擴(kuò)展度 | 可擴(kuò)展程度低 | 可以通過對接Middleware、Pipeline、Extension等組件實現(xiàn)非常強(qiáng)大的功能 |
- 如果快速實現(xiàn)一個頁面的抓取使用Pyspider,如果應(yīng)對大規(guī)模抓取或爬程度強(qiáng)的頁面使用Scrapy。
4. Pyspider的架構(gòu)
- Pyspider的架構(gòu)主要分為Scheduler(調(diào)度器)、Fetcher(抓取器)和Processer(處理器)三個部分。
-
爬取過程受Monitor(監(jiān)控器)監(jiān)控,抓取結(jié)果被Result Worker(結(jié)果處理器)處理。
| 組件 | 功能 |
|---|---|
| Scheduler | - 判斷是新任務(wù)還是需要重新爬取。 - 任務(wù)進(jìn)行優(yōu)先級分類 - 將任務(wù)發(fā)送給fetcher - 從processor返回的新任務(wù)隊列中接收任務(wù) - 處理周期任務(wù),丟失的任務(wù)和失敗的任務(wù),并且稍后重試。 |
| Fetcher | - 獲取web頁面 - 將頁面發(fā)給Processor |
| Processer | - 捕捉異常和記錄日志 - 運(yùn)行腳本解析和提取信息 - 發(fā)送狀態(tài)和新任務(wù)給Scheduler - 發(fā)送結(jié)果給Result Worker |
| Result Worker | - 從Porcess接收結(jié)果數(shù)據(jù) - 將數(shù)據(jù)保存到resultdb - 根據(jù)需要處理結(jié)果 |
| Monitor&Webui | 監(jiān)控過程并提供webUI界面 |
5. Pyspider的工作流程
第一步:
調(diào)用Handler類的on_start()方法生成最初任務(wù),并發(fā)送給Scheduler調(diào)度。
第二步:
Scheduler將任務(wù)發(fā)給Fetcher抓取內(nèi)容,并將內(nèi)容發(fā)給Processer。
第三步:
Processer處理響應(yīng)并提取出新的URL生成新的抓取任務(wù)。
Processer通過消息隊列通知Scheduler當(dāng)前抓取任務(wù)的執(zhí)行情況。
Processer將新的抓取人物發(fā)送給Scheduler。
Processer將新的提取結(jié)果發(fā)給Result Worker處理。
第四步:
Scheduler接收新的抓取任務(wù),查詢數(shù)據(jù)庫判斷是抓取任務(wù)還是重試任務(wù),并發(fā)送Fetcher。
不斷重復(fù)以上內(nèi)容,知道所有任務(wù)執(zhí)行完畢,抓取結(jié)束。
第五步:
回調(diào)on_finished()方法,這里可以定義后處理過程。
6. Pyspider的使用
- 以從爬取豆瓣影視區(qū)為例。
6.1 啟動pyspider
- 命令行輸入
pyspider all,啟動PhantomJs、ResultWorker、Processer、Fetcher、Scheduler和WebUI。
- 瀏覽器輸入地址
http:localhost:port,打開WebUI。
6.2 創(chuàng)建新項目
-
在WebUI創(chuàng)建一個新項目。
-
進(jìn)入編輯和調(diào)試頁面,并生成一段代碼。
- 編輯頁面的左側(cè)是代碼的調(diào)試頁面,左上角的
run可以單步調(diào)試爬蟲,下方可以預(yù)覽網(wǎng)頁。
-
編輯頁面的右側(cè)是代碼的編輯頁,可以在IDE中寫完了再黏貼過來。
Handler(BaseHandler)是爬蟲的主類,可以定義爬取、解析、存儲的邏輯。crawl_config用于爬蟲的全局配置。on_start()是爬取的入口,調(diào)用crawl()方法創(chuàng)建爬取請求,如果爬取成功,則將Response交給index_page()解析。index_page()接收Response參數(shù),并通過pyquery解析頁面。同時,還會遍歷鏈接,并通過crawl()生成新的請求。detail_page()接收Response參數(shù),并抓取頁面信息,不會生成新的請求。
6.3 爬取首頁
- 點(diǎn)擊
run后,下方的follow會出現(xiàn)標(biāo)注1,表示有新的爬取請求產(chǎn)生。
- 點(diǎn)擊右箭頭,執(zhí)行爬取請求,并通過
index_page()函數(shù)解析了內(nèi)容。
6.4 爬取頁面數(shù)據(jù)
- 為了爬取頁面數(shù)據(jù),我們需要修改Handler代碼。
- 使用pyquery解析頁面。
>>>#!/usr/bin/env python
>>># -*- encoding: utf-8 -*-
>>># Created on 2020-09-01 10:17:23
>>># Project: douban_spider
>>>from pyspider.libs.base_handler import *
>>>class Handler(BaseHandler):
>>> crawl_config = {
>>> }
>>> @every(minutes=24 * 60)
>>> def on_start(self):
>>> self.crawl('https://movie.douban.com/chart', callback=self.index_page)
>>> @config(age=10 * 24 * 60 * 60)
>>> def index_page(self, response):
>>> for each in response.doc('table').items():
>>> item = [x for x in each.find('span').items()]
>>> name = item[0].text()
>>> rating = item[2].text()
>>> print(f'片名:{name}\n評分:{rating}\n')
-
webUI顯示結(jié)果:
6.5 爬取子頁面
- 修改Handler代碼,收集子頁面鏈接,并創(chuàng)建新任務(wù)。
>>>#!/usr/bin/env python
>>># -*- encoding: utf-8 -*-
>>># Created on 2020-09-01 10:17:23
>>># Project: douban_spider
>>>import json
>>>from pyspider.libs.base_handler import *
>>>class Handler(BaseHandler):
>>> crawl_config = {
>>> }
>>> @every(minutes=24 * 60)
>>> def on_start(self):
>>> self.crawl('https://movie.douban.com/chart', callback=self.index_page)
>>> @config(age=10 * 24 * 60 * 60)
>>> def index_page(self, response):
>>> urls = set()
>>> for each in response.doc('a[href^="https://movie.douban.com/subject/"]').items():
>>> if each.attr.href not in urls:
>>> self.crawl(each.attr.href,callback=self.detail_page)
>>> urls.add(each.attr.href)
>>> @config(priority=2,fetch_type="js")
>>> def detail_page(self,response):
>>> page = json.loads(response.doc("script[type='application/ld+json']").text())
>>> return {
>>> "url": response.url,
>>> "title": response.doc('title').text(),
>>> "directors": [x.get("name") for x in page.get("director")],
>>> "author":[x.get("name") for x in page.get("author")],
>>> "actors":[x.get("name") for x in page.get("actor")],
>>> "description":page.get("description"),
>>> "rating":page.get("aggregateRating").get("ratingValue")
>>> }
-
在爬去首頁后出現(xiàn)了37個新任務(wù)。
-
執(zhí)行第一個任務(wù),爬取第一個子頁面內(nèi)容。
image.png
6.5 啟動爬蟲
-
在webUI的項目頁面,修改爬蟲狀態(tài)為running或debug。
-
點(diǎn)擊run啟動爬蟲
| 參數(shù) | 含義 |
|---|---|
| rate/burst | 當(dāng)前爬取速率 |
| rate | 每秒發(fā)送請求書 |
| burst | 流量控制中令牌筒算法的令牌數(shù) |
| process | 最近5分鐘、1小時、1天和所有的請求情況 藍(lán)色:等待被執(zhí)行的請求 綠色:成功的請求 黃色:請求失敗后等待重試的請求 紅色:失敗次數(shù)過多而被忽略的請求 |
-
點(diǎn)擊Active Tasks查看最近請求的詳細(xì)狀況
-
點(diǎn)擊Result查看爬取結(jié)果
7. Pyspider的方法
7.1 命令行用法
- pyspider命令行有很多可配置參數(shù),完整結(jié)構(gòu)為:
pyspider [OPTIONS] COMMAND [ARGS] - OPTIONS為可選參數(shù),可指定參數(shù)如下:
| 參數(shù) | 功能 |
|---|---|
| -c, --config FILENAME | 指定配置文件名稱 |
| --logging-config TEXT | 日志配置文件名稱,默認(rèn): pyspider/pyspider/logging.conf |
| --debug | 開啟調(diào)試模式 |
| --queue-maxsize INTEGER | 隊列的最大長度 |
| --taskdb TEXT | taskdb的數(shù)據(jù)庫連接字符串, default: sqlite |
| --projectdb TEXT | projectdb的數(shù)據(jù)庫連接字符串, default: sqlite |
| --resultdb TEXT | resultdb的數(shù)據(jù)庫連接字符串, default: sqlite |
| --message-queue TEXT | 消息隊列連接炙甘草default: multiprocessing.Queue |
| --amqp-url TEXT | [deprecated] amqp url for rabbitmq. please use --message-queue instead. |
| --beanstalk TEXT | [deprecated] beanstalk config for beanstalk queue. please use --message-queue instead. |
| --phantomjs-proxy TEXT | phantomjs使用的代理,ip:port的形式 |
| --data-path TEXT | 數(shù)據(jù)庫存放的路徑 |
| --version | pyspider的版本 |
| --help | 顯示幫助信息 |
- 可以使用
pyspider scheduler [OPTIONS]單獨(dú)運(yùn)行Scheduler組件,OPTIONS參數(shù)如下:
| 參數(shù) | 功能 |
|---|---|
| --xmlrpc / --no-xmlrpc | |
| --xmlrpc-host TEXT | |
| --xmlrpc-port INTEGER | |
| --inqueue-limit INTEGER | 任務(wù)隊列的最大程度,如果滿了則新的任務(wù)會被忽略 |
| --delete-time INTEGER | 設(shè)置為delete標(biāo)記之前的刪除時間 |
| --active-tasks INTEGER | 當(dāng)前活躍的任務(wù)數(shù)量配置 |
| --loop-limit INTEGER | 單輪最多調(diào)度的任務(wù)數(shù)量 |
| --scheduler-cls TEXT | scheduler使用的類 |
| --help | 顯示幫助信息 |
- 可以使用
pyspider fetcher [OPTIONS]單獨(dú)運(yùn)行Fetcher組件,OPTIONS參數(shù)如下:
| 參數(shù) | 功能 |
|---|---|
| --xmlrpc / --no-xmlrpc | |
| --xmlrpc-host TEXT | |
| --xmlrpc-port INTEGER | |
| --poolsize INTEGER | 同時請求的個數(shù) |
| --proxy TEXT | 使用的代理 |
| --user-agent TEXT | 使用的User-Agent |
| --timeout TEXT | 超時時間 |
| --fetcher-cls TEXT | Fetcher使用的類 |
| --help | 顯示幫助信息 |
- 可以使用
pyspider processor [OPTIONS]單獨(dú)運(yùn)行Processor組件,OPTIONS參數(shù)如下:
| 參數(shù) | 功能 |
|---|---|
| --processor-cls TEXT | Processor使用的類 |
| --help | 顯示幫助信息 |
- 可以使用
pyspider webui [OPTIONS]單獨(dú)運(yùn)行WebUI,OPTIONS參數(shù)如下:
| 參數(shù) | 功能 |
|---|---|
| --host TEXT | 運(yùn)行地址 |
| --port INTEGER | 運(yùn)行端口 |
| --cdn TEXT | js/css的cdn服務(wù)器 |
| --scheduler-rpc TEXT | scheduler的xmlrpc路徑 |
| --fetcher-rpc TEXT | fetcher的xmlrpc路徑 |
| --max-rate FLOAT | 每個項目最大的rate值 |
| --max-burst FLOAT | 每個項目最大的burst值 |
| --username TEXT | Auth驗證的用戶名 |
| --password TEXT | Auth驗證的密碼 |
| --need-auth | 是否需要驗證 |
| --webui-instance TEXT | 運(yùn)行時使用的Flash應(yīng)用 |
| --help | 顯示幫助信息 |
7.2 self.crawl()用法
-
self.crawl()方法實現(xiàn)了新請求的生成,參數(shù)配置如下:
| 參數(shù) | 功能 |
|---|---|
| url | 目標(biāo)爬取的url或url列表。 |
| callback | 爬取響應(yīng)的回調(diào)函數(shù)。 |
| age | 任務(wù)有效時間,如果某個任務(wù)在有效時間內(nèi)且已經(jīng)被執(zhí)行,則不會重復(fù)執(zhí)行。 |
| priority | 爬取任務(wù)的優(yōu)先級,默認(rèn)為0,數(shù)值越大越被優(yōu)先調(diào)用。 |
| exetime | 定時任務(wù),默認(rèn)為0,代表立即執(zhí)行。 |
| retries | 重試次數(shù),默認(rèn)為3。 |
| itag | 判斷網(wǎng)頁節(jié)點(diǎn)和上次爬取的是否相同,如果相同則不重復(fù)爬取。 |
| auto_recrawl | 如果為True,則任務(wù)過期后會重復(fù)執(zhí)行。 |
| method | HTTP請求方式,默認(rèn)為GET。 |
| params | 用來定義GET請求的參數(shù)。 |
| data | 用來傳遞POST表單數(shù)據(jù)。 |
| files | 上傳的文件。 |
| user_agent | 爬取使用的User-Agent。 |
| headers | 爬取使用的Headers。 |
| cookies | 爬取使用的Cookies。 |
| connect_timeout | 初始化鏈接等待的最長時間,默認(rèn)20秒。 |
| timeout | 抓取網(wǎng)頁的最長等待時間,默認(rèn)120秒。 |
| allow_redirects | 是否自動處理重定向,默認(rèn)為True。 |
| validate_cert | 是否驗證HTTPS證書,默認(rèn)為True。 |
| proxy | 用于配置代理。 |
| fetch_type | 使用fetch_type=js可以開啟PhantomJS渲染,用于抓取JavaScript頁面。 |
| js_script | 頁面加載完畢后執(zhí)行JS腳本,傳入腳本字符串。 |
| js_run_at | JS腳本運(yùn)行位置,默認(rèn)document-end。 |
| js_viewport_width/js_viewport_height | JS渲染頁面時的窗口大小。 |
| load_images | 加載JS頁面時是否加載圖片,默認(rèn)為False。 |
| save | 可以在不同的方法之間傳遞參數(shù)。 |
| cancel | 取消任務(wù)。 |
| force_update | 用于強(qiáng)制更新爬蟲狀態(tài)。 |
- 可以使用
crawl_config指定全局配置,配置中的參數(shù)會和crawl()方法創(chuàng)建任務(wù)時的參數(shù)合并。
>>>class Handler(BaseHandler):
>>> crawl_config = {
>>> }
7.3 任務(wù)區(qū)分
- 可以使用URL的MD5值作為任務(wù)的唯一ID,判斷是否是重復(fù)任務(wù)。
>>>import pyspider.libs.utils import md5string
>>>import json
>>>def get_taskid(self,task):
>>> return md5string(task['url']+json.dumps(task['fetch'].get('data','')))
7.4 定時爬取
- 可以通過every屬性設(shè)置爬取的時間間隔。
- 需要大于有效時間。
# 一小時爬取一次
@every(minutes=60)
def on_start(self):
self.crawl(url,callback=self.index_page)
7.5 項目狀態(tài)
| 狀態(tài) | 含義 |
|---|---|
| TODO | 項目被創(chuàng)建,但未實現(xiàn)。 |
| STOP | 項目停止。 |
| CHECKING | 項目被修改后,或出錯需要調(diào)整。 |
| DEBUG | 項目未測試通過,但也可以執(zhí)行。 |
| RUNNING | 項目運(yùn)行。 |
| PAUSE | 項目遇到錯誤暫停,等待一定時間后繼續(xù)爬取。 |
7.6 刪除項目
-
如果要刪除項目,需要將項目狀態(tài)設(shè)置為STOP,并將分組設(shè)置為delete,24小時后項目自動刪除。
參考資料
- https://blog.csdn.net/u010138758/article/details/80152151 J-Ombudsman
- https://www.cnblogs.com/zhuluqing/p/8832205.html moisiet
- https://www.runoob.com 菜鳥教程
- http://www.tulingxueyuan.com/ 北京圖靈學(xué)院
- http://www.imooc.com/article/19184?block_id=tuijian_wz#child_5_1 兩點(diǎn)水
- https://blog.csdn.net/weixin_44213550/article/details/91346411 python老菜鳥
- https://realpython.com/python-string-formatting/ Dan Bader
- https://www.liaoxuefeng.com/ 廖雪峰
- https://blog.csdn.net/Gnewocean/article/details/85319590 新海說
- https://www.cnblogs.com/Nicholas0707/p/9021672.html Nicholas
- https://www.cnblogs.com/dalaoban/p/9331113.html 超天大圣
- https://blog.csdn.net/zhubao124/article/details/81662775 zhubao124
- https://blog.csdn.net/z59d8m6e40/article/details/72871485 z59d8m6e40
- http://www.itdecent.cn/p/2b04f5eb5785 MR_ChanHwang
- 《Python學(xué)習(xí)手冊》Mark Lutz
- 《Python編程 從入門到實踐》Eric Matthes
- 《Python3網(wǎng)絡(luò)爬蟲開發(fā)實戰(zhàn)》崔慶才
本文作者:大師兄(superkmi)





















