大師兄的Python學(xué)習(xí)筆記(二十八): 爬蟲(九)

大師兄的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小時后項目自動刪除。


參考資料



本文作者:大師兄(superkmi)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容