Scrapyrt实战指南 - 将爬虫转换为HTTP API服务

📂 所属阶段:第五阶段 — 战力升级(分布式与进阶篇)
🔗 相关章节:Scrapy-Redis分布式架构 · Docker容器化爬虫

你有没有遇到过这种情况:写好了一个完美的 Scrapy 爬虫,却不知道怎么快速丢给后端、前端甚至第三方调用?或者想做一个“输入一个 URL → 返回结构化数据”的实时接口,又不想从零搭建 Flask / django 服务?今天这篇指南,带你用 3 分钟把爬虫变成 HTTP API,轻松搞定所有烦恼!


🎯 Scrapyrt 是什么?

Scrapyrt(Scrapy Real-Time)是 Scrapy 官方维护的轻量级插件。它的魔力在于:你不需要修改任何爬虫代码,就能直接把整个 Scrapy 项目变成一个 RESTful API 服务
它特别适合下面这些场景:

  • 用户触发的“即时按需爬取”(比如用户输入商品链接,实时抓取价格)
  • 微服务架构里的“数据采集组件”(通过 HTTP 调用,与其它服务解耦)
  • API 网关后方的“安全数据接口”(只需暴露一个经过认证的端点)

总结一下,Scrapyrt 有四大核心优势:

  1. 服务化架构:爬虫直接变成可调用的 Web 服务
  2. 无状态、易扩展:每个请求独立,易于横向扩展
  3. JSON 格式通信:前后端都喜欢的交互方式
  4. 与现有 Scrapy 项目完美兼容:不需要改动原来的 settings.pymiddleware

🚀 3 分钟快速启动

第一步:准备环境与项目

确保你的 Python 版本 ≥ 3.6,然后安装 Scrapy 和 Scrapyrt:

pip install scrapy scrapyrt

接着快速创建一个示例 Scrapy 项目,并生成一个基础爬虫:

scrapy startproject demo_spider
cd demo_spider
scrapy genspider example example.com

此时你的目录结构大概是这样:

demo_spider/
├── demo_spider/
│   ├── spiders/
│   │   └── example.py
│   └── settings.py
└── scrapy.cfg

第二步:改造一行代码,让爬虫支持动态 URL

打开 demo_spider/spiders/example.py,把 start_requests 方法改成下面这样(其余保持不变):

import scrapy

class ExampleSpider(scrapy.Spider):
    name = 'example'

    # 核心修改:通过 API 传递的 url 参数动态生成请求
    def start_requests(self):
        # 从属性中获取传入的 url(可以是字符串或列表)
        urls = getattr(self, 'url', None)
        if urls:
            # 统一处理成列表形式,兼容单个 URL 和多个 URL
            urls = [urls] if isinstance(urls, str) else urls
            for url in urls:
                yield scrapy.Request(url, callback=self.parse)

    def parse(self, response):
        yield {
            'url': response.url,
            'title': response.css('title::text').get().strip(),
            'status': response.status
        }

要点解释

  • 我们用 getattr(self, 'url', None) 获取调用方传过来的 url 参数。
  • 如果传的是字符串,就变成列表;如果已经是列表,则直接遍历。
  • 这样就允许一次请求传入多个 URL,非常灵活。

第三步:启动服务

demo_spider 根目录下(就是能看到 scrapy.cfg 的位置),执行:

scrapyrt

默认会监听 0.0.0.0:6023。控制台会输出类似 Starting Scrapyrt 1.2.0 on http://0.0.0.0:6023 的信息,表示服务启动成功。

第四步:验证服务

打开浏览器或终端,输入:

curl "http://localhost:6023/crawl.json?spider_name=example&url=https://httpbin.org/get"

你会立刻收到一个 JSON 响应,其中的 items 字段就包含了爬虫解析出来的数据(网页标题、状态码等)。就这么简单,一个实时爬虫 API 就跑起来了!


🔌 核心 API 详解

Scrapyrt 主要提供了两个核心端点,可以覆盖绝大多数使用场景。

1. /crawl.json —— 同步爬取(最常用)

请求方式GET
适用场景:小数据量、短时间的爬取任务(比如单个页面、轻量级列表)

参数名作用是否必填
spider_name爬虫名字(对应 name 属性)
url要爬取的 URL
max_requests最大请求数,可以限制爬取深度或广度
crawl_args传给爬虫的额外参数,应为 JSON 字符串

示例

curl "http://localhost:6023/crawl.json?spider_name=example&url=https://httpbin.org/get&max_requests=3"

如果想传多个 URL,可以在 url 参数中传入 & 分隔的多个值(实际行为取决于你的爬虫如何处理 url 列表),但更推荐使用 crawl_args 传递 JSON 列表:

curl "http://localhost:6023/crawl.json?spider_name=example&crawl_args=%7B%22url%22%3A%5B%22https://httpbin.org/get%22%2C%22https://httpbin.org/headers%22%5D%7D"

(其中 %7B%22url%22%3A%5B...{"url":["...","..."]} 的 URL 编码,你也可以用 Python 或 Postman 直接构造)

2. /crawl.json/request —— 自定义 Request(POST)

请求方式POST
适用场景:需要自定义 Headers、Cookies、Request Meta 等的复杂请求

请求体示例

curl -X POST http://localhost:6023/crawl.json/request \
  -H "Content-Type: application/json" \
  -d '{
    "spider_name": "example",
    "request": {
      "url": "https://httpbin.org/headers",
      "headers": {
        "User-Agent": "Custom Spider 1.0"
      },
      "meta": {
        "custom_key": "custom_value"
      }
    }
  }'

这种方式让你几乎完全控制 Scrapy 的 Request 对象,包括 cookiesmethod 等,非常灵活。


🐍 Python 极简客户端

如果你不想每次都手写 curl,可以封装一个几行代码的 Python 客户端,方便在其它项目中调用:

import requests

class ScrapyrtClient:
    def __init__(self, base_url="http://localhost:6023"):
        self.base_url = base_url.rstrip('/')

    def crawl(self, spider_name, url, **kwargs):
        params = {"spider_name": spider_name, "url": url}
        params.update(kwargs)  # 支持 max_requests、crawl_args 等
        resp = requests.get(f"{self.base_url}/crawl.json", params=params, timeout=300)
        resp.raise_for_status()
        return resp.json()

# 使用示例
client = ScrapyrtClient()
result = client.crawl("example", "https://httpbin.org/get")
print(result['items'][0]['title'])

同时,你也可以基于这个客户端封装异步调用、错误重试等逻辑,很适合集成到你的后端服务里。


🔒 快速安全加固(生产必备)

直接裸奔上生产?绝对不行!这里给出三个最实用的安全措施。

1. Nginx 反向代理 + HTTPS

让 Scrapyrt 只监听内网地址,前面放一个 Nginx 处理 HTTPS、认证和限流。

简单配置示例/etc/nginx/conf.d/scrapyrt.conf):

server {
    listen 443 ssl;
    server_name your-domain.com;

    ssl_certificate /path/to/fullchain.pem;
    ssl_certificate_key /path/to/privkey.pem;

    location / {
        # 只允许信任的 IP 访问(比如公司办公网、API 网关)
        allow 123.45.67.89;
        deny all;

        proxy_pass http://127.0.0.1:6023;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

2. 添加简单的 API Key 验证

可以通过 Nginx 的 auth_request 模块配合一个认证服务来做,或者在 Scrapyrt 前加一个简单的 Flask 代理,验证 Authorization 头。这里不展开完整实现,但是思路一定要有。

3. 限流防滥用

在 Nginx 里加上速率限制,避免单一客户端疯狂调用:

limit_req_zone $binary_remote_addr zone=scrapyrt:10m rate=5r/s;

server {
    ...
    location / {
        limit_req zone=scrapyrt burst=10 nodelay;
        proxy_pass http://127.0.0.1:6023;
    }
}

有了这三板斧,你的 API 服务就安全多了。


🐳 Docker 一键部署

容器化部署可以让环境一致,也方便横向扩展。我准备了一个简单的 Dockerfile,你可以直接使用:

FROM python:3.9-slim

WORKDIR /app

# 安装编译依赖(有些 lxml 等库需要)
RUN apt-get update && apt-get install -y --no-install-recommends \
    gcc libxml2-dev libxslt1-dev && \
    rm -rf /var/lib/apt/lists/*

# 复制依赖文件并安装
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 安装 Scrapyrt
RUN pip install scrapyrt

# 复制整个项目
COPY . .

EXPOSE 6023

# 健康检查:每 30 秒访问一次根路径
HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
    CMD curl -f http://localhost:6023/ || exit 1

CMD ["scrapyrt", "-p", "6023", "-i", "/app"]

其中 requirements.txt 里包含 Scrapy 等依赖,例如:

Scrapy>=2.11

然后构建并运行:

docker build -t scrapyrt-demo .
docker run -d -p 6023:6023 --name scrapyrt-container scrapyrt-demo

现在你就可以在宿主机上通过 http://localhost:6023 访问到容器内的爬虫服务了。如果想在 Compose 中与其他服务联动,也只需要几行配置。


❌ 高频问题排查

在实际使用中,你可能会遇到这几个坑,别慌,解决方案都在这里。

1. 端口被占用

# 查看谁占用了端口
lsof -i :6023
# 或者换一个端口启动
scrapyrt -p 6024

2. 爬虫超时

有些网站响应慢,或者爬虫逻辑较复杂,默认超时时间可能不够。可以通过启动参数和 Scrapy 设置共同调整:

# 启动时增加整体任务超时(秒)
scrapyrt -p 6023 --timeout 600

同时,在项目的 settings.py 中增加下载超时:

DOWNLOAD_TIMEOUT = 120   # 单个请求最多等 120 秒

3. 返回数据太大

如果爬虫抓取了太多页面,可能会撑爆内存或响应时间过长。可以在 API 参数里限制总请求数:

curl "http://localhost:6023/crawl.json?spider_name=example&url=xxx&max_requests=5"

或者在 Scrapy 设置里限制并发和深度:

CONCURRENT_REQUESTS = 8
DEPTH_LIMIT = 2

💡 核心最佳实践

最后,送你五条“压箱底”的建议,帮你把 Scrapyrt 用得又稳又好:

  1. 容器化部署:用 Docker 隔离环境,方便一键部署和快速扩容。
  2. Nginx 反向代理:统一加 HTTPS、IP 白名单、速率限制,把安全做在前头。
  3. 限制资源:每个 API 调用最好都设置 max_requests,同时在 Scrapyrt 启动时通过 --max-concurrent-requests 控制全局并发。
  4. 日志管理:如果你用 Docker,可使用 json-filesyslog 驱动;如果是裸机部署,记得配置 logrotate,别让日志撑爆磁盘。
  5. 健康检查:在 Dockerfile 或 Compose 中加上健康检查,配合编排工具自动重启异常服务,提升可用性。

🏷️ 标签云Scrapyrt HTTP API 实时爬虫 微服务 按需爬取 Docker部署