提供方便易用的WebUI系統,可視化地編寫和調試爬蟲。css
提供爬取進度監控、 爬取結果查看、爬蟲項目管理等功能。html
支持多種後端數據庫,如MySQL、 MongoDB、 Redis、 SQLite、 Elasticsearch、 PostgreSQL。web
支持多種消息隊列,如RabbitMQ、 Beanstalk、 Redis、 Kombu。sql
提供優先級控制、失敗重試、定時抓取等功能。數據庫
對接了PhantomJS,能夠抓取JavaScript渲染的頁面。json
支持單機和分佈式部署,支持Docker部署。後端
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()方法,這裏能夠定義後處理過程。
==================================================================================== 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 # 顯示幫助信息 ====================================================================================
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數據庫)。
- 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','')))
pyspider可使用crawl_config來指定全局的配置,配置中的參數會和crawl()方法建立任務時的參數合井。
class Handler(BaseHandler): crawl_config = {'headers':{'User-Agent':'GoogleBot'}}
經過every屬性來設置爬取的時間間隔。
@every(minutes=24 * 60) def on_start(self): for url in urllist: self.crawl(url, callback=self.index_page)
每一個項目都有6個狀態,分別是TODO、 STOP、 CHECKING、 DEBUG、 RUNNING、 PAUSE。
TODO:它是項目剛剛被建立還未實現時的狀態。
STOP:若是想中止某項目的抓取,能夠將項目的狀態設置爲STOP。
CHECKING:正在運行的項目被修改後就會變成CHEC阻NG狀態,項目在中途出錯須要調整的時候會遇到這種狀況。
DEBUG/RUNNING:這兩個狀態對項目的運行沒有影響,狀態設置爲任意一個,項目均可以運行,可是能夠用兩者來區分項目是否已經測試經過。
PAUSE:當爬取過程當中出現連續屢次錯誤時,項目會自動設置爲PAUSE狀態,並等待必定時間後繼續爬取。