工程化网页爬虫(Crawlee):把采集脚本改造成可靠流水线

前言

写采集脚本最常见的两种结局:一种是跑一次就结束,没有断点续跑、没有重试、没有队列,第二天要重来;另一种是写得很快,跑起来之后被站点风控拦在门外,或者并发一上去就大量 429 / 连接重置,最后数据缺一半。

问题不在「能不能抓到」,而在「能不能稳定跑完」。这个 Skill 给出的是基于 Crawlee 的一套工程化方法论,把请求路由、反封禁、数据存储、浏览器自动化这些事拆成明确的处理环节,目标是在 Node.js / Python 里产出「跑得稳、拿得全」的采集流水线,而不是随手写的脚本。

这是什么

一句话定位:这是一个把 Crawlee 的工程实践整理成可调用方法论的 Skill,用于生成可靠的网页采集流水线。

  • 出品方:昆仑增长(@kunlungrowth)
  • 版本:1.0.0
  • 来源:enterprise
  • 分类:dev-programming
  • 标签:requires_api_key=false,即不依赖外部 API Key
  • SkillHub 页面显示:评分 100000,下载 1308,安装 0
  • 官方地址:https://www.skillhub.cn/skills/kunlungrowth/python-node-web-crawler

它解决的问题在于:Crawlee 本身是一个功能较全的采集框架,能力分散在多个配置项和多种 Crawler 类型里,第一次用的人很容易只写出「一个默认 handler 从头跑到尾」的代码,漏掉路由分层、存储落盘和浏览器池管理。这个 Skill 把这些决策点显式化。

核心能力

下面列出的能力来自该 Skill 的公开简介,逐条对应 Crawlee 中的具体机制。

请求路由。 用 router 把不同类型的请求分发到不同的处理逻辑,而不是把所有逻辑堆在一个默认 handler 里。对应 Crawlee 的 crawler.router 与 default_handler 装饰器。

反封禁。 控制请求节奏、浏览器指纹与请求头一致性,使爬虫行为接近真实用户。Crawlee 在默认配置下就提供了一套指纹与请求头生成机制,包括 BrowserforgeFingerprintGenerator、BrowserforgeHeaderGenerator。

数据存储。 采集结果统一落盘到 Dataset / 存储目录,不靠内存里的 list 攒数据。对应 Dataset、push_data,以及运行后在当前工作目录生成的 storage/ 目录。

浏览器自动化。 需要执行客户端 JavaScript 的场景走 PlaywrightCrawler,纯 HTML 场景走 BeautifulSoupCrawler,两者可按页面类型混用。

自动扩缩容与重试。 由 AutoscaledPool 控制并发,失败请求按策略重试,这是「跑得稳」的主要来源。

安装与启用

这个 Skill 的安装入口在 SkillHub。它在 SkillHub 页面上的坐标是 @kunlungrowth/python-node-web-crawler,页面当前显示安装数为 0,公开资料中没有给出 Cursor / Codex CLI / Claude Code 各自的专属安装命令,因此这里不猜测命令格式。

启用 Skill 之后,它所依托的 Crawlee 库仍需要装依赖。以下是 Crawlee 官方文档中已核实的安装命令。

Python 侧,装全量特性并补齐浏览器依赖:

python -m pip install 'crawlee[all]'
playwright install

验证安装是否成功:

python -c 'import crawlee; print(crawlee.__version__)'

Python 侧要求 3.10 及以上。

如果希望直接起一个项目骨架,可以用 Crawlee CLI 加模板:

uvx 'crawlee[cli]' create my-crawler

已经装了 crawlee 的话,直接跑:

crawlee create my-crawler

Node.js / TypeScript 侧对应的是 Apify 的 Crawlee for JS/TS 实现,仓库地址 https://github.com/apify/crawlee 。Skill 简介里提到的 Node.js 支持即来自这一实现。

典型用法

以 Python 为例。下面的示例来自 Crawlee 官方文档,演示了一个最小可用的采集流程:注册默认请求处理器、提取数据、落盘、继续发现链接。

用 BeautifulSoupCrawler 处理静态 HTML:

import asyncio

from crawlee.crawlers import BeautifulSoupCrawler, BeautifulSoupCrawlingContext


async def main() -> None:
    crawler = BeautifulSoupCrawler(
        # Limit the crawl to max requests. Remove or increase it for crawling all links.
        max_requests_per_crawl=10,
    )

    # Define the default request handler, which will be called for every request.
    @crawler.router.default_handler
    async def request_handler(context: BeautifulSoupCrawlingContext) -> None:
        context.log.info(f'Processing {context.request.url} ...')

        # Extract data from the page.
        data = {
            'url': context.request.url,
            'title': context.soup.title.string if context.soup.title else None,
        }

        # Push the extracted data to the default dataset.
        await context.push_data(data)

        # Enqueue all links found on the page.
        await context.enqueue_links()

    # Run the crawler with the initial list of URLs.
    await crawler.run(['https://crawlee.dev'])


if __name__ == '__main__':
    asyncio.run(main())

如果页面内容依赖客户端 JavaScript 渲染,换成 PlaywrightCrawler,处理逻辑的写法保持一致:

import asyncio

from crawlee.crawlers import PlaywrightCrawler, PlaywrightCrawlingContext


async def main() -> None:
    crawler = PlaywrightCrawler(
        max_requests_per_crawl=10,
    )

    @crawler.router.default_handler
    async def request_handler(context: PlaywrightCrawlingContext) -> None:
        context.log.info(f'Processing {context.request.url} ...')

        data = {
            'url': context.request.url,
        }

        await context.push_data(data)
        await context.enqueue_links()

    await crawler.run(['https://crawlee.dev'])


if __name__ == '__main__':
    asyncio.run(main())

两次运行都会在当前工作目录下创建 storage/ 目录存放数据。跑之前记得先执行 playwright install,否则 PlaywrightCrawler 会因浏览器依赖缺失而启动失败。

适用场景与注意

适合的场景:需要长时间运行、对完整性有要求的采集任务,例如站群数据归档、周期性商品与资讯采集、多站点聚合。这类任务的共同点是「跑不完要接着跑」,所以请求队列、断点续跑和结构化存储是硬需求。

需要注意的几点:

1、max_requests_per_crawl 只是示例里的调试上限,生产使用要去掉或调到实际需要的规模,否则采集会在 10 个请求后停止。
2、静态页面优先用 BeautifulSoupCrawler,性能明显好于浏览器方案;只有确实需要执行客户端 JS 时才上 PlaywrightCrawler,浏览器池的内存开销要提前评估。
3、请求路由建议按站点或页面类型拆 handler,不要把所有站点塞进一个默认 handler,否则后续调整某一类站点时会影响全局。
4、反封禁不是免死金牌。默认指纹和请求头配置只能降低被识别的概率,遇到严格的风控仍需配合代理与速率策略,Skill 公开资料中未给出具体代理配置方案。
5、该 Skill 不依赖 API Key,但 Crawlee 官方文档、Python 包、Playwright 浏览器依赖本身都要从外部拉取,内网环境需要先处理镜像源。

小结

这个 Skill 的价值在于把「采集脚本」和「采集流水线」之间的工程决策显式化:路由怎么分、请求节奏怎么控、数据往哪存、什么时候用浏览器。配合 Crawlee 的安装命令和模板,可以在 Python 或 Node.js 里较快搭起一条能长期跑的采集流程。

官方地址:https://www.skillhub.cn/skills/kunlungrowth/python-node-web-crawler

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

Xiaoye