☰
Scrapyd部署实战:从本地爬虫到线上调度与监控
2026/10/17 9:51:06 网站建设 项目流程

1. Scrapyd 部署是什么,能解决什么问题

1.1 本地跑爬虫和线上跑爬虫,根本是两个世界

先聊个很多人都踩过的场景。你在本地把 Scrapy 爬虫调通了,数据正常入库,日志干净漂亮,觉得万事大吉。然后把代码传到服务器,用scrapy crawl xxx一跑,问题全来了:爬虫跑了一会儿进程挂了没人管,想定时启动没有统一入口,多个爬虫同时跑资源互相抢占,代码更新一次还要手动去服务器上拉代码、重启进程。我之前见过一个同学,线上爬虫挂了三天愣是没发现,等到数据报表对不上才反应过来——这种时候,光靠nohup和crontab硬扛,迟早出事。

Scrapyd 解决的就是这个问题。它是 Scrapy 官方配套的部署与调度服务,可以把爬虫项目打包上传到服务器上,通过它提供的 HTTP 接口来启停爬虫、查看状态、管理版本。换句话讲,Scrapyd 就是给你的爬虫群装了一个"调度总机",部署、运行、监控都在这个统一的入口上完成。

1.2 核心能力拆解:打包、上传、调度三件套

Scrapyd 能做的事,从使用角度可以拆成三个层面:

  • 项目打包:本地执行一条命令,当前爬虫项目会被打成 egg 包,这个包就是项目在服务器上的"版本快照"。
  • 项目上传:打包好的 egg 包会通过 Scrapyd 的 API 上传到服务端,Scrapyd 自动解包、注册版本,替代旧版本。
  • 任务调度:通过/schedule.json接口触发爬虫运行,通过/listjobs.json查询任务执行情况,随时可以取消或重启。

它适合谁来用?在我看来,只要你的爬虫不是跑一次就扔的一次性脚本,而是需要长期维护、持续采集、多任务并行的项目,就应该尽早把 Scrapyd 纳入技术栈。尤其是负责数据采集的工程师,或者自己搭数据系统的独立开发者,早一天用上这玩意儿,早一天摆脱"翻服务器日志查进程"的苦日子。

2. 部署之前的准备工作,一张清单讲透

2.1 环境与版本匹配,别让细节卡住流程

先说环境的硬性要求。Scrapyd 本身是一个 Python 包,安装命令很简单,但有几个版本上的坑需要注意。

我用得比较稳的组合是:Python 3.8 及以上版本、Scrapy 2.x、Scrapyd 1.2.x。如果你用的是 Scrapy 2.5 以上版本,配合 Scrapyd 1.2.0 以上基本没有问题。这里要特别提醒一点,Scrapyd 在 1.2 版本之后更新比较慢,官方文档一直比较简略,很多人初次接触时容易轻视它,实际部署时遇到问题才意识到文档之外还有很多细节。

安装命令如下:

pip install scrapyd scrapyd-client

注意这个scrapyd-client,它就是提供scrapyd-deploy命令的包。当年我刚开始学习的时候,只装了一个scrapyd,然后到处找scrapyd-deploy,后来才明白这两个是分开的。scrapyd是服务端,跑在服务器上;scrapyd-client是客户端工具,跑在你本地开发机上,负责打包和上传。

安装完成后,需要看一下版本是否对齐:

scrapyd version scrapyd-deploy -l

如果scrapyd-deploy提示找不到命令,大概率是 Python 的 Scripts 目录没进 PATH,把 Python 安装目录下的 Scripts 文件夹加到环境变量即可。

2.2 项目结构规范化:Scrapyd 部署的第一道门槛

在部署之前,必须确认你的 Scrapy 项目结构是标准的。什么叫标准?就是通过scrapy startproject创建出来的结构:

myproject/ ├── scrapy.cfg ├── myproject/ │ ├── __init__.py │ ├── items.py │ ├── middlewares.py │ ├── pipelines.py │ ├── settings.py │ └── spiders/ │ ├── __init__.py │ └── myspider.py

scrapy.cfg这个文件是部署配置的核心。默认内容大致如下:

[settings] default = myproject.settings [deploy] url = http://localhost:6800/ project = myproject

注意,[deploy]这个段落在新建项目时并不默认存在,需要手动加。如果你的项目没有这个段落,scrapyd-deploy会直接报错,找不到部署目标。我当时第一次部署时就是卡在这个环节,还以为是代码的问题,折腾了半天才反应过来是配置文件缺了部署信息。

如果只有一个部署目标,配置写在[deploy]下面即可。如果想区分测试环境和生产环境,可以写成[deploy:test]、[deploy:prod]这种带标签的形式,比如:

[deploy:test] url = http://192.168.1.100:6800/ project = myproject [deploy:prod] url = http://your-server-ip:6800/ project = myproject

这样之后就可以用scrapyd-deploy test -p myproject或scrapyd-deploy prod -p myproject区分发布目标。这种方式在项目多、环境多的时候特别好用,推荐养成这个习惯。

3. 本地部署实操全流程

3.1 服务端启动,第一道配置关卡

先说服务端。在你的服务器上安装好scrapyd之后,默认配置下直接运行:

scrapyd

它会监听0.0.0.0:6800端口,并生成一个默认的配置文件。这个配置文件在 Linux 系统上通常位于/etc/scrapyd/scrapyd.conf,在 macOS 上位于scrapyd启动目录下的scrapyd.conf。

默认配置内容大致是:

[scrapyd] eggs_dir = eggs logs_dir = logs items_dir = items jobs_to_keep = 5 dbs_dir = dbs max_proc = 0 max_proc_per_cpu = 4 finished_to_keep = 100 poll_interval = 5.0 bind_address = 0.0.0.0 http_port = 6800 debug = off

几个关键参数我给新手讲一下:

  • max_proc:允许并发运行的进程数,0 表示不限制,按照 CPU 核心数自动决定。对于大多数场景,保持默认即可。
  • max_proc_per_cpu:每个 CPU 核心最多同时运行的进程数,默认 4。如果你的服务器配置一般,建议调低到 2,防止内存被打满。
  • poll_interval:轮询间隔,Scrapyd 检查任务队列的间隔秒数,默认 5 秒。
  • jobs_to_keep:每个项目保留多少个最近完成的 job 记录。
  • finished_to_keep:完成的 job 记录保留数量。

用浏览器访问http://localhost:6800/,如果能看到一个简单的页面,并在页面上列出可用接口,说明服务端已经正常启动。需要注意的是,如果你要让其他机器也能访问,需要确保bind_address是0.0.0.0,同时放行 6800 端口。我在云服务器上部署时,经常遇到服务本身没毛病、但外网访问不了的问题,最后排查下来都是安全组和防火墙规则挡了端口。

3.2 本地打包与部署,scrapyd-deploy 的完整用法

服务端就绪后,回到本地项目目录,执行:

scrapyd-deploy -p myproject

如果你的scrapy.cfg里只有一个 deploy 目标,并且项目名已经写好,可以直接用:

scrapyd-deploy

执行成功后,你会看到这样的输出:

Packing version: 1651234567 Deploying to project "myproject" in http://127.0.0.1:6800/addversion.json Server response (200): {"status": "ok", "spiders": 2, "node_name": "xxx", "project": "myproject", "version": "1651234567"}

这里有几个信息值得关注。version那一串数字是时间戳,Scrapyd 用它来标识不同的部署版本。如果你对版本有自定义需求,可以加--version参数:

scrapyd-deploy -p myproject --version v1.0.0

spiders: 2表示 Scrapyd 识别到了两个爬虫,这个数字可以用来验证你的爬虫包是否被正确解析。如果这里的数字和你预期的爬虫数量对不上,说明项目打包时出问题了,或者爬虫本身有导入错误。

有时你会在输出中看到Deploying failed或者Unhandled Error,这种情况最常见的原因是网络不通,或者服务端的 egg 存储目录权限不对。遇到 500 错误时,先查服务端日志,不要从本地反复试。

3.3 用 API 远程调度爬虫任务

项目部署上去之后,触发爬虫不再需要登录服务器敲命令。通过 HTTP API 就能完成:

curl http://localhost:6800/schedule.json -d project=myproject -d spider=myspider

返回结果:

{"status": "ok", "jobid": "xxxxxxxxx"}

这个jobid就是本次任务的唯一标识,后续查询、取消任务都要用到它。

查询任务状态:

curl http://localhost:6800/listjobs.json?project=myproject

返回数据里包含running、pending、finished三个列表,分别对应运行中、排队中和已完成的任务。我曾遇到过一个任务一直显示pending,开始还以为是调度出了问题,后来发现是因为同时提交的任务太多,超过了max_proc_per_cpu的限制,任务在排队等待。这种时候listjobs.json就能帮你快速判断是排队还是卡死。

取消任务用/cancel.json:

curl http://localhost:6800/cancel.json -d project=myproject -d job=jobid

如果说本地调试阶段你还可以对着终端看日志,那么一旦上了 Scrapyd,日志文件就变成了远程文件。每个任务日志存放在服务器的logs目录下,路径规则是logs/project/spider/jobid.log,用scrapyd-deploy部署后,这些日志的位置由服务端的logs_dir配置决定。

3.4 关于日志查看,很多人忽略的两个细节

第一个细节是日志轮转。长时间运行的爬虫会产生很大的日志文件,Scrapyd 本身不处理日志切割。我的习惯是在服务器上配一个logrotate规则,按天切割,保留最近 7 天,避免磁盘被日志塞满。这个不配的话,爬虫跑一两个月,一个 log 文件动辄几个 GB,排查问题的时候连打开都费劲。

第二个细节是 Scrapy 的日志级别调整。在settings.py里加上:

LOG_LEVEL = "INFO"

并且在LOG_FORMAT中带上时间戳,这样远程日志才有排查价值。如果是 DEBUG 级别,日志量会非常大,而且 Scrapyd 调度下,控制台日志不会被打印,只看文件日志,所以合理的日志级别很关键。

4. 生产环境下的部署进阶方案

4.1 单机多项目部署,资源隔离是重点

很多人以为 Scrapyd 只能部署一个项目,实际上它支持多个项目共存。上传不同项目名的 egg 包即可,互不干扰。不过,多项目共用一台服务器时,最怕的是某个爬虫内存失控,把整台机器拖垮。

我个人的经验是,在配置里根据爬虫的重要程度调整并发参数。比如核心爬虫项目可以单独部署一个 Scrapyd 实例,次要爬虫用另一个实例,这样即使次要任务出问题,也不会影响核心数据采集。开启第二个实例只需要指定不同的端口:

scrapyd -p 6801

同时要准备不同的配置文件,或用环境变量指向不同配置。这种方式初始化成本不高,但隔离效果立竿见影。

4.2 多机扩展:从单机到分布式的迁移路径

当你的采集规模变大,单机已经不够用时,就需要考虑多机部署。Scrapyd 本身没有集群的概念,但可以搭建一个简单的分布式调度体系。

最朴素的做法是:多台服务器各自跑一个 Scrapyd 实例,用同一套scrapy.cfg配置多个 deploy 目标,把代码分别部署到各台机器上。然后,由一个中心调度程序统一调用各机器的/schedule.json接口,按负载情况将任务分发到不同机器。

这个方案不引入额外复杂组件,只用一个管理脚本就能跑通。具体调度策略可以很简单,比如轮询分发,或者根据各机器的listjobs.json结果,把任务分给运行中任务最少的那台。我当时用几个核心指标做判断:当前任务数、服务器负载、任务队列长度。这些都是通过接口实时读取的,实现难度不高,但带来了明显的吞吐提升。

4.3 部署流程自动化,少踩手动操作的坑

开发环境部署一个爬虫项目可能一天会发生好几次。每次敲一遍scrapyd-deploy其实还好,但生产环境频繁手动部署风险很大——一旦部署了包含 bug 的版本,线上爬虫全部挂掉,排查和回滚都要花时间。

我的建议是给部署加上版本管理和回滚能力。每次部署使用有意义的版本号,比如带上 git commit 的短 hash:

scrapyd-deploy -p myproject --version $(git rev-parse --short HEAD)

这样在出问题时,你可以回滚到之前的某个版本。Scrapyd 支持保留多个版本,但只有最新版本会被用于新任务。如果要回滚,重新部署旧版本的代码即可。

完整一点的自动化流程,可以在 CI 里配置两个步骤:先跑语法检查和单元测试,再执行部署命令。别嫌这两个步骤简单,我吃过一次亏,本地代码没问题,但部署到服务器后发现忘了把某个爬虫文件提交到仓库,CI 打包时直接少了一个爬虫。如果部署前有测试环节,这个问题完全可以在发布前发现。

5. 常见问题与排查实录

5.1 部署失败高频问题速查表

我在学习和带团队的过程中,总结了下面这一批高频问题,每一个都是实际踩过的坑:

现象可能原因解决思路
scrapyd-deploy提示找不到命令未安装scrapyd-client或 Scripts 未入 PATH安装scrapyd-client,检查环境变量
部署时连接被拒绝服务端未启动或 6800 端口被防火墙拦截确认服务端运行状态,检查防火墙规则
返回 500,日志中有文件权限错误egg 存储目录不可写给eggs、dbs等目录授权
部署成功但spiders数量为 0项目代码有导入错误,爬虫模块加载失败在本地执行scrapy list验证爬虫能否正常列出
任务一直处于pending状态并发进程数达到上限调整max_proc配置,或减少同时提交的任务数
爬虫运行了但没有任何输出日志输出到文件,终端看不到查看logs目录下的.log文件
部署时版本总是相同时间戳导致覆盖重复执行部署命令使用自定义版本号或加入 git commit hash

这张表我建议保存下来。很多东西在你只部署一两次时根本碰不到,等真正在生产环境出问题时,这些经验能帮你省下大把排查时间。

5.2 一个真实的排查案例:任务卡死的全过程

这里分享一个我印象比较深的案例。一个采集任务在本地跑得好好的,部署到 Scrapyd 后,一开始正常,运行到某个数据页后进程直接卡死。通过listjobs.json查看,任务状态显示running,但日志已经很久没有新输出。

排查过程大概是这样的:先看日志,确认卡住的时间点;然后还原现场,模拟那一段时间的数据请求,发现目标网站在某个特定条件下会长时间不返回响应,而 Scrapy 默认的下载超时是 180 秒,在这期间任务会一直等待,表现为"卡死"。

解决办法是在settings.py里加上:

DOWNLOAD_TIMEOUT = 30

同时开启了自动重试:

RETRY_TIMES = 3

这样,遇到长时间无响应的请求,爬虫会主动放弃并重试,而不是无限期等待。问题解决后,我又顺手在爬虫里加了一个统计中间件,把每个请求的响应时间打到日志里。以后遇到类似问题,不用瞎猜,直接看日志就能定位是哪个域名响应慢。

这个案例让我意识到,用上 Scrapyd 之后,"爬虫本地没问题"这句话就不再值得依赖。调度系统会把你的爬虫扔到各种真实网络环境里跑,超时、反爬、资源竞争这些新问题会不断出现,日志和监控体系必须跟上。

5.3 Scrapyd 的局限与替代方案的思考

Scrapyd 不是万能的。它没有内置可视化管理界面,虽然可以借助第三方工具或者写简单前端来展示任务状态,但和成熟的分布式调度系统相比,功能还是单薄很多。比如它没有定时调度功能,只提供了任务触发的 API。定时任务需要你用cron或外部调度器(比如caddy、systemd timer)去调用/schedule.json接口。此外,对于任务失败后的自动重试和告警,Scrapyd 也不具备,需要自己封装。

如果你只是个人使用或者团队规模比较小,Scrapyd 完全够用,而且它简单、稳定、可控。当业务规模大到需要可视化监控、任务编排和自动伸缩时,再考虑更重型的工作流调度平台也不迟。我的建议是:起步阶段用 Scrapyd,把核心逻辑跑通,积累数据;等到觉得维护成本开始变高的时候,再去迁移到更复杂的系统。用错了工具比没有工具更难受,这个判断标准我一直记着。

6. 部署过程中的几条硬核经验

6.1 版本号策略:时间戳之外的另一种选择

前面提过,Scrapyd 默认用时间戳作为版本号。但当你需要回滚到历史版本时,一堆时间戳根本分不清哪个对应哪次代码变更。我的做法是:在打包部署时,把版本号设为代码仓库的 commit 短 hash,这样每个版本号直接对应当前代码状态。部署后如果需要回溯,listversions.json可以查看所有版本:

curl http://localhost:6800/listversions.json?project=myproject

输出会列出所有已部署的版本号,以及每个版本对应的爬虫数量。这里的spiders计数也可以用来自动化校验部署是否完整。

6.2 scrapy.cfg 与多环境配置的管理技巧

当项目既要在本地开发,又要部署到测试服和生产服时,我一般会把配置抽到环境变量里。比如:

[deploy:prod] url = http://your-server-ip:6800/ project = myproject

但不同的环境可能会有不同的settings.py(比如数据库地址、代理配置),Scrapyd 本身不支持部署时动态切换配置。我的做法是在项目中加一个settings_prod.py,在部署前用环境变量或启动参数指定加载哪个配置。在爬虫启动时通过命令行参数传入:

curl http://localhost:6800/schedule.json -d project=myproject -d spider=myspider -d setting=PROD_SETTINGS

Scrapyd 的/schedule.json支持在参数中传递setting,它会被注入到 Scrapy 的 settings 中。这就意味着不同的任务可以用不同的配置,而不需要重新部署项目。实际操作时,我通常这样写:

curl http://localhost:6800/schedule.json -d project=myproject -d spider=myspider -d setting=DOWNLOAD_DELAY=3.0 -d setting=CONCURRENT_REQUESTS=8

这个功能对于首次调试参数很有用。比如某个爬虫近期被对方站点限流,我不需要改代码重新部署,直接临时调低并发和增加下载延迟,观察效果,确认没问题后再固化到代码里。

6.3 监控与告警:没有监控的调度都是裸奔

部署完 Scrapyd 后,我强烈建议立刻把监控补上,越早越好。最基础的三块:

  • 端口存活监控:定期探测 6800 端口,服务挂掉时第一时间收到通知。
  • 任务失败监控:调用listjobs.json,统计 finished 任务中状态异常的数量,异常时触发告警。
  • 数据量监控:根据业务数据量(比如入库条数)判断爬虫是否正常工作。有时候任务执行成功,但数据条数异常减少,这说明可能有页面结构变更或反爬规则变化,这种问题单看任务状态是发现不了的。

我在实际项目里用的是最朴素的方案:一个定时脚本,每 5 分钟调用一次listjobs.json,把关键指标写进日志,再通过媒体通知推送异常。这个方案的搭建成本非常低,但带来的安全感是实打实的。

想想看,以前排查爬虫问题要登录服务器、翻进程、看日志;现在只需要看监控报表,服务分布、任务状态、成功数量一目了然。这就是 Scrapyd 部署带给我的最大收益——把"靠感觉运维"变成了"看数据运维"。

7. 后续还可以扩展什么

7.1 给 Scrapyd 配一个任务调度器

前面说过,Scrapyd 没有内置定时调度。如果你希望爬虫能按固定时间运行,可以写一个简单的调度脚本,或者用主流的调度工具。核心逻辑都很简单:到点调用/schedule.json触发指定爬虫。我个人比较推荐先从系统自带的方式做起,把调度脚本放在服务器上跑熟,再考虑引入第三方组件。

7.2 结合采集任务编排做工程化

Scrapyd 完成的是"部署 + 调度"这一层,再往上走,一个完整的采集工程还需要:数据校验、失败报警、去重调度、代理池管理等。这些东西未必都需要引入复杂系统,但可以根据业务需要逐步加入。比如,我在跑一些规模化采集任务时,还会把 Scrapyd 的接口封装成一个小的管理 SDK,方便在代码里做任务编排和状态查询。底层的 API 其实已经很稳定,封装只是为了让调用侧的代码更整洁,避免到处写重复的请求逻辑。

说到底,Scrapyd 的部署能力只是开始,真正拉开差距的是你围绕它搭建的整套采集运维体系。

我个人在实际操作中的体会是:先跑通最小闭环,再逐步添砖加瓦,远比一开始就奔着完美架构去设计来得踏实。无论你是第一次部署 Scrapyd,还是已经在生产环境跑了一段时间,把基础概念夯实、把日志和监控体系搭好,再往上叠加任何高级功能都会顺利很多。希望这篇笔记能帮你少走一点弯路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询