Python 爬蟲之 Scrapy 分佈式原理以及部署

Scrapy分佈式原理node

關於Scrapy工做流程python

Scrapy單機架構linux

上圖的架構其實就是一種單機架構,只在本機維護一個爬取隊列,Scheduler進行調度,而要實現多態服務器共同爬取數據關鍵就是共享爬取隊列。git

分佈式架構github

我將上圖進行再次更改web

這裏重要的就是個人隊列經過什麼維護?redis

這裏通常咱們經過Redis爲維護,Redis,非關係型數據庫,Key-Value形式存儲,結構靈活。mongodb

而且redis是內存中的數據結構存儲系統,處理速度快,提供隊列集合等多種存儲結構,方便隊列維護數據庫

如何去重?json

這裏藉助redis的集合,redis提供集合數據結構,在redis集合中存儲每一個request的指紋

在向request隊列中加入Request前先驗證這個Request的指紋是否已經加入集合中。若是已經存在則不添加到request隊列中,若是不存在,則將request加入到隊列並將指紋加入集合

如何防止中斷?若是某個slave由於特殊緣由宕機,如何解決?

這裏是作了啓動判斷,在每臺slave的Scrapy啓動的時候都會判斷當前redis request隊列是否爲空

若是不爲空,則從隊列中獲取下一個request執行爬取。若是爲空則從新開始爬取,第一臺叢集執行爬取向隊列中添加request

如何實現上述這種架構?

這裏有一個scrapy-redis的庫,爲咱們提供了上述的這些功能

scrapy-redis改寫了Scrapy的調度器,隊列等組件,利用他能夠方便的實現Scrapy分佈式架構

關於scrapy-redis的地址:https://github.com/rmax/scrapy-redis

搭建分佈式爬蟲

參考官網地址:https://scrapy-redis.readthedocs.io/en/stable/

前提是要安裝scrapy_redis模塊:pip install scrapy_redis

這裏的爬蟲代碼是用的以前寫過的爬取知乎用戶信息的爬蟲

修改該settings中的配置信息:

替換scrapy調度器

SCHEDULER = "scrapy_redis.scheduler.Scheduler"

添加去重的class

DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"

添加pipeline

若是添加這行配置,每次爬取的數據也都會入到redis數據庫中,因此通常這裏不作這個配置

ITEM_PIPELINES = {

'scrapy_redis.pipelines.RedisPipeline': 300

}

共享的爬取隊列,這裏用須要redis的鏈接信息

這裏的user:pass表示用戶名和密碼,若是沒有則爲空就能夠

REDIS_URL = 'redis://user:pass@hostname:9001'

設置爲爲True則不會清空redis裏的dupefilter和requests隊列

這樣設置後指紋和請求隊列則會一直保存在redis數據庫中,默認爲False,通常不進行設置

SCHEDULER_PERSIST = True

設置重啓爬蟲時是否清空爬取隊列

這樣每次重啓爬蟲都會清空指紋和請求隊列,通常設置爲False

SCHEDULER_FLUSH_ON_START=True

分佈式

將上述更改後的代碼拷貝的各個服務器,固然關於數據庫這裏能夠在每一個服務器上都安裝數據,也能夠共用一個數據,我這裏方面是鏈接的同一個mongodb數據庫,固然各個服務器上也不能忘記:

全部的服務器都要安裝scrapy,scrapy_redis,pymongo

這樣運行各個爬蟲程序啓動後,在redis數據庫就能夠看到以下內容,dupefilter是指紋隊列,requests是請求隊列

Scrapy分佈式部署

這個scrapyd的github地址:https://github.com/scrapy/scrapyd

當在遠程主機上安裝了scrapyd並啓動以後,就會再遠程主機上啓動一個web服務,默認是6800端口,這樣咱們就能夠經過http請求的方式,經過接口的方式管理咱們scrapy項目,這樣就不須要在一個一個電腦鏈接拷貝過着經過git,關於scrapyd官方文檔地址:http://scrapyd.readthedocs.io/en/stable/

安裝scrapyd

安裝scrapyd:pip install scrapyd

這裏我在另一臺ubuntu linux虛擬機中一樣安裝scrapy以及scrapyd等包,保證所要運行的爬蟲須要的包都完成安裝,這樣咱們就有了兩臺linux,包括上篇文章中咱們已經有的linux環境

在這裏有個小問題須要注意,默認scrapyd啓動是經過scrapyd就能夠直接啓動,這裏bind綁定的ip地址是127.0.0.1端口是:6800,這裏爲了其餘虛擬機訪問講ip地址設置爲0.0.0.0

scrapyd的配置文件:/usr/local/lib/python3.5/dist-packages/scrapyd/default_scrapyd.conf

這樣咱們就能夠經過瀏覽器訪問:

關於部署

如何經過scrapyd部署項目,這裏官方文檔提供一個地址:https://github.com/scrapy/scrapyd-client,即經過scrapyd-client進行操做

這裏的scrapyd-client主要實現如下內容:

把咱們本地代碼打包生成egg文件

根據咱們配置的url上傳到遠程服務器上

咱們將咱們本地的scrapy項目中scrapy.cfg配置文件進行配置:

咱們其實還能夠設置用戶名和密碼,不過這裏沒什麼必要,只設置了url

這裏設置url必定要注意:url = http://192.168.1.9:6800/addversion.json

最後的addversion.json不能少

咱們在本地安裝pip install scrapy_client,安裝完成後執行:scrapyd-deploy

zhaofandeMBP:zhihu_user zhaofan$ scrapyd-deployPacking version 1502177138Deploying to project "zhihu_user" in http://192.168.1.9:6800/addversion.jsonServer response (200):{"node_name": "fan-VirtualBox", "status": "ok", "version": "1502177138", "spiders": 1, "project": "zhihu_user"}zhaofandeMBP:zhihu_user zhaofan$看到status:200表示已經成功

關於經常使用操做API

listprojects.json列出上傳的項目列表

zhaofandeMBP:zhihu_user zhaofan$ curl http://192.168.1.9:6800/listprojects.json{"node_name": "fan-VirtualBox", "status": "ok", "projects": ["zhihu_user"]}zhaofandeMBP:zhihu_user zhaofan$listversions.json列出有某個上傳項目的版本

zhaofandeMBP:zhihu_user zhaofan$ curl http://192.168.1.9:6800/listversions.json?project=zhihu_user{"node_name": "fan-VirtualBox", "status": "ok", "versions": ["1502177138"]}zhaofandeMBP:zhihu_user zhaofan$schedule.json遠程任務的啓動

下面咱們啓動的三次就表示咱們啓動了三個任務,也就是三個調度任務來運行zhihu這個爬蟲

zhaofandeMBP:zhihu_user zhaofan$ curl http://192.168.1.9:6800/schedule.json -d project=zhihu_user -d spider=zhihu{"node_name": "fan-VirtualBox", "status": "ok", "jobid": "97f1b5027c0e11e7b07a080027bbde73"}zhaofandeMBP:zhihu_user zhaofan$ curl http://192.168.1.9:6800/schedule.json -d project=zhihu_user -d spider=zhihu{"node_name": "fan-VirtualBox", "status": "ok", "jobid": "99595aa87c0e11e7b07a080027bbde73"}zhaofandeMBP:zhihu_user zhaofan$ curl http://192.168.1.9:6800/schedule.json -d project=zhihu_user -d spider=zhihu{"node_name": "fan-VirtualBox", "status": "ok", "jobid": "9abb1ba27c0e11e7b07a080027bbde73"}zhaofandeMBP:zhihu_user zhaofan$同時當啓動完成後,咱們能夠經過頁面查看jobs,這裏由於我遠端服務器並無安裝scrapy_redis,因此顯示任務是完成了,我點開日誌並能看到詳細的日誌狀況:

這裏出錯的緣由就是我上面忘記在ubuntu虛擬機安裝scrapy_redis以及pymongo模塊,進行

pip install scrapy_redis pymongo安裝後從新啓動,就能夠看到已經在運行的任務,同時點開Log日誌也能看到爬取到的內容:

listjobs.json列出全部的jobs任務

上面是經過頁面顯示全部的任務,這裏是經過命令獲取結果

zhaofandeMBP:zhihu_user zhaofan$ curl http://192.168.1.9:6800/listjobs.json?project=zhihu_user{"node_name": "fan-VirtualBox", "status": "ok", "running": [], "pending": [], "finished": [{"start_time": "2017-08-08 15:53:00.510050", "spider": "zhihu", "id": "97f1b5027c0e11e7b07a080027bbde73", "end_time": "2017-08-08 15:53:01.416139"}, {"start_time": "2017-08-08 15:53:05.509337", "spider": "zhihu", "id": "99595aa87c0e11e7b07a080027bbde73", "end_time": "2017-08-08 15:53:06.627125"}, {"start_time": "2017-08-08 15:53:10.509978", "spider": "zhihu", "id": "9abb1ba27c0e11e7b07a080027bbde73", "end_time": "2017-08-08 15:53:11.542001"}]}zhaofandeMBP:zhihu_user zhaofan$cancel.json取消全部運行的任務

這裏能夠將上面啓動的全部jobs均可以取消:

zhaofandeMBP:zhihu_user zhaofan$ curl http://192.168.1.9:6800/cancel.json -d project=zhihu_user -d job=0f5cdabc7c1011e7b07a080027bbde73{"node_name": "fan-VirtualBox", "status": "ok", "prevstate": "running"}zhaofandeMBP:zhihu_user zhaofan$ curl http://192.168.1.9:6800/cancel.json -d project=zhihu_user -d job=63f8e12e7c1011e7b07a080027bbde73{"node_name": "fan-VirtualBox", "status": "ok", "prevstate": "running"}zhaofandeMBP:zhihu_user zhaofan$ curl http://192.168.1.9:6800/cancel.json -d project=zhihu_user -d job=63f8e12f7c1011e7b07a080027bbde73{"node_name": "fan-VirtualBox", "status": "ok", "prevstate": "running"}這樣當咱們再次經過頁面查看,就能夠看到全部的任務都是finshed狀態:

我相信看了上面這幾個方法你必定會以爲真不方便還須要輸入那麼長,因此有人替你幹了件好事把這些API進行的再次封裝:https://github.com/djm/python-scrapyd-api

關於python-scrapyd-api

該模塊可讓咱們直接在python代碼中進行上述那些api的操做

首先先安裝該模塊:pip install python-scrapyd-api

使用方法以下,這裏只演示了簡單的例子,其餘方法其實使用很簡單按照規則寫就行:

from scrapyd_api import ScrapydAPIscrapyd = ScrapydAPI('http://192.168.1.9:6800')res = scrapyd.list_projects()res2 = scrapyd.list_jobs('zhihu_user')print(res)print(res2)Cancel a scheduled job

scrapyd.cancel('project_name', '14a6599ef67111e38a0e080027880ca6')

Delete a project and all sibling versions

scrapyd.delete_project('project_name')

Delete a version of a project

scrapyd.delete_version('project_name', 'version_name')

Request status of a job

scrapyd.job_status('project_name', '14a6599ef67111e38a0e080027880ca6')

List all jobs registered

scrapyd.list_jobs('project_name')

List all projects registered

scrapyd.list_projects()

List all spiders available to a given project

scrapyd.list_spiders('project_name')

List all versions registered to a given project

scrapyd.list_versions('project_name')

Schedule a job to run with a specific spider

scrapyd.schedule('project_name', 'spider_name')

Schedule a job to run while passing override settings

settings = {'DOWNLOAD_DELAY': 2}

Schedule a job to run while passing extra attributes to spider initialisation

scrapyd.schedule('project_name', 'spider_name', extra_attribute='value')

以上是所有代碼,只是善於分享,不足之處請包涵!爬蟲基本的原理就是,獲取源碼,進而獲取網頁內容。通常來講,只要你給一個入口,經過分析,能夠找到無限個其餘相關的你須要的資源,進而進行爬取。

相關文章
相關標籤/搜索