Crawlee LinkeDOMCrawler 完全指南:基于 linkedom 的轻量级 HTTP 爬虫 API 深度解析
2026/9/11 17:36:58 网站建设 项目流程

Crawlee LinkeDOMCrawler 完全指南:基于 linkedom 的轻量级 HTTP 爬虫 API 深度解析

【免费下载链接】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 仓库中@crawlee/linkedom包的公开 API 报告(crawlee-linkedom.api.md)编写,系统讲解LinkeDOMCrawler的完整 API 表面:从类与选项接口、爬取上下文(LinkeDOMCrawlingContext)的六大核心能力,到路由器工厂与类型化用法。作为基于纯 HTTP 请求 + linkedom DOM 实现的高速爬虫,LinkeDOMCrawler是处理静态 HTML/XML/JSON 页面的利器。读完本文,你将掌握该爬虫的初始化、window/document解析、parseWithCheeriowaitForSelector、链接提取与入队等全部 API 用法,并能结合源码理解其底层实现原理与适用边界。

一、包定位:@crawlee/linkedom是什么

@crawlee/linkedom是 Crawlee 家族中的一个 HTTP 系爬虫包(版本 4.0.0,见 package.json),核心导出只有两类内容:

  1. LinkeDOMCrawler及其相关的选项、上下文、错误处理器、钩子、请求处理器类型;
  2. createLinkeDOMRouter路由器工厂函数,同时重新导出@crawlee/http的全部 APIexport * from "@crawlee/http")。

从类型依赖看,该包完全构建在@crawlee/http之上:LinkeDOMCrawler extends HttpCrawler,而HttpCrawler本身又是@crawlee/coreBasicCrawler的 HTTP 实现。因此你可以把LinkeDOMCrawler理解为"拥有 DOM 解析能力的 HttpCrawler"——它用裸 HTTP 请求下载页面,再用 linkedom 把响应体解析为真实的 DOM 树。

它与CheerioCrawler的差异在于解析方式:Cheerio 是类 jQuery 的字符串级选择器工具,而 linkedom 提供的是符合 W3C 标准的window/document/Document对象,更接近浏览器原生 DOM API。正如 http-clients.mdx 中所说,这类"HTTP 系爬虫"比基于浏览器的爬虫更快,但一般无法执行客户端 JavaScript。

二、LinkeDOMCrawler 类:核心 API 与继承体系

2.1 类签名

API 报告中LinkeDOMCrawler的完整泛型签名如下:

export class LinkeDOMCrawler< ContextExtension = Dictionary<never>, ExtendedContext extends LinkeDOMCrawlingContext = LinkeDOMCrawlingContext & ContextExtension, Routes extends Record<keyof Routes, Dictionary> = Record<string, GetUserDataFromRequest<LinkeDOMCrawlingContext['request']>>, StatisticStateExtension extends object = {}, > extends HttpCrawler<LinkeDOMCrawlingContext, ContextExtension, ExtendedContext, Routes, StatisticStateExtension> { constructor(options?: LinkeDOMCrawlerOptions<ContextExtension, ExtendedContext, any, any, Routes, StatisticStateExtension>); protected buildContextPipeline(): ContextPipeline<CrawlingContext, LinkeDOMCrawlingContext>; }

从源码结构看(linkedom-crawler.ts),该类的公开面非常克制:构造函数接收LinkeDOMCrawlerOptions,内部重写了受保护的buildContextPipeline()方法,其余能力全部继承自HttpCrawler

2.2 构造函数与选项(LinkeDOMCrawlerOptions)

LinkeDOMCrawlerOptions是一个空扩展接口,直接继承HttpCrawlerOptions

export interface LinkeDOMCrawlerOptions<...> extends HttpCrawlerOptions< LinkeDOMCrawlingContext<UserData, JSONData>, ContextExtension, ExtendedContext, Routes, StatisticStateExtension > {}

这意味着所有HttpCrawler的选项都可用,其中最常用的包括:

选项作用
requestHandler每次请求成功后调用的处理函数,接收LinkeDOMCrawlingContext
preNavigationHooks/postNavigationHooks请求发出前/后的钩子,可用于调整请求或上下文
requestManager请求管理器(RequestQueue本身就是一个请求管理器),替代已废弃的requestList/requestQueue
additionalMimeTypes允许处理的额外 MIME 类型(默认只处理 HTML/XML/JSON 等白名单类型)
minConcurrency/maxConcurrency/maxRequestsPerMinute并发控制,由ConcurrencySystem判断空闲 CPU/内存后才派发新请求
concurrencySystem需要更精细控制时,可注入预配置的并发系统

构造函数实现(linkedom-crawler.ts)会解构出contextPipelineBuilder并默认注入本类实现的构建器:

constructor(options: LinkeDOMCrawlerOptions<...> = {}) { const { contextPipelineBuilder, ...rest } = options; super({ ...rest, contextPipelineBuilder: contextPipelineBuilder ?? (() => this.buildContextPipeline()), }); }

即:除非用户显式提供自定义的contextPipelineBuilder,否则LinkeDOMCrawler会使用自己的管道——HttpCrawler的基础管道之后依次compose两个动作:parseContent(把响应体解析成 linkedom DOM),再addHelpers(注入四个便捷助手方法)

2.3 MIME 类型白名单与解析行为差异

源码类注释(linkedom-crawler.ts)明确指出:默认只处理text/htmlapplication/xhtml+xmltext/xmlapplication/xmlapplication/json五种 MIME 类型(以Content-Type响应头为准),其他类型直接跳过。需要处理更多类型时使用additionalMimeTypes选项——底层由 http-crawler.ts 的z.string()数组 schema 校验,并通过extendSupportedMimeTypes()扩展白名单。

关键点在于解析行为因内容类型而异parseContent的实现(linkedom-crawler.ts)只区分 XML 与 HTML 两种解析模式:

const isXml = crawlingContext.contentType.type.includes('xml'); const document = LinkeDOMCrawler.#parser.parseFromString( crawlingContext.body.toString(), isXml ? 'text/xml' : 'text/html', );

从源码结构看,HTML 与 XML 之外的 JSON 等类型并非由 linkedom 解析出真实 DOM(linkedom 对非 HTML/XML 内容支持有限),处理时需结合requestHandler中可用的contentTypebody自行判断。另外注意LinkeDOMCrawler使用静态共享的DOMParser实例static #parser = new DOMParser(),来自linkedom/cached),跨请求复用解析器以减少开销。

三、爬取上下文 LinkeDOMCrawlingContext:六大能力详解

LinkeDOMCrawlingContextrequestHandler收到的核心对象,继承自InternalHttpCrawlingContext<UserData, JSONData>,并新增了 6 个成员:

export interface LinkeDOMCrawlingContext<UserData extends Dictionary = any, JSONData extends Dictionary = any> extends InternalHttpCrawlingContext<UserData, JSONData> { window: Window; document: Document; waitForSelector(selector: string, timeoutMs?: number): Promise<void>; parseWithCheerio(selector?: string, timeoutMs?: number): Promise<CheerioAPI>; extractLinks(options?: ExtractLinksOptions): Promise<string[]>; enqueueLinks(options?: EnqueueLinksOptions): Promise<AddRequestsBatchedResult>; }

3.1 window 与 document:原生的 DOM 解析入口

  • window:linkedom 解析出的 Window 对象,可直接操作window.document
  • documentDocument类型(源码注释说明:实际可能是 linkedom 的HTMLDocumentXMLDocument,取决于响应 Content-Type;为了书写便利统一声明为原生Document类型)。

这是本爬虫区别于 CheerioCrawler 的最大特点——你可以直接用浏览器风格的 DOM API:

const crawler = new LinkeDOMCrawler({ async requestHandler({ request, window, document }) { await Dataset.pushData({ url: request.url, title: window.document.title, // 也可以: h1: document.querySelector('h1')?.textContent, }); }, }); await crawler.run(['https://crawlee.dev']);

上述示例就是类注释中的官方用法(linkedom-crawler.ts),也是 e2e 测试 main.ts 中实际验证过的模式(用document.querySelector('title')断言页面标题非空)。

3.2 waitForSelector:等待元素出现

waitForSelector(selector: string, timeoutMs?: number): Promise<void>;

默认超时5 秒。实现原理(linkedom-crawler.ts)很直接:用cheerio.load(body)加载响应体,若$(selector)匹配不到元素,则sleep(50)后递归重试,直到超时抛错Selector '...' not found.

由于 linkedom 不执行 JavaScript,这个"等待"实际上等待的是后续钩子或并发任务导致的 body 内容变化(例如其他钩子修改了上下文 body)。典型用法:

async requestHandler({ waitForSelector, parseWithCheerio }) { await waitForSelector('article h1'); const $ = await parseWithCheerio(); const title = $('title').text(); }

3.3 parseWithCheerio:在 linkedom 与 Cheerio 之间无缝切换

parseWithCheerio(selector?: string, timeoutMs?: number): Promise<CheerioAPI>;

该助手返回一个CheerioAPI(来自cheerio包),让你能用与 CheerioCrawler 完全相同的方式处理数据。若传入selector,会先按 5 秒超时查找该选择器,找不到则抛错:

async requestHandler({ parseWithCheerio }) { const $ = await parseWithCheerio(); const title = $('title').text(); const links = $('a').map((_, el) => $(el).attr('href')).get(); }

注意源码中parseWithCheeriotimeoutMs参数当前并未实际用于轮询(linkedom-crawler.ts 中直接cheerio.load(body)后立即检查选择器),但从类型签名看它被保留用于 API 一致性,调用时传selector做一次性校验即可。

3.4 extractLinks 与 enqueueLinks:链接提取与入队

extractLinks(options?: ExtractLinksOptions): Promise<string[]>; enqueueLinks(options?: EnqueueLinksOptions): Promise<AddRequestsBatchedResult>;

两者是配套的:

  • extractLinks:从已解析的 DOM 中提取 URL 并返回字符串数组,不写入请求队列。实现位于私有函数extractUrlsFromWindow(linkedom-crawler.ts):用window.document.querySelectorAll(selector)(默认'a')收集所有元素的href,过滤空值后用tryAbsoluteURL(href, baseUrl)解析为绝对 URL,baseUrl默认取request.loadedUrl ?? request.url
  • enqueueLinks:提取 URL 后通过addRequests批量加入请求队列(返回AddRequestsBatchedResult)。它先用resolveBaseUrlForEnqueueLinksFiltering根据strategy、最终请求 URL、原始 URL 和用户提供的baseUrl计算过滤基准,默认strategyEnqueueStrategy.SameHostname(同主机名策略)。

典型用法见 e2e 测试:

crawler.router.addDefaultHandler(async ({ document, enqueueLinks, request, log }) => { const { url } = request; await enqueueLinks({ include: ['https://crawlee.dev/js/docs/**'], }); const pageTitle = document.querySelector('title')?.textContent ?? ''; log.info(`URL: ${url} TITLE: ${pageTitle}`); await Dataset.pushData({ url, pageTitle }); });

这个模式展示了一条完整的递归爬取链路:抓取起始页 →enqueueLinks按 glob 模式筛选入队 → 处理子页面 → 存入 Dataset。

四、类型别名:ErrorHandler、Hook 与 RequestHandler

API 报告还导出三个类型别名,全部是对@crawlee/http对应类型的特化,把上下文固定为LinkeDOMCrawlingContext

export type LinkeDOMErrorHandler<...> = ErrorHandler<CrawlingContext, LinkeDOMCrawlingContext<UserData, JSONData> & ContextExtension>; export type LinkeDOMHook<...> = InternalHttpHook<LinkeDOMCrawlingContext<UserData, JSONData>>; export type LinkeDOMRequestHandler<...> = RequestHandler<LinkeDOMCrawlingContext<UserData, JSONData>>;
  • LinkeDOMErrorHandler:错误处理函数签名,可用于failedRequestHandler,例如配合ErrorSnapshotter记录失败快照;
  • LinkeDOMHookpreNavigationHooks/postNavigationHooks中的钩子函数类型,可在请求前后访问或修改LinkeDOMCrawlingContext
  • LinkeDOMRequestHandlerrequestHandler的类型别名,供需要显式标注类型的场景使用。

使用示例(钩子):

const crawler = new LinkeDOMCrawler({ preNavigationHooks: [ (crawlingContext) => { // 调整请求或上下文 crawlingContext.request.headers = { ...crawlingContext.request.headers, 'X-Custom': '1' }; }, ], async requestHandler({ window }) { // ... }, });

五、createLinkeDOMRouter:类型安全的标签路由

createLinkeDOMRouterRouter.create<LinkeDOMCrawlingContext>()的快捷方式,返回可充当requestHandler的路由器实例。API 报告给出了三个重载,分别对应三种路由风格:

// 1. 无参:默认上下文,未类型化的路由 export function createLinkeDOMRouter< Context extends LinkeDOMCrawlingContext = LinkeDOMCrawlingContext, Routes extends Record<keyof Routes, Dictionary> = Record<string, GetUserDataFromRequest<Context['request']>>, >(routes?: RouterRoutes<Context, Routes>): RouterHandler<Context, Routes>; // 2. 显式 UserData 泛型 export function createLinkeDOMRouter< Context extends LinkeDOMCrawlingContext = LinkeDOMCrawlingContext, UserData extends Dictionary = GetUserDataFromRequest<Context['request']>, >(routes?: RouterRoutes<Context, Record<string, UserData>>): RouterHandler<Context, Record<string, UserData>>; // 3. Schema 驱动:const 类型参数的 RouteSchemas export function createLinkeDOMRouter< Context extends LinkeDOMCrawlingContext = LinkeDOMCrawlingContext, const Schemas extends RouteSchemas = RouteSchemas, >(schemas: Schemas): RouterHandler<Context, RoutesFromSchemas<Schemas>>;

实现只有一行(linkedom-crawler.ts):return Router.create(routesOrSchemas)

官方用法示例(类注释提供):

import { LinkeDOMCrawler, createLinkeDOMRouter } from 'crawlee'; const router = createLinkeDOMRouter(); router.addHandler('label-a', async (ctx) => { ctx.log.info('处理 label-a'); }); router.addDefaultHandler(async (ctx) => { ctx.log.info('默认处理器'); }); const crawler = new LinkeDOMCrawler({ requestHandler: router, }); await crawler.run();

配合第三种重载,你还可以用 zod 风格的 schema 声明userData结构,获得request.userData全类型推断与运行时校验,这是大型爬虫项目组织多页面逻辑的标准做法。e2e 测试 main.ts 展示的crawler.router.addDefaultHandler(...)模式与之等价(LinkeDOMCrawler继承自HttpCrawler,自带router属性)。

六、安装与运行环境

@crawlee/linkedom的 package.json 明确了运行约束:

  • Node.js >= 22.0.0"engines": { "node": ">=22.0.0" });
  • ESM 模块"type": "module",导出入口为./dist/index.js);
  • 关键依赖:@crawlee/http(workspace 依赖,提供HttpCrawler基类)、@crawlee/types@crawlee/utilscheerio ^1.0.0(用于parseWithCheerio/waitForSelector)、linkedom ^0.18.10(DOM 解析)、@apify/timeout@apify/utilitiestslib

在 monorepo 中使用 pnpm 时,安装入口为@crawlee/linkedom;单包使用时,也可以从crawlee聚合包导入(源码示例即import { LinkeDOMCrawler, createLinkeDOMRouter } from 'crawlee',见 crawlee 聚合入口 与 crawlee.api.md)。

七、已知限制与适用场景

源码类注释明确列出了LinkeDOMCrawler的限制(linkedom-crawler.ts):

  1. 不执行 JavaScript:若目标网站依赖 JS 渲染内容,应改用PuppeteerCrawlerPlaywrightCrawler(基于无头 Chrome);
  2. 暂不支持代理与 Cookie:每次请求都从空 Cookie 存储开始,User-Agent 恒为Chrome
  3. MIME 白名单:默认只处理 HTML/XML/JSON 五类 Content-Type,其他类型需additionalMimeTypes手动扩展;
  4. 解析差异:HTML、XML、JSON 的解析行为不同,JSON 等类型不会获得完整的 linkedom DOM 树。

同时,其优势也非常明确(README.md):使用裸 HTTP 请求下载页面,速度快、带宽利用率高,特别适合纯静态页面的批量抓取、站点地图遍历、RSS/XML 源处理等场景。由于输出的是标准 DOM 对象,它还能为 AI/LLM 数据管线提供结构化的 HTML 语义数据。

选型速查

需求推荐爬虫
静态 HTML 高速抓取,需 DOM APILinkeDOMCrawler
类 jQuery 字符串选择器,极致轻量CheerioCrawler
需要执行 JS、完整浏览器渲染PuppeteerCrawler/PlaywrightCrawler
需要代理轮换、Cookie 管理优先考虑CheerioCrawler等支持代理的 HTTP 系爬虫

八、小结

@crawlee/linkedom是 Crawlee 生态中"HTTP 系 + 标准 DOM"路线的代表实现:

  • API 表面LinkeDOMCrawler类(继承HttpCrawler)、LinkeDOMCrawlerOptionsLinkeDOMCrawlingContextwindow/document/waitForSelector/parseWithCheerio/extractLinks/enqueueLinks)、三个类型别名与createLinkeDOMRouter
  • 实现要点:共享DOMParser静态实例、管道依次执行parseContentaddHelpers、XML/HTML 双模式解析、SameHostname默认入队策略;
  • 边界清晰:快但无 JS、无代理/Cookie、固定 Chrome UA、MIME 白名单可扩展。

完整的公开 API 清单以 crawlee-linkedom.api.md 为准,源码实现见 linkedom-crawler.ts,端到端验证示例见 linkedom-default-ts e2e 测试。

【免费下载链接】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),仅供参考

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

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

立即咨询