🐸 青蛙编程网
首页 / Python / 爬虫 / 7. Crawlee

7. Crawlee

这是什么:Crawlee 是商业化爬虫平台 Apify 团队开源的爬虫框架(Node.js 版久经沙场,Python 版已稳定)。它的核心是一套异步爬虫基础设施:请求队列、去重、自动限速、失败重试、代理轮换、数据集存储全部内置——而且从 HTTP 爬虫升级到浏览器渲染爬虫只换一个类名。

为什么学它:前两个框架解决「爬得快、爬得多」,Crawlee 解决「爬得现代」:全异步架构天然高并发;HTTP 爬不动 JS 页面时,把 BeautifulSoupCrawler 换成 PlaywrightCrawler,解析代码一行不改。需要混合采集(一部分接口、一部分渲染页)的项目用它最顺。

如何用:装包 → 写第一个异步爬虫 → 理解请求队列与数据集 → 见识一键切换浏览器渲染。

装包

pip install "crawlee[beautifulsoup]"

第一个异步爬虫

Python 版 Crawlee 基于 asyncio(异步编程,函数用 async def、调用用 await)。存成 crawlee_demo.py 运行:

import asyncio

from crawlee.beautifulsoup_crawler import BeautifulSoupCrawler, BeautifulSoupCrawlingContext


async def main():
    crawler = BeautifulSoupCrawler(max_requests_per_crawl=10)   # 最多抓 10 个请求


    @crawler.router.default_handler                             # 每个页面进来都走这里
    async def request_handler(context: BeautifulSoupCrawlingContext):
        context.log.info(f"正在抓取 {context.request.url}")
        soup = await context.parse()                            # 解析成 BeautifulSoup 对象


        for quote in soup.select("div.quote"):
            await context.push_data({                           # 数据存进数据集
                "text": quote.select_one("span.text").get_text(strip=True),
                "author": quote.select_one("small.author").get_text(strip=True),
            })


        await context.enqueue_links()                           # 页面上的链接自动入队


    await crawler.run(["https://quotes.toscrape.com/"])


asyncio.run(main())

你会看到:日志逐条打出 INFO 正在抓取 …,程序结束后项目目录多出一个 storage/ 文件夹——数据在里面(下一节讲)。

三个关键调用记牢:

调用 作用 对应手写爬虫的
context.parse() 拿到 BeautifulSoup 对象 第 3 章的解析
context.push_data({...}) 数据写入内置数据集 第 4 章的存储
context.enqueue_links() 页面所有链接自动进请求队列 第 4 章的队列 + 去重 + urljoin

你没写的东西:队列管理、URL 去重、相对地址拼接、限速、重试——Crawlee 的请求队列(默认本地文件存储)全包了。

数据去了哪:storage 目录

运行后在项目目录找到 storage/datasets/default/,里面每个结果一个文件,像这样:

{ "text": "\u201cThe world as we have created it\u2026\u201d", "author": "Albert Einstein" }

想一次拿全?再写几行把数据集导出:

    dataset = await context.get_dataset()          # 在 handler 里拿
    print(await dataset.get_data())                # {"items": [...], ...}

也可以用 Crawlee 自带 CLI:pip install "crawlee[cli]" 后运行 crawlee run ...,或直接读 storage/ 里的 JSON。注意:storage/ 会缓存上次的请求队列和数据,改了代码想从头跑,先删掉整个 storage 目录。

换一个类:从 HTTP 爬虫到浏览器渲染

遇到 JS 渲染的页面(第 1 章的动态形态),HTTP 请求拿到的是空壳——换 PlaywrightCrawler,用真浏览器跑完 JS 再解析:

pip install "crawlee[playwright]"
playwright install chromium        # 下载浏览器内核,一次性
from crawlee.playwright_crawler import PlaywrightCrawler, PlaywrightCrawlingContext

crawler = PlaywrightCrawler(max_requests_per_crawl=10)      # 只换这一行
# handler 里同样 context.parse() 拿 BeautifulSoup、push_data、enqueue_links

解析代码完全不变——这就是 Crawlee 的设计哲学:HTTP 和浏览器只是「取页面的方式」,业务逻辑只有一份。(对 JS 渲染想深入,是进阶话题,本教程点到为止。)

三大框架怎么选

维度 Scrapy(第 5 章) feapder(第 6 章) Crawlee(本章)
架构 twisted 异步 多线程 asyncio 异步
分布式 加装 scrapy-redis 拼装 内置(上 Redis 即用) 平台化(配 Apify/代理池)
JS 渲染 加装 scrapy-playwright 需自行集成 换类名即可
数据导出 命令行一键导出 Item 管道入库 push_data 数据集
上手难度 中(项目结构多) 低(像普通脚本) 低(但需要懂 asyncio)
适合场景 大规模站群采集 国内业务型、分布式 混合采集、要渲染的现代站点

选型没有标准答案:规模优先选 Scrapy/feapder,现代站点和渲染优先选 Crawlee——三个都写过一遍,你就有了「看菜下单」的能力,这正是本栈的目的。

常见翻车现场

症状 原因 修复
ImportError: cannot import ... Crawlee 版本迭代快,import 路径变过 以官方文档为准,重看该版本 API
程序没反应直接退出 忘了 asyncio.run(main()) async 的 main 必须由它启动
抓的是旧数据/没抓新页面 storage/ 缓存了上次队列 删掉 storage 目录重跑
抓太多停不下来 链接一直有新链接(日历类站点) max_requests_per_crawl 限总量
Playwright 报浏览器未装 只装了包没装内核 playwright install chromium

动手改

  1. 把 max_requests_per_crawl 从 10 改成 20,观察它爬到第 2 页后自动停住
  2. 给 push_data 增加 tags 字段(提示:quote.select("a.tag") 循环取文本)
  3. 用 enqueue_links(include=[r"/page/"]) 只入队翻页链接,对比抓取范围变化

上一章:feapder · 下一章:综合练习 🐸

📥 下载本章代码

ZIP 内含本章全部代码文件与说明,解压即用,与教程内容同步生成。