數據之路 - Python爬蟲 - PySpider框架

1.PySpider基本功能

  • 提供方便易用的WebUI系統,可視化地編寫和調試爬蟲。css

  • 提供爬取進度監控、 爬取結果查看、爬蟲項目管理等功能。html

  • 支持多種後端數據庫,如MySQL、 MongoDB、 Redis、 SQLite、 Elasticsearch、 PostgreSQL。web

  • 支持多種消息隊列,如RabbitMQ、 Beanstalk、 Redis、 Kombu。sql

  • 提供優先級控制、失敗重試、定時抓取等功能。數據庫

  • 對接了PhantomJS,能夠抓取JavaScript渲染的頁面。json

  • 支持單機和分佈式部署,支持Docker部署。後端

2.PySpider架構

pyspider的架構主要分爲Scheduler(調度器)、Fetcher( 抓取器)、Processer(處理器)三個部分,整個爬取過程受到Monitor (監控器)的監控,抓取的結果被Result Worker (結果處理器)處理。服務器

Scheduler發起任務調度,Fetcher負責抓取網頁內容,Processer負責解析網頁內容,而後將新生成的Request發給Scheduler進行調度,將生成的提取結果輸出保存。cookie

  • 每一個pyspider 的項目對應一個Pythonj閱本,該腳本中定義了一個Handler 類,它有一個on_start()方法。 爬取首先調用on_start()方法生成最初的抓取任務,而後發送給Scheduler進行調度。架構

  • Scheduler將抓取任務分發給Fetcher進行抓取,Fetcher執行並獲得響應,隨後將響應發送給Processer。

  • Processer 處理響應並提取出新的 URL生成新的抓取任務,而後經過消息隊列的方式通知Schduler 當前抓取任務執行狀況,並將新生成的抓取任務發送給Scheduler。 若是生成了新的提取結果,則將其發送到結果隊列等待ResultWorker處理。

  • Scheduler接收到新的抓取任務,而後查詢數據庫,判斷其若是是新的抓取任務或者是須要重試的任務就繼續進行調度,而後將其發送回Fetcher進行抓取。

  • 不斷重複以上工做,直到全部的任務都執行完畢,抓取結束。

  • 抓取結束後,程序會回調on_finished()方法,這裏能夠定義後處理過程。

3.PySpider命令行

 

====================================================================================
pyspider [OPTIONS) COMMAND [ARGS]

-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        # 數據庫存放的路徑
--version               # pyspider的版本
--help                  # 顯示幫助信息
====================================================================================
pyspider scheduler [OPTIONS]

--xmlrpc / --no-xmlrpc
--xmlrpc -host TEXT 
--xmlrpc-port INTEGER 
--inqueue-limit INTEGER     # 任務隊列的最大長度,若是滿了則新的任務會被忽略
--delete-time INTEGER       # 設置爲delete標記以前的刪除時間
--active-tasks INTEGER      # 當前活躍任務數量配置
… loop-limit INTEGER        # 單輪最多調度的任務數量
-scheduler els TEXT         # Scheduler使用的類
--help                      # 顯示幫助信息
====================================================================================
pysp1der fetcher [OPTIONS]

--xmlrpc / --no-xmlrpc 
--xmlrpc-host TEXT 
--xmlrpc-port INTEGER 
--poolsize INTEGER          # 同時請求的個數
--proxy TEXT                # 使用的代理
--user-agent TEXT           # 使用的User-Agent
--timeout TEXT              # 超時時間
--fetcher-els TEXT          # Fetcher使用的類
--help                      # 顯示幫助信息
====================================================================================
pyspider processor [OPTIONS]

--processor-cls TEXT Processor  # 使用的類
--help                          # 顯示幫助信息
====================================================================================
pyspider webui [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應用
--help                      # 顯示幫助信息
====================================================================================
View Code

 

4.PySpider基本使用

pyspider all,啓動pyspider的全部組件,包括PhantomJS、ResultWorker、Processer、Fetcher、 Scheduler、WebUI,這些都是pyspider運行必備的組件。

 

from libs.base_handler import *

class Handler(BaseHandler):

    @every(minutes=24*60, seconds=0)
    def on_start(self):
        self.crawl('http://scrapy.org/', callback=self.index_page)
    
    # @every:告訴調度器 on_start方法天天執行一次。
    # on_start:做爲爬蟲入口代碼,調用此函數,啓動抓取。
    
    @config(age=10*24*60*60)
    def index_page(self, response):
        for each in response.doc('a[href^="http://"]').items():
            self.crawl(each.attr.href, callback=self.detail_page)
    
    # @config:告訴調度器 request請求的過時時間是10天,10天內再遇到這個請求直接忽略。此參數亦可在self.crawl(url, age=10*24*60*60)中設置。
    # index_page:獲取一個Response對象,response.doc是pyquery對象的一個擴展方法。
    
    def detail_page(self, response):
        return {
                "url": response.url,
                "title": response.doc('title').text(),
                }
    
    # detail_page:返回一個結果集對象。這個結果默認會被添加到resultdb數據庫(若是啓動時沒有指定數據庫默認調用sqlite數據庫)。

 

5.crawl方法

- url:爬取的url,能夠是單個URL字符串,也能夠是URL列表。
=================================================================================================
- callback:callback是回調函數,指定了該URL對應的響應內容用哪一個方法來解析。

    def on_start(self):
        self.crawl('http://scrapy.org/', callback=self.index_page)
=================================================================================================    
- age:任務的有效時間。 若是某個任務在有效時間內且已經被執行,則它不會重複執行。

    # 設置方法1
    def on_start(self): 
        self.crawl('http://www.example.org/', callback=self.callback, age=10*24*60*6o) 
    
    # 設置方法2
    @config(age=10 * 24 * 60 * 60) 
    def callback(self): 
        pass 
=================================================================================================
- priority:爬取任務的優先級,其值默認是0, priority的數值越大,對應的請求會越優先被調度。

    def index_page(self): 
      self.crawl('http://www.example.org/page.html', callback=self.index_page) 
      self.crawl('http://www.example.org/233.html’, callback=self .detail_page, priority=l) 
=================================================================================================
- exetime:設置定時任務,其值是時間戳,默認是0,即表明當即執行。

    import  time 
    def on_start(self): 
      self.crawl(’http://www.example.org/', 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()) 
=================================================================================================
- auto_recrawl:當開啓時,爬取任務在過時後會從新執行,循環時間即定義的age時間長度。

    def on_start(self): 
        self.craw1('http://www.example.org/', callback=self.callback, age=5*60*60, auto_recrawl=True) 
=================================================================================================  
- 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表單數據。

    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:爬取時使用的代理,它支持用戶名密碼的配置。
    # 設置方法1
    def on_start(self):
        self.crawl(’http://httpbin.org/get', callback=self.callback, proxy=’127.0.0.1:9743') 
        
    # 設置方法2
    class Handler(BaseHandler): 
        crawl_config = { 'proxy':  '121.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腳本。
    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:渲染頁面時的窗口大小。

- load_ images:加載JavaScript頁面時肯定是否加載圖片,它默認是否。
=================================================================================================
- save
    # 設置方法1
    def on_start(self): 
        self.crawl(’http://www.example.org/', callback=self.callback, save={'page': 1}) 
        
    # 設置方法2
    def callback(self,  response): 
        return response.save['page'] 
=================================================================================================
- cancel:是取消任務,若是一個任務是ACTIVE狀態的,則須要將force_update設置爲True。

- force_ update

6.任務區分

在pyspider判斷兩個任務是不是重複的是使用的是該任務對應的URL的MD5值做爲任務的惟一ID,若是D相同,那麼兩個任務就會斷定爲相同,其中一個就不會爬取了。不少狀況下請求的連接多是同一個,可是POST的參數不一樣。

這時能夠重寫task_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',''))) 

7.全局配置

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

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

8.定時爬取

經過every屬性來設置爬取的時間間隔

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

9.項目狀態

每一個項目都有6個狀態,分別是TODO、 STOP、 CHECKING、 DEBUG、 RUNNING、 PAUSE。

  • TODO:它是項目剛剛被建立還未實現時的狀態。

  • STOP:若是想中止某項目的抓取,能夠將項目的狀態設置爲STOP。

  • CHECKING:正在運行的項目被修改後就會變成CHEC阻NG狀態,項目在中途出錯須要調整的時候會遇到這種狀況。

  • DEBUG/RUNNING:這兩個狀態對項目的運行沒有影響,狀態設置爲任意一個,項目均可以運行,可是能夠用兩者來區分項目是否已經測試經過。

  • PAUSE:當爬取過程當中出現連續屢次錯誤時,項目會自動設置爲PAUSE狀態,並等待必定時間後繼續爬取。

相關文章
相關標籤/搜索