Crawlee JSDOMCrawler 完全指南:用 Window API 与 jsdom 解析 HTML 构建高效爬虫 📅 发布时间:2026/9/11 19:24:07 👁 浏览次数: Crawlee JSDOMCrawler 完全指南用 Window API 与 jsdom 解析 HTML 构建高效爬虫【免费下载链接】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/crawleeJSDOMCrawler 是 Crawlee 中基于 Node.js 的 jsdom 实现进行网页解析的爬虫它用原生 HTTP 请求获取页面后将 HTML 交给 jsdom 构建出完整的window/document对象让你像在前端开发中一样使用浏览器 API 提取数据。本文以crawlee/jsdom包的公开 API 报告docs/public-api/crawlee-jsdom.api.md为骨架结合源码、示例与测试完整讲解其工作原理、配置参数、上下文方法、脚本执行模式与路由用法帮助你在「CheerioCrawler 不够用、又不需要完整浏览器」的场景下快速落地。JSDOMCrawler 是什么介于 Cheerio 与无头浏览器之间JSDOMCrawler是crawlee/jsdom包导出的核心爬虫类它继承自HttpCrawler见 packages/jsdom-crawler/src/internals/jsdom-crawler.ts因此天然继承了 HttpCrawler 的全部能力HTTP 请求管理、请求队列、重试、并发控制、会话与数据集存储等。它的核心工作流非常直接官方文档 docs/guides/jsdom_crawler.mdx 中描述为how the crawler works使用专门化的 HTTP 客户端发起纯 HTTP 请求下载页面通常返回 HTML将响应正文交给jsdom解析构造出一个完整的 DOM 环境把window对象注入requestHandler让你用浏览器侧的 Window API / Element API 提取数据。与CheerioCrawler相比它提供了一整套 HTML DOM APIdocument.querySelectorAll、element.textContent、a.href等对前端开发者极为友好与PuppeteerCrawler/PlaywrightCrawler相比它不启动真实浏览器速度更快、带宽占用更低。官方指南给出的优劣势总结如下优势易于搭建无需启动浏览器进程对前端开发者熟悉——直接用window/document操作页面页面内容可以被脚本操纵配合runScripts执行页面 JS纯 HTTP 请求模式下能自动规避一部分反爬检测。劣势比CheerioCrawler慢因为要构建完整 DOM无法处理依赖 JavaScript 渲染内容的网站并发过高时容易给目标网站造成压力。关于浏览器 API 的等价关系指南中有个经典对照浏览器里document.title在 JSDOMCrawler 中应写window.document.title。快速开始一个完整可运行的示例仓库中的官方示例 docs/examples/jsdom_crawler.ts 展示了 JSDOMCrawler 的完整用法这里给出带注释的完整版本import { JSDOMCrawler, log, LogLevel } from crawlee; // 可选将日志级别调到 DEBUG 便于调试 log.setLevel(LogLevel.DEBUG); const crawler new JSDOMCrawler({ // 爬虫并行下载与处理页面并发由系统内存/CPU 自动调节 // 这里给出硬性上下限 minConcurrency: 10, maxConcurrency: 50, // 出错时每个页面最多重试 1 次 maxRequestRetries: 1, // 单页处理超时时间秒 requestHandlerTimeoutSecs: 30, // 整个爬取过程最多 10 个请求 maxRequestsPerCrawl: 10, // 每个 URL 都会调用此函数 async requestHandler({ pushData, request, window }) { log.debug(Processing ${request.url}...); // 用 Window API 提取数据 const title window.document.title; const h1texts: { text: string }[] []; window.document.querySelectorAll(h1).forEach((element) { h1texts.push({ text: element.textContent! }); }); // 存入数据集本地模式下写入 ./storage/datasets/default await pushData({ url: request.url, title, h1texts, }); }, // 重试超过 maxRequestRetries 1 次仍失败时调用 failedRequestHandler({ request }) { log.debug(Request ${request.url} failed twice.); }, }); // 传入 URL 列表并等待爬取完成 await crawler.run([https://crawlee.dev]); log.debug(Crawler finished.);其中pushData、request、window都来自JSDOMCrawlingContext下文详述。运行后数据会以 JSON 形式落在本地./storage/datasets/default目录中。公开 API 全景从 API 报告看包结构crawlee/jsdom的 API 报告docs/public-api/crawlee-jsdom.api.md完整列出了包的公开导出。整个包的入口文件 packages/jsdom-crawler/src/index.ts 只有两行export * from crawlee/http与export * from ./internals/jsdom-crawler.js——这印证了报告末尾export * from crawlee/http的含义JSDOMCrawler 会连带导出 HttpCrawler 的所有类型与工具。包的核心导出可归纳为 7 组导出类型说明JSDOMCrawlerclass爬虫主类继承自HttpCrawlerJSDOMCrawlerOptionsinterface构造参数扩展自HttpCrawlerOptionsJSDOMCrawlingContextinterfacerequestHandler 收到的爬取上下文JSDOMRequestHandlertype请求处理函数类型JSDOMErrorHandlertype失败处理函数类型JSDOMHooktype钩子函数类型pre/post navigation 等createJSDOMRouterfunction基于 label 的路由工厂3 个重载包依赖方面见 packages/jsdom-crawler/package.json它直接依赖crawlee/http继承爬虫骨架、jsdomDOM 解析、cheerioparseWithCheerio辅助、apify/timeout脚本执行超时以及zod参数校验要求 Node.js22.0.0。JSDOMCrawlerOptions专有选项与继承选项JSDOMCrawlerOptions在HttpCrawlerOptions之上只新增了两个专属选项见源码 packages/jsdom-crawler/src/internals/jsdom-crawler.tsrunScripts默认false是否下载并执行页面中的脚本。设为true时jsdom 会以dangerously模式执行页面内的 JavaScript源码第 303 行适用于依赖客户端渲染才能显示内容的页面如 React 应用存在安全风险它会执行目标网站的任意脚本只在信任目标站点时开启源码中在执行脚本后会等待window的load事件最长等待 10 秒见addTimeoutToPromise调用第 330-350 行超时仅记录 debug 日志不会中断爬取。hideInternalConsole默认false是否屏蔽 jsdom 内部 console 的输出。为false时jsdom 页内console.log/console.error等消息会通过VirtualConsole.sendTo(console, { omitJSDOMErrors: true })转发到 Node.js 控制台源码第 284-286 行为true时消息不会默认打印到控制台但你仍可通过crawler.getVirtualConsole()主动监听。这两个选项在源码中通过zod校验optionsShape见第 218-222 行构造时会解析并解构出runScripts、hideInternalConsole与contextPipelineBuilder其余参数全部透传给HttpCrawler构造函数。继承自 HttpCrawler 的常用选项由于继承关系以下 HttpCrawler 选项同样生效官方示例与 README 均有使用minConcurrency/maxConcurrency并发上下限由ConcurrencySystem依据空闲 CPU 与内存动态调度新请求maxRequestsPerMinute每分钟请求数上限maxRequestsPerCrawl整个爬取过程的请求总数上限maxRequestRetries单页最大重试次数requestHandlerTimeoutSecs每个页面的处理超时additionalMimeTypes额外的 MIME 类型白名单requestManager请求管理器可传RequestQueue或将RequestList通过toTandem()组合成RequestManagerTandem实现静态列表 动态入队旧的requestList/requestQueue选项仍被接受并合并进requestManager仅为向后兼容。需要特别注意MIME 类型过滤默认情况下 JSDOMCrawler 只处理text/html、application/xhtmlxml、text/xml、application/xml与application/json这五种Content-Type其余类型直接跳过。如需处理更多类型用additionalMimeTypes扩展并留意不同内容类型的解析行为差异。JSDOMCrawlingContextrequestHandler 的完整工具箱每次请求都会构造一个JSDOMCrawlingContext它扩展自InternalHttpCrawlingContext在 HttpCrawler 上下文的基础上增加了以下成员见 API 报告与源码第 70-117 行属性window / document / body成员类型说明windowDOMWindowjsdom 构造的窗口对象可用全部 Window APIdocumentDocument即window.documentHTML 文档对象bodystringHTML 字符串在skipNavigation场景下访问会抛出NavigationSkippedError注意body是一个 getter返回window.document.documentElement.outerHTML源码第 354-355 行即包含html根元素的完整序列化 HTML。方法waitForSelectorwaitForSelector(selector: string, timeoutMs?: number): Promisevoid等待匹配 CSS 选择器的元素出现默认超时 5 秒。实现方式是先用cheerio.load(body)检查选择器若不存在则以 50ms 间隔轮询重试直到超时源码第 422-435 行async requestHandler({ waitForSelector, parseWithCheerio }) { await waitForSelector(article h1); const $ await parseWithCheerio(); const title $(title).text(); }方法parseWithCheerioparseWithCheerio(selector?: string, timeoutMs?: number): PromiseCheerioAPI返回一个 cheerio 句柄让你可以用与CheerioCrawler完全相同的方式处理数据cheerio.load加载body。传入selector时若当前 DOM 中找不到该选择器会直接抛错默认 5s 超时。这是JSDOM 取 DOM、Cheerio 做解析的混合玩法先用 Window API 操作再用 cheerio 的选择器语法提取。方法extractLinksextractLinks(options?: ExtractLinksOptions): Promisestring[]从解析后的 DOM 中提取 URL 列表不加入请求队列。默认选择器为a提取每个元素的href属性并通过tryAbsoluteURL结合baseUrl优先request.loadedUrl其次request.url解析为绝对地址见extractUrlsFromWindow源码第 454-465 行。方法enqueueLinksenqueueLinks(options?: EnqueueLinksOptions): PromiseAddRequestsBatchedResult从 DOM 提取 URL 并加入请求队列内部先调用extractLinks再调用上下文自带的addRequests。默认strategy为EnqueueStrategy.SameHostname仅入队同主机链接且会自动配合maxCrawlDepth控制递归深度——这一点有测试直接验证见下文。深入源码上下文管线、虚拟控制台与脚本执行上下文管线ContextPipelineJSDOMCrawler 覆盖了buildContextPipeline()源码第 250-261 行在 HttpCrawler 管线之上追加两个阶段parseContent把响应正文解析为 JSDOM 窗口对象addHelpers注入extractLinks/enqueueLinks/waitForSelector/parseWithCheerio四个辅助方法。同时注册了清理逻辑解除jsdomError监听并调用context.window?.close()释放 DOM 内存避免长爬取过程中的内存泄漏。JSDOM 实例的构造细节parseContent源码第 295-387 行构造 JSDOM 时传入的关键参数url响应 URL保证相对链接解析正确contentTypeXML 类型内容用text/xml否则用text/html判断依据是contentType.type.includes(xml)runScripts: dangerously仅当runScripts开启resources包级共享的ResourceLoader实例其 userAgent 固定为 Chrome UAMozilla/5.0 ... Chrome/107.0.0.0 Safari/537.36源码第 199-204 行virtualConsole见下节pretendToBeVisual: true让 jsdom 模拟可视环境便于某些依赖视觉 API 的脚本运行。为了兼容真实浏览器环境源码还为window注入了两个 shimmatchMedia的桩实现第 310-322 行以及document.createRange的降级实现第 323-328 行——许多前端库依赖这些 API缺失会导致页面脚本崩溃。VirtualConsolejsdom 日志桥接getVirtualConsole()源码第 277-291 行惰性创建VirtualConsole实例默认hideInternalConsole: false将 jsdom 内部 console 消息转发到 Node.js 的console跳过 jsdomError无论是否隐藏都会注册jsdomError监听器以 debug 级别记录页面脚本错误你可以主动获取该实例监听特定事件例如把错误升级为爬取日志const console crawler.getVirtualConsole(); console.on(error, (e) { log.error(e); });createJSDOMRouter基于 label 的路由分发createJSDOMRouter()是Router.createJSDOMCrawlingContext()的快捷封装源码第 491-505 行用于按请求的labelrequest.label分发到不同处理函数。API 报告展示了它的三个重载不传参或传RouterRoutes返回RouterHandlerJSDOMCrawlingContext, Routes传RouteSchemaszod schema 映射时自动推导出带类型校验的RoutesFromSchemas路由。典型用法源码注释中的示例import { JSDOMCrawler, createJSDOMRouter } from crawlee; const router createJSDOMRouter(); router.addHandler(label-a, async (ctx) { ctx.log.info(...); }); router.addDefaultHandler(async (ctx) { ctx.log.info(...); }); const crawler new JSDOMCrawler({ requestHandler: router, }); await crawler.run();将router直接作为requestHandler传入即可。schema 重载让每个 label 的userData拥有 zod 校验与完整类型推导适合多页面类型的站点详情页 / 列表页 / 搜索页。测试验证行为由测试背书仓库测试 test/core/crawlers/dom_crawler.test.ts 对 JSDOMCrawler 的关键行为做了实证基础解析对本地 HTTP 服务器返回的 HTMLwindow.document.title与document.querySelector(p).textContent能正确提取出Example Domain与Hello, world!递归爬取与深度控制maxCrawlDepth: 1时从/depth-0出发enqueueLinks()只会再爬一层/depth-1验证了enqueueLinks对maxCrawlDepth的遵守同文件还覆盖了LinkeDOMCrawler的等价行为。这些测试同时印证了默认enqueueLinks()使用SameHostname策略且请求管理RequestQueue与并发调度都复用 HttpCrawler 的成熟实现。局限性使用前必须知道的边界依据官方 API 文档注释源码第 124-197 行JSDOMCrawler 有以下明确限制不支持代理与 Cookies每次打开页面都从空 cookie store 开始也没有代理配置能力若需要会话管理 / 代理轮换请使用 HttpCrawler 系的其他实现或浏览器型爬虫userAgent 固定为 Chrome即使设置了请求头资源加载器仍使用包内固定的 Chrome UA见 packages/jsdom-crawler/src/internals/jsdom-crawler.tsjsdom 未完整实现 Web 标准runScripts模式下部分网站仍可能运行失败或表现异常不适合 JS 渲染站点需要完整浏览器渲染时应改用 PuppeteerCrawler 或 PlaywrightCrawler指南 docs/guides/jsdom_crawler.mdx 中也有同样提示。何时选择 JSDOMCrawler综合来看选型判断可以这样简化页面首屏 HTML 已包含全部数据、无需执行 JS →CheerioCrawler最快或JSDOMCrawler需要 DOM API / 可操纵内容页面依赖 JS 渲染或需要点击、滚动等交互 →PuppeteerCrawler/PlaywrightCrawler需要执行少量页面脚本但不想启动浏览器 →JSDOMCrawlerrunScripts: true注意安全与兼容性风险。官方示例 docs/examples/jsdom_crawler_react.ts 给出了一个典型的runScripts场景直接打开 React 计算器应用执行按钮点击document.querySelectorAll(button)[12].click()等后读取结果——整个过程跑在 Node.js 进程内比浏览器方案轻量得多。更多示例可参考 docs/examples/jsdom_crawler.mdx 与指南 docs/guides/jsdom_crawler.mdx它们展示了从提取页面标题与 h1到交互式应用的完整用法梯度。【免费下载链接】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),仅供参考