Python3 爬蟲學習筆記 C18【爬蟲框架 pyspider — 深入理解】


Python3 爬蟲學習筆記第十八章 —— 【爬蟲框架 pyspider — 深入理解】


【18.1】啓動參數

常用啓動命令:pyspider all,完整命令結構爲:pyspider [OPTIONS] COMMAND [ARGS],OPTIONS 爲可選參數,包含以下參數:

  • -c, --config FILENAME:指定配置文件名稱
  • –logging-config TEXT:日誌配置文件名稱,默認: pyspider/pyspider/logging.conf
  • –debug:開啓調試模式
  • –queue-maxsize INTEGER:隊列的最大長度
  • –taskdb TEXT:taskdb 的數據庫連接字符串,默認: sqlite
  • –projectdb TEXT:projectdb 的數據庫連接字符串,默認: sqlite
  • –resultdb TEXT:resultdb 的數據庫連接字符串,默認: sqlite
  • –message-queue TEXT:消息隊列連接字符串,默認: multiprocessing.Queue
  • –phantomjs-proxy TEXT:PhantomJS 使用的代理,ip:port 的形式
  • –data-path TEXT:數據庫存放的路徑
  • –add-sys-path / --not-add-sys-path:將當前工作目錄添加到python lib搜索路徑
  • –version:顯示 pyspider 的版本信息
  • –help:顯示幫助信息

配置文件爲一個 JSON 文件,一般爲 config.json 文件,常用配置如下:

{
  "taskdb": "mysql+taskdb://username:password@host:port/taskdb",
  "projectdb": "mysql+projectdb://username:password@host:port/projectdb",
  "resultdb": "mysql+resultdb://username:password@host:port/resultdb",
  "message_queue": "amqp://username:password@host:port/%2F",
  "webui": {
  	"port": 5000,
    "username": "some_name",
    "password": "some_passwd",
    "need-auth": true
  }
}

可以設置對應的用戶名,密碼,端口等信息,使用命令 pyspider -c config.json all 即可運行


【18.2】運行單個組件

pyspider 的架構主要分爲 Scheduler(調度器)、Fetcher(抓取器)、Processer(處理器)三個部分,都可以單獨運行,基本命令: pyspider [component_name] [options]


【18.2.1】運行 Scheduler

pyspider scheduler [OPTIONS]
Options:
  --xmlrpc /--no-xmlrpc
  --xmlrpc-host TEXT
  --xmlrpc-port INTEGER
  --inqueue-limit INTEGER  任務隊列的最大長度,如果滿了則新的任務會被忽略
  --delete-time INTEGER    設置爲 delete 標記之前的刪除時間
  --active-tasks INTEGER   當前活躍任務數量配置
  --loop-limit INTEGER     單輪最多調度的任務數量
  --fail-pause-num INTEGER 上次失敗時自動暫停項目暫停次數,任務失敗,將0設置爲禁用
  --scheduler-cls TEXT     Scheduler 使用的類
  --threads TEXT           ThreadBaseScheduler 的線程號,默認值:4
  --help                   顯示幫助信息

【18.2.2】運行 Fetcher

pyspider fetcher [OPTIONS]
Options:
  --xmlrpc /--no-xmlrpc
  --xmlrpc-host TEXT
  --xmlrpc-port INTEGER
  --poolsize INTEGER         同時請求的個數
  --proxy TEXT               使用的代理
  --user-agent TEXT          使用的 User-Agent
  --timeout TEXT             超時時間
  --phantomjs-endpoint TEXT  phantomjs 的端點,通過 pyspider 啓動 phantomjs
  --splash-endpoint TEXT     執行 splash 的端點:http://splash.readthedocs.io/en/stable/api.html execut
  --fetcher-cls TEXT         Fetcher 使用的類
  --help                     顯示幫助信息

【18.2.3】運行 Processer

pyspider processor [OPTIONS]
Options:
  --processor-cls TEXT  Processor 使用的類
  --process-time-limit INTEGER    腳本處理時間限制
  --help                          顯示幫助信息

【18.2.4】運行 WebUI

pyspider webui [OPTIONS]
Options:
  --host TEXT                   運行地址
  --port INTEGER                運行端口
  --cdn TEXT                    JS 和 CSS 的 CDN 服務器
  --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         運行時使用的 Flask 應用
  --process-time-limit INTEGER  調試中的腳本處理時間限制
  --help                        顯示幫助信息

【18.3】crawl() 方法各參數

參數文檔:http://docs.pyspider.org/en/latest/apis/self.crawl/


  • url:爬取目標 URL,可以定義爲單個 URL 字符串,也可以定義成 URL 列表

  • callback:回調函數,指定了該 URL 對應的響應內容用哪個方法來解析,示例:
    def on_start(self):
      self.crawl('http://www.itrhx.com/', callback=self.index_page)
    
    代碼解釋:指定 callbackindex_page,代表爬取 http://www.itrhx.com/ 得到的響應會用 index_page() 方法來解析,而 index_page() 方法的第一個參數就是響應對象,如下所示:
    def index_page(self, response):
      pass
    

  • age:任務的有效時間,如果某個任務在有效時間內且已經被執行,則它不會重複執行,有如下兩種設置方法:

    def on_start(self):
      self.crawl('http://www.itrhx.com/', callback=self.callback, age=10*24*60*60)
    
    @config(age=10 * 24 * 60 * 60)
    def callback(self):
        pass
    

  • priority:爬取任務的優先級,其值默認是 0,priority 的數值越大,對應的請求會越優先被調度,如下所示,2.html 頁面將會優先爬取:
    def index_page(self):
      self.crawl('http://www.itrhx.com/1.html', callback=self.index_page)
      self.crawl('http://www.itrhx.com/2.html', callback=self.detail_page, priority=1)
    

  • exetime:設置定時任務,其值是時間戳,默認是 0,即代表立即執行,如下所示表示該任務會在 30 分鐘之後執行:
    import time
    def on_start(self):
      self.crawl('http://www.itrhx.com/', callback=self.callback, exetime=time.time()+30*60)
    

  • retries:定義重試次數,其值默認是 3

  • itag:設置判定網頁是否發生變化的節點值,在爬取時會判定次當前節點是否和上次爬取到的節點相同。如果節點相同,則證明頁面沒有更新,就不會重複爬取,如下所示:
    def index_page(self, response):
      for item in response.doc('.item').items():
          self.crawl(item.find('a').attr.url, callback=self.detail_page, itag=item.find('.update-time').text())
    
    代碼解釋:設置 update-time 這個節點的值爲 itag,在下次爬取時就會首先檢測這個值有沒有發生變化,如果沒有變化,則不再重複爬取,否則執行爬取

  • auto_recrawl:開啓時,爬取任務在過期後會重新執行,循環時間即定義的 age 時間長度,如下所示:
    def on_start(self):
      self.crawl('http://www.itrhx.com/', callback=self.callback, age=5*60*60, auto_recrawl=True)
    
    代碼解釋:定義 age 有效期爲 5 小時,設置了 auto_recrawlTrue,這樣任務就會每 5 小時執行一次

  • method:HTTP 請求方式,默認爲 GET,如果想發起 POST 請求,可以將 method 設置爲 POST

  • params:定義 GET 請求參數,如下所示表示兩個等價的爬取任務:
    def on_start(self):
      self.crawl('http://httpbin.org/get', callback=self.callback, params={'a': 123, 'b': 'c'})
      self.crawl('http://httpbin.org/get?a=123&b=c', callback=self.callback)
    

  • data:POST 表單數據,當請求方式爲 POST 時,我們可以通過此參數傳遞表單數據,如下所示:
    def on_start(self):
      self.crawl('http://httpbin.org/post', callback=self.callback, method='POST', data={'a': 123, 'b': 'c'})
    

  • files:上傳的文件,需要指定文件名,如下所示:
    def on_start(self):
      self.crawl('http://httpbin.org/post', callback=self.callback, method='POST', files={field: {filename: 'content'}})
    

  • user_agent:爬取使用的 User-Agent

  • headers:爬取時使用的 Headers,即 Request Headers

  • cookies:爬取時使用的 Cookies,爲字典格式

  • connect_timeout:在初始化連接時的最長等待時間,默認爲 20 秒

  • timeout:抓取網頁時的最長等待時間,默認爲 120 秒

  • allow_redirects:確定是否自動處理重定向,默認爲 True

  • validate_cert:確定是否驗證證書,此選項對 HTTPS 請求有效,默認爲 True

  • proxy:爬取時使用的代理,支持用戶名密碼的配置,格式爲 username:password@hostname:port,如下所示:
    def on_start(self):
      self.crawl('http://httpbin.org/get', callback=self.callback, proxy='127.0.0.1:9743')
    
    也可以設置 craw_config 來實現全局配置,如下所示:
    class Handler(BaseHandler):
      crawl_config = {'proxy': '127.0.0.1:9743'}
    

  • fetch_type:開啓 PhantomJS 渲染,如果遇到 JavaScript 渲染的頁面,指定此字段即可實現 PhantomJS 的對接,pyspider 將會使用 PhantomJS 進行網頁的抓取,如下所示:
    def on_start(self):
      self.crawl('https://www.taobao.com', callback=self.index_page, fetch_type='js')
    

  • js_script:頁面加載完畢後執行的 JavaScript 腳本,如下所示,頁面加載成功後將執行頁面混動的 JavaScript 代碼,頁面會下拉到最底部:
    def on_start(self):
      self.crawl('http://www.example.org/', callback=self.callback,
                 fetch_type='js', js_script='''
                 function() {window.scrollTo(0,document.body.scrollHeight);
                     return 123;
                 }
                 ''')
    

  • js_run_at:代表 JavaScript 腳本運行的位置,是在頁面節點開頭還是結尾,默認是結尾,即 document-end

  • js_viewport_width/js_viewport_height:JavaScript 渲染頁面時的窗口大小

  • load_images:在加載 JavaScript 頁面時確定是否加載圖片,默認爲否

  • save:在不同的方法之間傳遞參數,如下所示:
    def on_start(self):
      self.crawl('http://www.example.org/', callback=self.callback,
                 save={'page': 1})
    
    def callback(self, response):
      return response.save['page']
    

  • cancel:取消任務,如果一個任務是 ACTIVE 狀態的,則需要將 force_update 設置爲 True

  • force_update:即使任務處於 ACTIVE 狀態,那也會強制更新狀態

【18.4】任務區分

pyspider 判斷兩個任務是否是重複的是使用的是該任務對應的 URL 的 MD5 值作爲任務的唯一 ID,如果 ID 相同,那麼兩個任務就會判定爲相同,其中一個就不會爬取了

某些情況下,請求的鏈接是同一個,但是 POST 的參數不同,這時可以重寫 task_id() 方法,利用 URL 和 POST 的參數來生成 ID,改變這個 ID 的計算方式來實現不同任務的區分:

import json
from pyspider.libs.utils import md5string
def get_taskid(self, task):
    return md5string(task['url']+json.dumps(task['fetch'].get('data', '')))

【18.5】全局配置

pyspider 可以使用 crawl_config 來指定全局的配置,配置中的參數會和 crawl() 方法創建任務時的參數合併:

class Handler(BaseHandler):
    crawl_config = {
        'headers': {'User-Agent': 'GoogleBot',}
        'proxy': '127.0.0.1:9743'
    }

【18.6】定時爬取

通過 every 屬性來設置爬取的時間間隔,如下代碼表示每天執行一次爬取:

@every(minutes=24 * 60)
def on_start(self):
    for url in urllist:
        self.crawl(url, callback=self.index_page)

注意事項:如果設置了任務的有效時間(age 參數),因爲在有效時間內爬取不會重複,所以要把有效時間設置得比重複時間更短,這樣纔可以實現定時爬取

錯誤舉例:設定任務的過期時間爲 5 天,而自動爬取的時間間隔爲 1 天,當第二次嘗試重新爬取的時候,pyspider 會監測到此任務尚未過期,便不會執行爬取:

@every(minutes=24 * 60)
def on_start(self):
    self.crawl('http://www.itrhx.com/', callback=self.index_page)

@config(age=5 * 24 * 60 * 60)
def index_page(self):
    pass
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章