周一至周五 09:00 - 18:00(UTC+08:00) ©2026 NST LABS TECH LTD. 保留所有权利。
如何在2026年使用JavaScript抓取网站 | Nstproxy方式
Marcus Chen Product & Network Architect
2026年如何使用JavaScript抓取网站 | Nstproxy方式
TL;DR
使用原生 fetch() 加 Cheerio 当响应已经包含数据时;对于静态 HTML,使用浏览器是不必要的开销。
当所需值仅在 JavaScript 运行后出现时,使用 Playwright,但要等待有意义的页面条件,而不是任意延迟。
生产爬虫需要明确的超时、状态检查、模式验证、有界重试、速率限制和稳定的标识符——而不仅仅是偶尔有效的选择器。
Nstproxy Crawl 适合于渲染、重试、网站发现和输出转换等成为基础设施工作而非应用逻辑的点。
仅抓取公开或授权页面,遵守适用的规则和条款,尽量减少保留的数据。
JavaScript 网络爬虫从响应开始,而不是浏览器
JavaScript 网络爬虫的过程是请求允许的网页资源,提取所需字段,并返回用于下游使用的稳定记录。最便宜可靠的方法取决于数据的存在地点:在初始 HTML 中、嵌入的 JSON 有效载荷中、文档 API 后面,或仅在渲染的浏览器状态中。
这个决定比库的流行度更重要。静态页面通常可以用 Node.js fetch() 和 Cheerio 处理。客户端渲染的目录可能需要 Playwright。广泛或重复的工作流程可能更好地由像 Nstproxy Crawl 这样的托管集合层来服务,同时你的 JavaScript 代码保持对验证和业务规则的所有权。
MDN Fetch 指南 提到了一个重要的失败模式:fetch() 并不会因为服务器返回 HTTP 错误而拒绝。你的代码必须在解析主体之前检查 response.ok 或状态。这一小细节将一个有效的记录与意外存储为产品数据的品牌 404 页面区分开来。
选择正确的 JavaScript 抓取方法
正确的方法是最简单的选项,能够一致地返回完整、有效的数据。
页面行为 首选项 升级时机 响应中有完整的 HTML fetch() + Cheerio所需字段缺失或标记频繁变化 结构化的 JSON 端点 直接 JSON 请求 端点没有文档、无稳定性或访问未授权 内容在脚本运行后出现 Playwright 浏览器操作、队列、重试或工件主导维护 多页面或受限网站发现 托管抓取 API 你需要超出通用提取的自定义域验证
Cheerio 加载和查询 HTML,而不执行页面 JavaScript。其官方文档加载指南 和 使其非常适合服务器渲染的页面。Playwright 控制浏览器页面,其 推荐使用面向用户的属性和明确的契约,而不是脆弱的 CSS 路径。
选择器指南
这个区别非常实际:不要启动 Chromium 以解析已在响应中的标题;当 HTML 仅是一个空的应用壳时,也不要不断添加 Cheerio 选择器。为了更多的上下文,请在决定你的工作是单页提取还是多页发现之前,比较 抓取与爬行 。
详细教程:逐步构建 JavaScript 爬虫 本教程从 Books to Scrape 提取书名、价格和标准 URL,这是一个为抓取练习而构建的公共实践网站。工作流程故意限制在单一页面。
方法 1:使用 fetch 和 Cheerio 抓取静态 HTML
步骤 1:创建项目 使用当前的 Node.js 运行时和内置的 fetch(),并安装 Cheerio:
mkdir js-scraper && cd js-scraper
npm init -y
npm install cheerio
步骤 2:抓取、解析和验证页面 下面的脚本检查 HTTP 状态,验证内容类型,解析每个产品卡片,规范化 URL,并拒绝空结果。这些检查使得失败可以被明确,而不是返回看起来成功的空数组。
import * as cheerio from "cheerio" ;
const target = "https://books.toscrape.com/" ;
const controller = new AbortController ( ) ;
const timer = setTimeout ( ( ) => controller . abort ( ) , 15_000 ) ;
try {
const response = await fetch ( target , {
headers : { "user-agent" : "Nstproxy-Tutorial/1.0 (+authorized-demo)" } ,
signal : controller . signal ,
} ) ;
if ( ! response . ok ) throw new Error ( ` HTTP ${ response . status } ` ) ;
const type = response . headers . get ( "content-type" ) ?? "" ;
if ( ! type . includes ( "text/html" ) ) throw new Error ( ` 意外的类型: ${ type } ` ) ;
const $ = cheerio . load ( await response . text ( ) ) ;
const books = $ ( "article.product_pod" )
. map ( ( _ , card ) => {
const link = $ ( card ) . find ( "h3 a" ) ;
const title = link . attr ( "title" ) ?. trim ( ) ;
const href = link . attr ( "href" ) ;
const priceText = $ ( card ) . find ( ".price_color" ) . text ( ) . trim ( ) ;
if ( ! title || ! href || ! / ^ £ \d + \. \d {2} $ / . test ( priceText ) ) return null ;
return { title , priceText , url : new URL ( href , target ) . href } ;
} )
. get ( )
. filter ( Boolean ) ;
if ( books . length === 0 ) throw new Error ( "Schema check failed: no books" ) ;
console . log ( JSON . stringify ( { count : books . length , sample : books [ 0 ] } , null , 2 ) ) ;
} finally {
clearTimeout ( timer ) ;
}
结果结构是稳定的,即使卡片周围的展示文本发生变化:
{
"count" : 20 ,
"sample" : {
"title" : "A Light in the Attic" ,
"priceText" : "£51.77" ,
"url" : "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html"
}
}
将该输出视为合同。仅当其标题、价格格式和绝对 URL 通过验证时,记录才会被接受。返回二十个节点的选择器并不能证明这些节点是正确的二十个产品。
方法 2:使用 Playwright 渲染 JavaScript
步骤 1:确认渲染是否必要 打开网络响应或在测试浏览器中禁用 JavaScript。如果目标值已经在 HTML 中,则继续使用方法 1。如果它们在 XHR/fetch 调用后到达,则在有文档的情况下优选授权的结构化端点;否则渲染页面。
步骤 2:等待语义条件 Playwright 定位器对当前 DOM 进行解析并包含自动等待行为。生产脚本仍应设置导航超时并等待所需的特定集合:
import { chromium } from "playwright" ;
const browser = await chromium . launch ( { headless : true } ) ;
try {
const page = await browser . newPage ( ) ;
await page . goto ( "https://books.toscrape.com/" , {
waitUntil : "domcontentloaded" ,
timeout : 30_000 ,
} ) ;
const cards = page . locator ( "article.product_pod" ) ;
await cards . first ( ) . waitFor ( { state : "visible" } ) ;
const titles = await cards . locator ( "h3 a" ) . evaluateAll ( ( links ) =>
links . map ( ( link ) => link . getAttribute ( "title" ) ?. trim ( ) ) . filter ( Boolean ) ,
) ;
if ( titles . length === 0 ) throw new Error ( "没有经过验证的标题" ) ;
console . log ( JSON . stringify ( { count : titles . length , first : titles [ 0 ] } ) ) ;
} finally {
await browser . close ( ) ;
}
避免使用 waitForTimeout(5000) 作为准备策略。在快速页面上,它很慢,而在慢速页面上仍然存在竞争。等待结果容器、已知的 API 响应或其他表示页面实际上已准备好的条件。
使 JavaScript 抓取器具备生产安全性 生产安全性来自于界定工作和测试含义,而不是从更快地发送请求。
为每个网络边界设置超时。 覆盖 DNS、连接、响应、浏览器导航和下游存储。挂起的请求不得无限期占用工作线程。
仅重试瞬态失败。 选定网络错误、429 和一些 5xx 响应进行重试,并设定有界的指数回退和抖动。不重试无效选择器或永久授权失败。
限制每个主机的并发性。 保守启动,观察延迟和错误率,并在提供时尊重 Retry-After。
使用稳定标识符。 存储规范 URL 或站点提供的产品 ID,并使写入操作为幂等,以便重试不会重复记录。
验证内容,而不仅仅是状态。 检查预期字段、值格式、语言以及最小/最大记录范围。软 404 通常返回 200。
记录操作上下文。 记录目标主机、状态、持续时间、重试计数、解析器版本和验证结果——绝对不要记录凭据或私密响应主体。
当渲染、重试和站点发现成为瓶颈时,请使用 Nstproxy Crawl 一个 JavaScript 抓取工具已经跨入基础设施工作,当浏览器工作者、重试、提取清理、任务状态和工件存储所需的努力超过您实际需要的记录时。Nstproxy Crawl 解决了这一瓶颈,作为公共页面和有限站点工作的托管网络收集层。它返回结构化或视觉输出,以使您的 Node.js 服务能够专注于域验证、去重、增强和存储。当前的计费支持按需使用和订阅,URL 处理和代理流量分开计算;验证与您的工作负载匹配的实时计划。Nstproxy Crawl 可以减少操作开销,但并不取代权限检查或特定业务的验收测试。
消除浏览器群维护: 当需要执行 JavaScript 时,使用托管渲染,而不是自己操作浏览器工作者。
防止 uncontrolled 站点发现: 设置明确的深度、页面限制和包含/排除规则,以便抓取无法游走到日历、搜索页面、登录流程或无限参数中。
向您的应用程序提供可用输出: 请求下游代码所需的表示,然后在接受之前验证响应正文的成功和任务状态。
将成本与接受的记录进行比较: 查看 当前抓取计费模型 ,并比较每个经过验证的记录的成本,而不仅仅是每个请求的成本。
API 凭证是实时抓取请求的前提条件,因此这里不显示虚构的托管服务输出。当您集成时,请将密钥保存在密钥管理器或环境变量中,绝不要放在源代码管理中。
确保 JavaScript 网络抓取的授权和边界 负责任的 JavaScript 网络抓取使用公共或授权数据进行特定目的,只收集应用程序所需的数据。阅读站点的条款、隐私公告和适用法律;遵守合同和技术限制;避免在没有适当法律依据的情况下绕过身份验证、支付墙、私人页面和受管制的个人数据。
机器人排除协议 标准化了抓取者的 robots.txt 规则,同时也指出这些规则不是访问授权。将 robots.txt 视为操作信号,而不是收集或重用数据的权限。定义保留限制,当不再需要时删除过时的原始 HTML,并将外展或分析工作流程与通用收集管道隔离。
结论:构建最小的能够适应变化的抓取工具 从 fetch() 和 Cheerio 开始,仅将真正动态的页面提升到 Playwright,并在其维护超过您的域逻辑时将重复的渲染和抓取操作移至托管基础设施。运行静态示例,为您的真实授权目标添加架构断言,并在增加并发之前测量接受的记录。如果多个代理源后续成为操作问题,请将 Nstproxy Proxy Manager 评估为单独的路由层。
常见问题 是的,当您的团队已经使用 Node.js 或目标需要浏览器执行时,JavaScript 是一个强大的抓取选择。原生的 fetch()、Cheerio、Playwright 和成熟的队列库涵盖了从单个静态页面到维护抓取管道的工作负载。
问:我应该使用 Cheerio 还是 Playwright?
当初始响应包含所需的 HTML 时使用 Cheerio,当必须运行 JavaScript 以生成数据时使用 Playwright。在接受浏览器的成本和复杂性之前确认这一差异。
问:为什么 fetch 即使是 404 也返回页面?
fetch() 对 HTTP 错误状态解析为 Response,因此您的代码必须检查 response.ok 或 response.status。它会对特定的网络级失败拒绝,而不是每个失败的 HTTP 结果。
问:我该如何防止选择器断裂?
优先使用语义属性、稳定的ID、结构化数据和作用域选择器,然后验证提取的记录。监控架构指纹和样本输出比节点计数检查更早地捕捉到潜在的漂移。
不,代理改变网络路由;它们并不授予权限或免除法律、合同、隐私或版权义务。仅在合法授权的收集政策内使用代理。
问:我应该在什么时候使用Nstproxy Crawl,而不是我自己的抓取工具?
当浏览器渲染、受限发现、重试、任务状态或输出转换成为重复的基础设施工作时,请使用Nstproxy Crawl。保留自己的JavaScript层用于特定领域的验证、身份、存储和政策执行。
立即访问住宅、数据中心、IPv6 与 ISP 高质量代理池。 创建免费账号并立即试用 ->