第50讲:Scrapy 部署不用愁,Scrapyd 的原理和使用
上節(jié)課我們的分布式爬蟲部署完成并可以成功運行了,但是有個環(huán)節(jié)非常煩瑣,那就是代碼部署。
我們設想下面的幾個場景:
-
如果采用上傳文件的方式部署代碼,我們首先需要將代碼壓縮,然后采用 SFTP 或 FTP 的方式將文件上傳到服務器,之后再連接服務器將文件解壓,每個服務器都需要這樣配置。
-
如果采用 Git 同步的方式部署代碼,我們可以先把代碼 Push 到某個 Git 倉庫里,然后再遠程連接各臺主機執(zhí)行 Pull 操作,同步代碼,每個服務器同樣需要做一次操作。
如果代碼突然有更新,那我們必須更新每個服務器,而且萬一哪臺主機的版本沒控制好,還可能會影響整體的分布式爬取狀況。
所以我們需要一個更方便的工具來部署 Scrapy 項目,如果可以省去一遍遍逐個登錄服務器部署的操作,那將會方便很多。
本節(jié)我們就來看看提供分布式部署的工具 Scrapyd。
1.了解 Scrapyd
接下來,我們就來深入地了解 Scrapyd,Scrapyd 是一個運行 Scrapy 爬蟲的服務程序,它提供一系列 HTTP 接口來幫助我們部署、啟動、停止、刪除爬蟲程序。Scrapyd 支持版本管理,同時還可以管理多個爬蟲任務,利用它我們可以非常方便地完成 Scrapy 爬蟲項目的部署任務調(diào)度。
準備工作
首先我們需要安裝 scrapyd,一般我們部署的服務器是 Linux,所以這里以 Linux 為例來進行說明。
這里推薦使用 pip 安裝,命令如下:
pip3 install scrapyd另外為了我們編寫的項目能夠運行成功,還需要安裝項目本身的環(huán)境依賴,如上一節(jié)的項目需要依賴 Scrapy、Scrapy-Redis、Gerapy-Pyppeteer 等庫,也需要在服務器上安裝,否則會出現(xiàn)部署失敗的問題。
安裝完畢之后,需要新建一個配置文件 /etc/scrapyd/scrapyd.conf,Scrapyd 在運行的時候會讀取此配置文件。
在 Scrapyd 1.2 版本之后,不會自動創(chuàng)建該文件,需要我們自行添加。首先,執(zhí)行如下命令新建文件:
sudo mkdir /etc/scrapyd sudo vi /etc/scrapyd/scrapyd.conf接著寫入如下內(nèi)容:
[scrapyd] eggs_dir = eggs logs_dir = logs items_dir = jobs_to_keep = 5 dbs_dir = dbs max_proc = 0 max_proc_per_cpu = 10 finished_to_keep = 100 poll_interval = 5.0 bind_address = 0.0.0.0 http_port = 6800 debug = off runner = scrapyd.runner application = scrapyd.app.application launcher = scrapyd.launcher.Launcher webroot = scrapyd.website.Root ? [services] schedule.json = scrapyd.webservice.Schedule cancel.json = scrapyd.webservice.Cancel addversion.json = scrapyd.webservice.AddVersion listprojects.json = scrapyd.webservice.ListProjects listversions.json = scrapyd.webservice.ListVersions listspiders.json = scrapyd.webservice.ListSpiders delproject.json = scrapyd.webservice.DeleteProject delversion.json = scrapyd.webservice.DeleteVersion listjobs.json = scrapyd.webservice.ListJobs daemonstatus.json = scrapyd.webservice.DaemonStatus配置文件的內(nèi)容可以參見官方文檔 https://scrapyd.readthedocs.io/en/stable/config.html#example-configuration-file。這里的配置文件有所修改,其中之一是 max_proc_per_cpu 官方默認為 4,即一臺主機每個 CPU 最多運行 4 個 Scrapy 任務,在此提高為 10。另外一個是 bind_address,默認為本地 127.0.0.1,在此修改為 0.0.0.0,以使外網(wǎng)可以訪問。
Scrapyd 是一個純 Python 項目,這里可以直接調(diào)用它來運行。為了使程序一直在后臺運行,Linux 和 Mac 可以使用如下命令:
(scrapyd > /dev/null &)這樣 Scrapyd 就可以在后臺持續(xù)運行了,控制臺輸出直接忽略。當然,如果想記錄輸出日志,可以修改輸出目標,如下所示:
(scrapyd> ~/scrapyd.log &)此時會將 Scrapyd 的運行結果輸出到~/scrapyd.log 文件中。當然也可以使用 screen、tmux、supervisor 等工具來實現(xiàn)進程守護。
安裝并運行了 Scrapyd 之后,我們就可以訪問服務器的 6800 端口看到一個 WebUI 頁面了,例如我的服務器地址為 120.27.34.25,在上面安裝好了 Scrapyd 并成功運行,那么我就可以在本地的瀏覽器中打開: http://120.27.34.25:6800,就可以看到 Scrapyd 的首頁,這里請自行替換成你的服務器地址查看即可,如圖所示:
如果可以成功訪問到此頁面,那么證明 Scrapyd 配置就沒有問題了。
2. Scrapyd 的功能
Scrapyd 提供了一系列 HTTP 接口來實現(xiàn)各種操作,在這里我們可以將接口的功能梳理一下,以 Scrapyd 所在的 IP 為 120.27.34.25 為例進行講解。
2.1 daemonstatus.json
這個接口負責查看 Scrapyd 當前服務和任務的狀態(tài),我們可以用 curl 命令來請求這個接口,命令如下:
curl http://139.217.26.30:6800/daemonstatus.json這樣我們就會得到如下結果:
{"status": "ok", "finished": 90, "running": 9, "node_name": "datacrawl-vm", "pending": 0}返回結果是 Json 字符串,status 是當前運行狀態(tài), finished 代表當前已經(jīng)完成的 Scrapy 任務,running 代表正在運行的 Scrapy 任務,pending 代表等待被調(diào)度的 Scrapyd 任務,node_name 就是主機的名稱。
2.2 addversion.json
這個接口主要是用來部署 Scrapy 項目,在部署的時候我們需要首先將項目打包成 Egg 文件,然后傳入項目名稱和部署版本。
我們可以用如下的方式實現(xiàn)項目部署:
curl http://120.27.34.25:6800/addversion.json -F project=wenbo -F version=first -F egg=@weibo.egg在這里 -F 即代表添加一個參數(shù),同時我們還需要將項目打包成 Egg 文件放到本地。
這樣發(fā)出請求之后我們可以得到如下結果:
這個結果表明部署成功,并且其中包含的 Spider 的數(shù)量為 3。此方法部署可能比較煩瑣,在后面我會介紹更方便的工具來實現(xiàn)項目的部署。
2.3 schedule.json
這個接口負責調(diào)度已部署好的 Scrapy 項目運行。我們可以通過如下接口實現(xiàn)任務調(diào)度:
curl http://120.27.34.25:6800/schedule.json -d project=weibo -d spider=weibocn在這里需要傳入兩個參數(shù),project 即 Scrapy 項目名稱,spider 即 Spider 名稱。返回結果如下:
{"status": "ok", "jobid": "6487ec79947edab326d6db28a2d86511e8247444"}status 代表 Scrapy 項目啟動情況,jobid 代表當前正在運行的爬取任務代號。
2.4 cancel.json
這個接口可以用來取消某個爬取任務,如果這個任務是 pending 狀態(tài),那么它將會被移除,如果這個任務是 running 狀態(tài),那么它將會被終止。
我們可以用下面的命令來取消任務的運行:
curl http://120.27.34.25:6800/cancel.json -d project=weibo -d job=6487ec79947edab326d6db28a2d86511e8247444在這里需要傳入兩個參數(shù),project 即項目名稱,job 即爬取任務代號。返回結果如下:
{"status": "ok", "prevstate": "running"}status 代表請求執(zhí)行情況,prevstate 代表之前的運行狀態(tài)。
2.5 listprojects.json
這個接口用來列出部署到 Scrapyd 服務上的所有項目描述。我們可以用下面的命令來獲取 Scrapyd 服務器上的所有項目描述:
curl http://120.27.34.25:6800/listprojects.json這里不需要傳入任何參數(shù)。返回結果如下:
{"status": "ok", "projects": ["weibo", "zhihu"]}status 代表請求執(zhí)行情況,projects 是項目名稱列表。
2.6 listversions.json
這個接口用來獲取某個項目的所有版本號,版本號是按序排列的,最后一個條目是最新的版本號。
我們可以用如下命令來獲取項目的版本號:
curl http://120.27.34.25:6800/listversions.json?project=weibo在這里需要一個參數(shù) project,就是項目的名稱。返回結果如下:
{"status": "ok", "versions": ["v1", "v2"]}status 代表請求執(zhí)行情況,versions 是版本號列表。
2.7 listspiders.json
這個接口用來獲取某個項目最新的一個版本的所有 Spider 名稱。我們可以用如下命令來獲取項目的 Spider 名稱:
curl http://120.27.34.25:6800/listspiders.json?project=weibo在這里需要一個參數(shù) project,就是項目的名稱。返回結果如下:
{"status": "ok", "spiders": ["weibocn"]}status 代表請求執(zhí)行情況,spiders 是 Spider 名稱列表。
2.8 listjobs.json
這個接口用來獲取某個項目當前運行的所有任務詳情。我們可以用如下命令來獲取所有任務詳情:
curl http://120.27.34.25:6800/listjobs.json?project=weibo在這里需要一個參數(shù) project,就是項目的名稱。返回結果如下:
{"status": "ok", "pending": [{"id": "78391cc0fcaf11e1b0090800272a6d06", "spider": "weibocn"}], "running": [{"id": "422e608f9f28cef127b3d5ef93fe9399", "spider": "weibocn", "start_time": "2017-07-12 10:14:03.594664"}], "finished": [{"id": "2f16646cfcaf11e1b0090800272a6d06", "spider": "weibocn", "start_time": "2017-07-12 10:14:03.594664", "end_time": "2017-07-12 10:24:03.594664"}]}status 代表請求執(zhí)行情況,pendings 代表當前正在等待的任務,running 代表當前正在運行的任務,finished 代表已經(jīng)完成的任務。
2.9 delversion.json
這個接口用來刪除項目的某個版本。我們可以用如下命令來刪除項目版本:
curl http://120.27.34.25:6800/delversion.json -d project=weibo -d version=v1在這里需要一個參數(shù) project,就是項目的名稱,還需要一個參數(shù) version,就是項目的版本。返回結果如下:
{"status": "ok"}status 代表請求執(zhí)行情況,這樣就代表刪除成功了。
2.10 delproject.json
這個接口用來刪除某個項目。我們可以用如下命令來刪除某個項目:
curl http://120.27.34.25:6800/delproject.json -d project=weibo在這里需要一個參數(shù) project,就是項目的名稱。返回結果如下:
{"status": "ok"}status 代表請求執(zhí)行情況,這樣就代表刪除成功了。
以上就是 Scrapyd 所有的接口,我們可以直接請求 HTTP 接口即可控制項目的部署、啟動、運行等操作。
3.ScrapydAPI 的使用
以上的這些接口可能使用起來還不是很方便,沒關系,還有一個 ScrapydAPI 庫對這些接口又做了一層封裝,其安裝方式如下:
pip3 install python-scrapyd-api下面我們來看下 ScrapydAPI 的使用方法,其實核心原理和 HTTP 接口請求方式并無二致,只不過用 Python 封裝后使用更加便捷。
我們可以用如下方式建立一個 ScrapydAPI 對象:
然后就可以通過調(diào)用它的方法來實現(xiàn)對應接口的操作了,例如部署的操作可以使用如下方式:
egg = open('weibo.egg', 'rb') scrapyd.add_version('weibo', 'v1', egg)這樣我們就可以將項目打包為 Egg 文件,然后把本地打包的 Egg 項目部署到遠程 Scrapyd 了。
另外 ScrapydAPI 還實現(xiàn)了所有 Scrapyd 提供的 API 接口,名稱都是相同的,參數(shù)也是相同的。
例如我們可以調(diào)用 list_projects 方法即可列出 Scrapyd 中所有已部署的項目:
scrapyd.list_projects() ['weibo', 'zhihu']另外還有其他的方法在此不再一一列舉了,名稱和參數(shù)都是相同的,更加詳細的操作可以參考其官方文檔: http://python-scrapyd-api.readthedocs.io/。
我們可以通過它來部署項目,并通過 HTTP 接口來控制任務的運行,不過這里有一個不方便的地方就是部署過程,首先它需要打包 Egg 文件然后再上傳,還是比較煩瑣的,這里再介紹另外一個工具 Scrapyd-Client。
4.Scrapyd-Client 部署
Scrapyd-Client 為了方便 Scrapy 項目的部署,提供兩個功能:
-
將項目打包成 Egg 文件。
-
將打包生成的 Egg 文件通過 addversion.json 接口部署到 Scrapyd 上。
也就是說,Scrapyd-Client 幫我們把部署全部實現(xiàn)了,我們不需要再去關心 Egg 文件是怎樣生成的,也不需要再去讀 Egg 文件并請求接口上傳了,這一切的操作只需要執(zhí)行一個命令即可一鍵部署。
要部署 Scrapy 項目,我們首先需要修改一下項目的配置文件,例如我們之前寫的 Scrapy 項目,在項目的第一層會有一個 scrapy.cfg 文件,它的內(nèi)容如下:
[settings] default = scrapypyppeteer.settings ? [deploy] #url = http://localhost:6800/ project = scrapypyppeteer在這里我們需要配置 deploy,例如我們要將項目部署到 120.27.34.25 的 Scrapyd 上,就需要修改為如下內(nèi)容:
[deploy] url = http://120.27.34.25:6800/ project = scrapypyppeteer這樣我們再在 scrapy.cfg 文件所在路徑執(zhí)行如下命令:
scrapyd-deploy運行結果如下:
Packing version 1501682277 Deploying to project "weibo" in http://120.27.34.25:6800/addversion.json Server response (200): {"status": "ok", "spiders": 1, "node_name": "datacrawl-vm", "project": "scrapypyppeteer", "version": "1501682277"}返回這樣的結果就代表部署成功了。
我們也可以指定項目版本,如果不指定的話默認為當前時間戳,指定的話通過 version 參數(shù)傳遞即可,例如:
scrapyd-deploy --version 201707131455值得注意的是在 Python3 的 Scrapyd 1.2.0 版本中我們不要指定版本號為帶字母的字符串,需要為純數(shù)字,否則可能會出現(xiàn)報錯。
另外如果我們有多臺主機,我們可以配置各臺主機的別名,例如可以修改配置文件為:
[deploy:vm1] url = http://120.27.34.24:6800/ project = scrapypyppeteer ? [deploy:vm2] url = http://139.217.26.30:6800/ project = scrapypyppeteer有多臺主機的話就在此統(tǒng)一配置,一臺主機對應一組配置,在 deploy 后面加上主機的別名即可,這樣如果我們想將項目部署到 IP 為 139.217.26.30 的 vm2 主機,我們只需要執(zhí)行如下命令:
scrapyd-deploy vm2這樣我們就可以將項目部署到名稱為 vm2 的主機上了。
如此一來,如果我們有多臺主機,我們只需要在 scrapy.cfg 文件中配置好各臺主機的 Scrapyd 地址,然后調(diào)用 scrapyd-deploy 命令加主機名稱即可實現(xiàn)部署,非常方便。
如果 Scrapyd 設置了訪問限制的話,我們可以在配置文件中加入用戶名和密碼的配置,同時修改端口,修改成 Nginx 代理端口,如在模塊一我們使用的是 6801,那么這里就需要改成 6801,修改如下:
[deploy:vm1] url = http://120.27.34.24:6801/ project = scrapypyppeteer username = admin password = admin ? [deploy:vm2] url = http://139.217.26.30:6801/ project = scrapypyppeteer username = germey password = germey這樣通過加入 username 和 password 字段,我們就可以在部署時自動進行 Auth 驗證,然后成功實現(xiàn)部署。
5.總結
以上我們介紹了 Scrapyd、Scrapyd-API、Scrapyd-Client 的部署方式,希望你可以多多嘗試。
總結
以上是生活随笔為你收集整理的第50讲:Scrapy 部署不用愁,Scrapyd 的原理和使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 第27讲:令人抓狂的 JavaScrip
- 下一篇: Frida基础操作命令