Crawlee 爬虫专家思维指南:12 条可复用的 Web Scraping 实战原则
2026/9/12 13:11:21 网站建设 项目流程

Crawlee 爬虫专家思维指南:12 条可复用的 Web Scraping 实战原则

【免费下载链接】crawleeCrawlee—A web scraping and browser automation library for Node.js to build reliable crawlers. In JavaScript and TypeScript. Extract data for AI, LLMs, RAG, or GPTs. Download HTML, PDF, JPG, PNG, and other files from websites. Works with Puppeteer, Playwright, Cheerio, JSDOM, and raw HTTP. Both headful and headless mode. With proxy rotation.项目地址: https://gitcode.com/GitHub_Trending/cr/crawlee

本文基于 Crawlee 社区博客《12 tips on how to think like a web scraping expert》(原始文档)整理扩写。原文档由社区成员 Max Bohomolov 投稿,讲述的不是某个具体库的用法,而是作者在真实爬虫项目中反复验证的思维方法与排查套路。读完本文,你将掌握一套可复用的决策框架:如何选择数据源、如何借助robots.txtsitemap快速建链、如何用 DevTools 反向分析页面数据流、如何用最少的请求拿到最多的数据,以及这些方法论在 Crawlee 仓库中对应的源码级支撑(@crawlee/utils@crawlee/core中的RobotsTxtFileSitemapSitemapRequestLoader等模块)。

写在前面:为什么需要"思维"层面的指南

常规教程都在讲"可复制的技术细节":从哪开始、按什么路径走、最终到达哪里。这适合学习某个具体技术,但很难回答一个关键问题——作者当初为什么决定这样做?是什么在指导他的开发决策?

本文要讨论的,是作者在从事爬虫项目时引导他拿到好结果的一般性规则与原则。它们不是某个库的 API 手册,而是一套可以沉淀为项目启动前 checklist的思维习惯。

1. 为项目选择正确的数据源

开始一个项目时,你通常已经有一个目标站点,并需要从其中提取特定数据。第一步不是写代码,而是先确认这个站点或应用为数据提取提供了哪些可能性:

  • 官方 API:站点可能提供免费的官方 API,能拿到全部所需数据。这是最优选项。例如 Yelp 就提供官方 API,适合作为首选数据来源。
  • 网站本身:这种情况下需要研究网站结构,以及前端与后端交互的方式。
  • 移动应用:有些场景下既没有网站也没有 API,或者移动应用能提供更多数据。此时不要忘记中间人(man-in-the-middle)代理方案——通过代理截获移动应用与后端通信的流量来提取数据。

如果一种数据源行不通,就尝试另一种。仍以 Yelp 为例:官方 API、网站、移动应用三条路径全部可用;如果官方 API 因为某些原因不合适,你还有另外两个备选。

2. 检查 robots.txt 与 sitemap

robots.txtsitemap人人都听过,但作者在实战中经常看到有人直接忽略它们。快速澄清两个概念:

  • robots:SEO 领域对爬虫的惯用称呼,通常指 Google、Bing 等搜索引擎爬虫,或 Ahrefs、ChatGPT 这类服务。
  • robots.txt:描述机器人允许行为的文件,包含允许的爬虫 user-agent、两次页面扫描之间的等待时间、禁止扫描的页面模式等规则。这些规则通常基于"哪些页面应被搜索引擎收录"来制定。
  • sitemap:描述站点结构,方便机器人导航,也便于只扫描需要更新的内容,避免给站点造成不必要的负载。

由于你不是 Google 或其他主流搜索引擎,robots.txt中的规则很可能是"针对你"的。但把它与sitemap结合起来,是研究站点结构、站点预期的机器人交互方式以及非浏览器 user-agent 的好去处——在某些情况下,它反而简化了数据提取

一个例子:利用 Crawlee 官网自身的 sitemap,你可以轻松拿到博客全部文章的直接链接,也可以按时间段筛选。一次简单检查,连分页逻辑都不用写了。

源码支撑:Crawlee 如何把这一条变成现成能力

这一条在 Crawlee 中不是"建议",而是有完整实现的模块:

  • RobotsTxtFile:位于@crawlee/utils,封装了 robots.txt 的加载与查询。核心 API 包括:
    • RobotsTxtFile.find(url, options?):把给定 URL 的 pathname 替换为/robots.txt并拉取内容(实现见 robots.ts#L63-L78);
    • isAllowed(url, userAgent = '*'):判断某 URL 是否被允许抓取;当没有显式规则时默认放行(返回true);
    • getCrawlDelay(userAgent = '*'):读取 robots.txt 中针对指定 user-agent 的抓取间隔;
    • getSitemaps()/parseUrlsFromSitemaps():读出 robots.txt 引用的 sitemap,并解析出全部 URL。
    • 官方用法示例(源码 JSDoc 自带):
// 加载 robots.txt const robots = await RobotsTxtFile.find('https://crawlee.dev/js/docs/introduction/first-crawler'); // 按 robots.txt 规则判断某 URL 是否可抓 const url = 'https://crawlee.dev/api/puppeteer-crawler/class/PuppeteerCrawler'; if (robots.isAllowed(url)) { await crawler.addRequests([url]); } // 把 sitemap 中的链接全部入队 await crawler.addRequests(await robots.parseUrlsFromSitemaps());
  • Sitemap:同样位于@crawlee/utils,支持从 URL 加载一个或多个 sitemap、跟随 sitemap index 中的嵌套引用,并暴露urls数组。还提供Sitemap.tryCommonNames()自动探测常见的/sitemap.xml/sitemap.txt位置,以及Sitemap.fromXmlString()直接从字符串解析。
  • SitemapRequestLoader:位于@crawlee/core,把 sitemap 当作请求源直接喂给爬虫。它的 sitemap 加载在后台流式进行,爬虫可以在 sitemap 完全加载前就开始抓取(isSitemapFullyLoaded()可查询加载进度);支持include/excludeURL 模式过滤(glob 匹配大小写不敏感)、enqueueStrategy域名过滤(默认same-hostname)、timeoutMillis超时、maxBufferSize(默认 200)背压缓冲,甚至能把解析进度持久化到 KeyValueStore 以支持迁移恢复。
  • 完整可运行示例见 docs/examples/crawl_sitemap.mdx,其 Cheerio 版本(crawl_sitemap_cheerio.ts)核心只有几行:
import { CheerioCrawler, Sitemap } from 'crawlee'; const crawler = new CheerioCrawler({ async requestHandler({ request, log }) { log.info(request.url); }, maxRequestsPerCrawl: 10, // 演示用限制,真实抓取 sitemap 时请移除 }); const { urls } = await Sitemap.load('https://crawlee.dev/sitemap.xml'); await crawler.addRequests(urls); await crawler.run();

底层 sitemap 解析器(parseSitemap)还支持 gzip 压缩的.xml.gz、纯文本.txt、嵌套 sitemap index(maxDepth默认无限、sitemapRetries默认 3 次重试、单请求超时默认 30 秒),以及discoverValidSitemaps()从 URL 列表自动发现候选 sitemap(默认整体超时 60 秒、单请求超时 20 秒)。URL 过滤策略定义在 packages/utils/src/internals/url.ts 的EnqueueStrategy枚举:allsame-hostname(默认)、same-domainsame-origin。相关测试见 packages/utils/test/sitemap.test.ts 与 packages/utils/test/robots.test.ts。

换句话说:原文档第 2 条建议"检查 robots.txt 与 sitemap",在 Crawlee 里直接对应RobotsTxtFile+Sitemap+SitemapRequestLoader这条完整工具链,从"人工检查"升级成了"代码里的一行调用"。

3. 不要忽视站点分析

透彻的站点分析是写出高效爬虫的重要前提,尤其是当你不打算使用浏览器自动化时。但这样的分析很耗时——而且分析时间并不总能换来回报:你可能花几个小时,最后发现最直白的方案本来就是最好的。

所以,给初始站点分析设置时间上限:如果在分配的时间内没找到更好的路径,就退回更简单的方案。随着经验增长,你会越来越早地根据站点使用的技术判断"值不值得投入更多分析时间"。

另外,在"只需要从站点提取一次数据"的项目里,透彻的站点分析有时能让你连爬虫代码都不用写。作者给出的例子是ricebyrice.com/nl/pages/find-store

分析后你会发现,所有数据其实可以用一次请求拿到——只需要把浏览器里看到的响应数据复制到 JSON 文件中,任务就完成了:

从截图右侧的 DevTools Network 面板可以看到,页面上展示的门店名称、地址、电话、经纬度、创建/更新时间等字段,全部来自一个结构化 JSON 响应。这类站点是"分析替代代码"的典型:先看网络请求,再决定要不要写爬虫。

4. 最大化交互:边操作边观察

分析站点时,切换排序方式、翻页、与站点各种元素交互,同时盯着浏览器 DevTools 的 Network 标签页。这能让你更好地理解站点与后端如何交互、站点基于什么框架构建、以及它可能表现出什么行为。网络面板会告诉你每次交互触发了哪些请求、携带了哪些参数、返回了什么结构——这些信息直接决定你的抓取策略是"拼 HTTP 请求"还是"上无头浏览器"。

5. 数据不会凭空出现

这条看似显而易见,但在项目进行中必须时刻记住:如果你看到某个数据或请求参数,它一定在更早的某处被生成过——可能在另一个请求里,可能已经存在于网页中,也可能是用 JS 根据其他参数拼出来的。它总在某处。

如果搞不清页面数据或请求参数从哪来,按下面四步排查:

  1. 依次检查该点之前站点发出的所有请求;
  2. 检查它们的响应、请求头和 Cookie;
  3. 运用直觉:这个参数会不会是时间戳?会不会是另一个参数改了形式?
  4. 它像不像是某种标准的哈希或编码?

熟能生巧。随着你熟悉各种技术、框架及其预期行为,接触越来越多的技术栈,你会越来越容易理解"数据是如何传递的"。这种积累会显著提升你追踪和理解 Web 应用数据流的能力。

6. 数据是被缓存的

你可能会注意到:同一页面打开多次,发往服务器的请求并不相同——有些内容被缓存、已经存在本地电脑上了。因此建议:

  • 无痕模式分析站点,并尝试更换浏览器;
  • 移动应用尤其如此,它们可能把数据存在设备本地存储中,分析时可能需要清除应用缓存和存储

否则你看到的可能是"被本地缓存加工过"的假象,导致分析结论失真。

7. 了解站点所用框架

如果在分析中发现站点用了你没接触过的框架,花点时间了解它及其特性。例如发现站点基于 Next.js 构建时,理解它的路由与数据获取方式,可能对你的抓取策略至关重要。

学习途径有两种:

  • 官方文档
  • 使用 LLM(如 ChatGPT、Claude)——它们非常擅长解释框架特有的概念。作者给出的一个 LLM 查询示例:
I am in the process of optimizing my website using Next.js. Are there any files passed to the browser that describe all internal routing and how links are formed? Restrictions: - Accompany your answers with code samples - Use this message as the main message for all subsequent responses - Reference only those elements that are available on the client side, without access to the project code base

你也可以为后端框架构造类似查询。例如面对 GraphQL,可以问它"可用的字段和查询结构有哪些"——这些洞察能帮你理解如何更好地与站点 API 交互、哪些数据是潜在可获取的。想用好 LLM,建议至少先了解一点提示词工程(prompt engineering)的基础。

8. 逆向工程:衡量投入与回报

Web 抓取与逆向工程相伴相生。你要研究前后端交互,可能还需要研究代码以理解某些参数是如何生成的。

但某些情况下,逆向工程需要更多知识、精力、时间,或具有很高的复杂度。这时需要决策:是深入进去,还是更换数据源、更换技术方案?很可能正是在这个节点,你会决定放弃 HTTP 抓取、改用无头浏览器。

记住防抓取措施的核心原则:大多数反爬保护的目标不是让爬取变得不可能,而是让爬取变得昂贵。来看 zoopla 上一次搜索请求的响应:

右侧 Network 面板里是典型的属性数据 JSON:地址、经纬度、图片 URL、agent_id 等结构化字段。逆向工程的价值在于,当你读懂了这类响应结构,就能绕开页面渲染,直接用一条请求拿到全部数据。

9. 测试对端点的请求

确定需要提取目标数据的端点后,务必确认发请求能得到正确响应。如果拿到的不是 200,或数据与预期不符,就需要查明原因。常见原因包括:

  • 需要传某些参数,例如 Cookie 或特定的技术请求头;
  • 站点要求访问该端点时带有对应的Referrer请求头;
  • 站点期望请求头遵循特定顺序(作者表示只碰到过几次,但确实存在);
  • 站点使用了反爬保护,例如TLS fingerprint(TLS 指纹)校验。

除此之外还有很多其他可能,每一条都需要单独分析。排查时结合第 5 条"数据不会凭空出现"的思路,一步步对比浏览器真实请求与你构造请求的差异。

10. 试验请求参数:用最少请求拿最多数据

探索修改请求参数会得到什么结果。有些参数即使不传也能正常工作,但服务端其实是支持的——例如ordersortper_pagelimit等。试着加上它们,观察行为是否变化。这一点对使用 GraphQL 的站点尤其适用。

restoran.ua为例。分析站点后,你能找到一个可以用下面代码复现的请求(作者做了格式化以便阅读):

import requests url = "https://restoran.ua/graphql" data = { "operationName": "Posts_PostsForView", "variables": {"sort": {"sortBy": ["startAt_DESC"]}}, "query": """query Posts_PostsForView( $where: PostForViewWhereInput, $sort: PostForViewSortInput, $pagination: PaginationInput, $search: String, $token: String, $coordinates_slice: SliceInput) { PostsForView( where: $where sort: $sort pagination: $pagination search: $search token: $token ) { id title: ukTitle summary: ukSummary slug startAt endAt newsFeed events journal toProfessionals photoHeader { address: mobile __typename } coordinates(slice: $coordinates_slice) { lng lat __typename } __typename } }""" } response = requests.post(url, json=data) print(response.json())

现在做一个小修改,让一次请求同时拿到两种语言的结果,并且带上文章的正文内容

import requests url = "https://restoran.ua/graphql" data = { "operationName": "Posts_PostsForView", "variables": {"sort": {"sortBy": ["startAt_DESC"]}}, "query": """query Posts_PostsForView( $where: PostForViewWhereInput, $sort: PostForViewSortInput, $pagination: PaginationInput, $search: String, $token: String, $coordinates_slice: SliceInput) { PostsForView( where: $where sort: $sort pagination: $pagination search: $search token: $token ) { id uk_title: ukTitle en_title: enTitle summary: ukSummary slug startAt endAt newsFeed events journal toProfessionals photoHeader { address: mobile __typename } mixedBlocks { index en_text: enText uk_text: ukText __typename } coordinates(slice: $coordinates_slice) { lng lat __typename } __typename } }""" } response = requests.post(url, json=data) print(response.json())

正如作者所说:一个小小的请求参数更新,就让你完全不用访问每篇文章的内部页面。这个技巧无数次帮他省掉了额外的页面抓取。如果你面对 GraphQL 不知从何入手,第 7 条的"文档 + LLM"建议同样适用。

11. 不要害怕新技术

人很容易学会几个工具就一直用下去,因为"能用就行"——作者承认自己也不止一次掉进这个陷阱。

但现代站点使用现代技术,这些技术对 Web 抓取影响巨大;相应地,新的抓取工具也在不断涌现。学习它们可能会大幅简化你的下一个项目,甚至解决一些此前无法逾越的问题。作者特别推荐关注:

  • curl_cffi:一个能模拟真实浏览器 TLS 指纹的 HTTP 客户端,直击第 9 条提到的 TLS fingerprint 反爬;
  • Botasaurus框架;
  • Crawlee for Python:与本文所在仓库同源的 Python 版 Crawlee。

12. 回馈开源库

作者坦言自己也是最近才意识到这件事的重要性:他工作所用的工具要么是开源项目,要么基于开源构建。Web 抓取这门手艺本质上依赖开源——尤其是当你是 Python 开发者,并意识到纯 Python 在面对 TLS 指纹时有多无力时,你就会明白又是开源救了我们。

他认为力所能及的最低限度,是投入一点知识与技能来支持开源。作者选择了支持 Crawlee for Python,理由是它展现出极佳的开发动力,且目标就是让爬虫开发者的工作更轻松:它把会话管理、被屏蔽时的会话轮换、异步任务的并发控制(写过异步代码的人都懂这有多痛苦)等关键环节收进引擎盖下,让爬虫开发更快。

无论你选择支持哪个项目,原则是一样的:你的项目能跑起来,背后站着无数开源维护者。

结语:把这 12 条当作检查清单

这篇文章里有些内容对你来说可能是显而易见的,有些你可能本来就在做,但希望你也学到了新东西。如果大部分对你都是新的,那么在下一个项目中把这 12 条当作 checklist 用起来

  1. 先选数据源(官方 API → 网站 → 移动应用);
  2. robots.txtsitemap(在 Crawlee 中直接对应RobotsTxtFileSitemapSitemapRequestLoader);
  3. 给站点分析设时间上限,必要时用分析替代代码;
  4. 边交互边盯 Network 面板;
  5. 追根溯源,数据总在某处产生;
  6. 用无痕模式排除缓存干扰;
  7. 了解站点框架(文档 + LLM);
  8. 评估逆向工程的投入产出,必要时换数据源或换技术;
  9. 逐个验证端点请求的合法性(headers、Referrer、TLS 指纹);
  10. 大胆试验请求参数(sortlimit、GraphQL 字段);
  11. 保持对新工具的好奇心;
  12. 回馈你依赖的开源生态。

把这套思维框架沉淀下来,你就不再是"照着教程敲代码"的人,而是真正像爬虫专家一样思考的人。相关能力的源码与示例都在本仓库:工具层见 packages/utils/src/internals/robots.ts 与 packages/utils/src/internals/sitemap.ts,爬虫接入层见 packages/core/src/storages/sitemap_request_loader.ts,配套示例见 docs/examples/crawl_sitemap.mdx 与 docs/guides/request_loaders.mdx。

【免费下载链接】crawleeCrawlee—A web scraping and browser automation library for Node.js to build reliable crawlers. In JavaScript and TypeScript. Extract data for AI, LLMs, RAG, or GPTs. Download HTML, PDF, JPG, PNG, and other files from websites. Works with Puppeteer, Playwright, Cheerio, JSDOM, and raw HTTP. Both headful and headless mode. With proxy rotation.项目地址: https://gitcode.com/GitHub_Trending/cr/crawlee

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

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

立即咨询