Scrapyd 和 ScrapydAPI 的使用

在上一章中,我们学习了 Scrapy 框架,利用它可以快速开发一个爬虫程序。Scrapyd又是什么呢?跟Scrapy相比,Scrapyd多了一个字母d,这个d其实就是部署(deploy)的意思,所以Scrapyd就是为了方便管理和部署Scrapy爬虫程序而诞生的。本节中,我们先简单了解下Scrapyd及其用法。

了解 Scrapyd

Scrapyd 是一个运行Scrapy爬虫的服务程序,它提供一系列HTTP接口来帮助我们部署、启动、停止和删除爬虫程序。Scrapyd支持版本管理,同时还可以管理多个爬虫任务,利用它我们可以非常方便地完成Scrapy爬虫项目的部署任务调度。

准备工作

请确保本机或服务器已经正确安装好了 Scrapyd, 安装命令如下:

pip3 install scrapyd

更详细的安装流程可以参考: https://setup.scrape.center/scrapyd

安装并完成 Scrapyd 相应的配置之后, 我们直接输入 scrapyd 即可启动对应的服务, 命令如下:

scrapyd

运行之后, 会有类似如下的输出:

[Launcher] Scrapyd 1.2.1 started: max_proc=8, runner='scrapyd.runner'

这就代表 Scrapyd 已经启动成功了。

访问 Scrapyd

Scrapyd 默认会在6800端口上运行。访问服务器的6800端口,我们就可以看到一个WebUI页面了。本案例中,我们依然在A(192.168.2.3)服务器上启动Scrapyd服务。启动完成之后,我们打开 http://192.168.2.3:6800/ ,即可看到类似如图17-1所示的页面。

图 17-1 Scrapyd 页面

如果可以成功访问到此页面,那么证明 Scrapyd 配置就没有问题了。

如果访问失败,那 Scrapyd 监听的地址很有可能是 127.0.0.1,这是默认配置。此时可以修改 scrapyd.conf 文件,将 bind_address 修改为 0.0.0.0,具体可以参见 https://scrapyd.readthedocs.io/en/stable/config.html#config

比如,可以在当前命令行行在目录下新建一个 scrapyd.conf 文件,将其内容进行如下修改:

[scrapyd]
bind_address = 0.0.0.0
http_port = 6800

这样就指定了 Scrapyd 可以被公开访问,同时运行在 6800 端口。修改完成之后,再次重启 Scrapyd, 它应该就可以被访问到了。

Scrapyd 的功能

Scrapyd 提供了一系列 HTTP 接口来实现各种操作,这里我们可以将接口的功能梳理一下,以 Scrapyd 所在的 IP 192.168.2.3 为例来进行说明。

此处使用 curl 命令来模拟 HTTP 的各种请求,你也可以使用其他工具(如 Postman、Python 等)来进行请求,效果都是一样的。另外,这里使用的 IP 是 A 主机的 IP,请自行替换为你的 Scrapyd 服务所在主机的 IP。

daemonstatus.json

这个接口负责查看 Scrapyd 当前的服务和任务状态,我们可以用 curl 命令来请求这个接口,具体如下:

curl http://192.168.2.3:6800/daemonstatus.json

这样我们就会得到如下结果:

{"status": "ok", "finished": 90, "running": 9, "node_name": "vm1", "pending": 0}

返回结果是JSON字符串,其中status是当前运行状态,finished代表当前已经完成的Scrapy任务,running代表正在运行的Scrapy任务,pending代表等待被调度的Scrapyd任务,node_name就是主机的名称。

addversion.json

这个接口主要用来部署 Scrapy 项目。在部署的时候,我们首先要将项目打包成 egg 文件,然后传入项目名称和部署版本。

我们可以用如下方式实现项目部署:

curl http://192.168.2.3:6800/addversion.json -F project=<project_name> -F version=v1 -F egg=@<project_name>.egg

这里 -F 即代表添加一个参数,同时我们还需要将项目打包成 egg 文件放到本地。另外,还需要将 <project_name> 替换成真实的项目名称。

这样发出请求之后,我们可以得到类似如下结果:

{"status": "ok", "spiders": 3}

这个结果表明部署成功,并且其中包含的 Spider 的数量为 3。

Spider 的数量视具体的项目为准,不同的项目包含的 Spider 数量可能不同,此处样例为 3。

使用此方法部署可能比较麻烦,后文会介绍更方便的工具来实现项目的部署。

schedule.json

部署完成之后,项目其实就存在于 Scrapyd 之上了,那么怎么来运行这个 Scrapy 项目呢?此时可以借助 schedule.json 这个接口,它负责调度已部署好的 Scrapy 项目。

我们可以用如下方式实现任务调度:

curl http://192.168.2.3:6800/schedule.json -d project=<project_name> -d spider=<spider_name>

这里需要传入两个参数:project 即 Scrapy 项目名称,spider 即 Spider 名称。

返回结果类似如下:

{"status": "ok", "jobid": "6487ec79947edab326d6db28a2d86511e8247444"}

其中 status 代表 Scrapy 项目启动情况,jobid 代表当前正在运行的爬取任务代号。

类似于执行了如下命令:

scrapy crawl <spider_name>

这就相当于 Scrapyd 启动了对应项目的一个 Spider。Spider 是由 Scrapyd 运行的,运行之后就相当于运行了一个任务,其任务标识号就是 jobid,我们可以根据这个 jobid 来查看或操作该 Spider 的运行状态。

cancel.json

这个接口可以用来取消某个爬取任务。如果这个任务是 pending 状态,那么它将会被移除;如果这个任务是 running 状态,那么它将会被终止。

我们可以用下面的命令来取消任务的运行:

curl http://192.168.2.3:6800/cancel.json -d project=<project_name> -d job=6487ec79947edab326d6db28a2d86511e8247444

这里需要传入两个参数:project 即项目名称,job 即爬取任务的代号,其值就是上文所说的 schedule.json 接口返回的 jobid 的内容。

返回结果如下:

{"status": "ok", "prevstate": "running"}

其中 status 代表请求执行情况,prevstate 代表之前的运行状态。

listprojects.json

这个接口用来列出部署到 Scrapyd 服务上的所有项目的描述信息。

我们可以用下面的命令来获取 Scrapyd 服务器上的所有项目描述:

curl http://192.168.2.3:6800/listprojects.json

这里不需要传入任何参数。

返回结果类似如下:

{"status": "ok", "projects": ["project1", "project2"]}

其中 status 代表请求执行情况,projects 是项目名称列表。

listversions.json

这个接口用来获取某个项目的所有版本号。版本号是按顺序排列的,其最后一个条目是最新版本号。

我们可以用如下命令来获取项目的版本号:

curl http://192.168.2.3:6800/listversions.json?project=<project_name>

这里需要用到参数 project,就是项目的名称。

返回结果如下:

{"status": "ok", "versions": ["v1", "v2"]}

其中 status 代表请求执行情况,versions 是版本号列表。

listspiders.json

这个接口用来获取某个项目最新的一个版本的所有 Spider 名称。

我们可以用如下命令来获取项目的 Spider 名称:

这里需要用到参数 project,就是项目的名称。

返回结果类似如下:

{"status": "ok", "spiders": ["spider1"]}

其中 status 代表请求执行情况,spiders 是 Spider 名称列表。

listjobs.json

这个接口用来获取某个项目 当前运行的所有任务详情。

我们可以用如下命令来获取所有任务详情:

curl http://192.168.2.3:6800/listjobs.json?project=project

这里需要用到参数 project,就是项目的名称。

返回结果如下:

{"status": "ok", "pending": [{"id": "78391cc0fcaf11e1b0090800272a6d06", "spider": "spider1"}], "running": [{"id": "422e608f9f28cef127b3d5ef93fe99399", "spider": "spider1", "start_time": "2020-07-12 10:14:03.594664"}], "finished": [{"id": "2f16646cfcaf11e1b0090800272a6d06", "spider": "spider1", "start_time": "2020-07-12 10:14:03.594664", "end_time": "2020-07-12 10:24:03.594664"}]}

其中 status 代表请求执行情况,pending 代表当前正在等待的任务,running 代表当前正在运行的任务,finished 代表已经完成的任务。

delversion.json

这个接口用来删除项目的某个版本。

我们可以用如下命令来删除项目版本:

curl http://192.168.2.3:6800/delversion.json -d project=<project_name> -d version=<version_name>

这里需要用到参数 project,就是项目的名称;还需要用到参数 version,就是项目的版本。

返回结果如下:

{"status": "ok"}

其中 status 代表请求执行情况,这样就代表删除成功了。

delproject.json

这个接口用来删除某个项目。

我们可以用如下命令来删除某个项目:

curl http://192.168.2.3:6800/delproject.json -d project=<project_name>

这里需要用到参数 project,就是项目的名称。

返回结果如下:

{"status": "ok"}

其中 status 代表请求执行情况,这样就代表删除成功了。

以上就是 Scrapyd 所有的接口,我们可以直接请求 HTTP 接口来控制项目的部署、启动、运行等操作。

ScrapydAPI 的使用

以上这些接口用起来可能还不是很方便,没关系,ScrapyAPI 库对这些接口又做了一层封装,使用 pip3 即可安装它:

pip3 install python-scrapyd-api

下面我们来看看 ScrapydAPI 的使用方法,其核心原理和 HTTP 请求方式并无二致,只不过用 Python 封装后使用更加便捷。

我们可以用如下方式建立一个 ScrapydAPI 对象:

from scrapyd_api import ScrapydAPI
scrapyd = ScrapydAPI('http://192.168.2.3:6800')

然后就可以调用它的方法来实现对应接口的操作了,例如部署操作可以使用如下方式:

egg = open('project.egg', 'rb')
scrapyd.add_version('project', 'v1', egg)

这样我们就可以将项目打包为 egg 文件,然后把本地打包的 egg 项目部署到远程 Scrapyd 了。

另外,ScrapydAPI 还实现了所有 Scrapyd 提供的 API 接口,名称都是相同的,参数也是相同的。

例如,我们调用 list_projects 方法即可列出 Scrapyd 中所有已部署的项目:

scrapyd.list_projects()
['project1', 'project2']

另外,其他方法在此不再一一列举了,名称和参数都是相同的,更加详细的操作可以参考其官方文档: http://python-scrapyd-api.readthedocs.io/

总结

本节介绍了 Scrapyd 及 ScrapydAPI 的相关用法,我们可以通过它来部署项目,并通过 HTTP 接口来控制爬虫任务的运行,不过这里有一个不方便的地方,那就是部署过程。首先它需要打包 egg 文件,然后上传,这还是比较烦琐的。在下一节中,我们介绍一个更加方便的工具来完成部署过程。