大多数关于 JavaScript 密集型网站的建议都止步于第一个决策:这个页面是否需要浏览器?这个问题很重要,何时才真正需要无头浏览器来抓取一文对此有详细解答。相当一部分”JavaScript 网站”最终会发现其实并不需要浏览器。
本指南从那篇文章结束的地方开始。你已经确认目标页面确实需要渲染。现在还有第二个决策,它对成本和值班安排的影响远超第一个决策:是自己运行浏览器,还是把页面交给帮你运行浏览器的网页抓取 API?
首先,确认页面是否真的需要渲染
在投入任何一条路径之前先做个快速检查,因为渲染始终是更慢、更重的选项。
将源码与渲染后的页面进行比较。 打开原始 HTML 响应。如果你要的数据就在其中,那你不需要浏览器。
查找嵌入状态。 许多 JavaScript 框架会将初始页面数据以 JSON 形式打包进 script 标签中,这样浏览器就能在不发起额外请求的情况下对页面进行水合(hydrate)。如果你的数据就在那段 JSON 里,那么一个普通的 HTTP 请求加上 JSON 解析就足够了。
观察网络请求。 如果页面在加载后从某个 JSON 端点获取数据,直接请求该端点通常比围绕它渲染整个页面更划算。
如果以上三种方法都拿不到数据,或者该端点是签名的、不透明的,或以你无法复现的方式受到保护,那你就需要渲染。请继续阅读。
自己运行浏览器实际意味着什么
在笔记本电脑上运行一个无头浏览器很容易。但在生产环境中运行一整支浏览器舰队则是一个运维问题,而且这些成本很容易被低估,因为它们不会出现在原型阶段。
容量。 每个浏览器实例都很吃内存,这限制了一台机器上能运行多少实例,并把并发变成了一笔基础设施账单。
稳定性。 浏览器会在遇到不友好的页面时挂起、泄漏内存、崩溃。生产环境的舰队需要看门狗机制、实例回收,以及能在工作进程于页面处理中途死亡后仍能存活的队列。
维护。 浏览器版本、自动化库以及自动化特征都在不断变化。上个季度还能用的舰队,可能在你的代码一行都没改动的情况下就开始失败。
代理。 渲染流量仍然需要优质 IP,并且要正确接入浏览器,处理好认证与按上下文隔离。把这件事做对本身就是一项独立的工作;参见在 Playwright 中使用住宅代理。
封锁与验证挑战。 CAPTCHA 和反机器人检测需要检测、处理和重试机制,而且即便尝试失败,消耗的浏览器时间也已经付出了。
重试与等待。 判断动态页面何时加载完成,以及在未完成时该怎么做,这是需要你为每个站点单独编写和维护的逻辑。
这些都不是什么稀奇的事。它们只是没人会向客户收费的工作,而且随着每一个新目标的出现,这项工作量还会继续增长。
网页抓取 API 能替你分担什么
网页抓取 API 把上面这份清单变成了请求参数。以 Shifter 网页抓取 API 为例:
- 渲染。
render_js=1会在无头 Chrome 中运行页面,计费与静态抓取相同,均为一个积分。 - 等待。
wait_for_css会让抓取等待直到某个选择器出现,timeout则限制每个页面的浏览器耗时上限。 - 交互。
js_instructions会在抓取前运行一连串scrollTo、click和wait步骤,可覆盖 cookie 提示条、加载更多按钮以及滚动触发内容。 - 结构化输出。
extract_rules可根据 CSS 选择器返回 JSON,因此无需自行部署解析器。 - 重试。 抓取失败、CAPTCHA 以及目标站点的临时性错误会自动重试,最多三次,并使用不同的代理。
- 验证挑战。 隐身模式默认开启,reCAPTCHA 和 hCaptcha 会在渲染请求过程中被实时处理。
- IP。 Growth 及以上套餐会通过住宅和移动 IP 池路由,支持全球地理位置定位。Starter 套餐使用美国和欧盟的数据中心 IP,对于许多未受保护的页面已经足够。
- 会话。
session_id可在多步骤流程中保留 cookie、浏览器状态以及上游 IP,闲置 10 分钟后过期。 - 计费。 每次成功响应收取一个积分。失败请求、目标站点错误以及 API 自身发起的重试均不收费。
并发数按套餐设有上限,从 Starter 的 20 到 Enterprise 的 500 不等,超出上限的请求会返回 429。完整的参数参考文档从渲染 JavaScript 开始。
什么时候自己运行浏览器仍是正确选择
API 并非总是答案,有必要坦诚说明它不适用的场景。
长时间交互式会话。 如果某个流程需要浏览器在网站上长时间停留,且暂停时长超过了会话的闲置窗口期,那么自己的浏览器更适合。
任意的浏览器逻辑。 如果页面需要自定义脚本、扩展程序,或超出滚动、点击和等待范围之外的交互,由你自己掌控的浏览器会更灵活。
必须使用自有基础设施。 出于合同或安全原因,某些工作负载必须在特定网络或环境内运行。
体量非常大且非常稳定。 在足够大的规模、且目标很少变化的情况下,自有基础设施的单页成本可能更低,前提是你已经拥有能够运行它的工程师团队。
测试与调试。 视觉回归测试、单步调试,以及任何需要人工盯着浏览器观察的场景,都应该放在你自己的机器上进行。
按目标逐一决策的对照表
选择应按目标逐一进行,而非按公司整体决定。大多数成熟的抓取技术栈会同时使用这三条路径。
| 目标特征 | 最佳路径 |
|---|---|
| 数据在原始 HTML 或嵌入的 JSON 中 | 普通 HTTP 请求 |
| 数据来自可重放的 JSON 端点 | 直接向该端点发起普通 HTTP 请求 |
| 渲染内容,无保护,低流量 | 两者皆可;使用 API 工作量更小 |
| 渲染内容受反机器人检测保护 | 网页抓取 API |
| 渲染内容涉及多个市场 | 按请求指定国家的网页抓取 API |
| 长期认证会话或自定义浏览器逻辑 | 自有浏览器配合住宅代理 |
| 拥有内部团队且体量巨大、稳定 | 自有浏览器,以总成本评估 |
按每个可用页面的成本进行比较
在这个决策中常见的错误是,拿 API 的单次请求价格与服务器成本相比较,然后得出服务器更便宜的结论。
公平的比较应该是每个可用页面的成本。对于自有舰队,这包括闲置或崩溃的浏览器所占用的计算资源、失败尝试消耗的代理带宽,以及花在维护、重试和验证挑战处理上的工程时间,再除以实际产出正确数据的页面数。对于仅按成功响应计费的 API,失败请求不计费,因此每积分的价格更接近每个可用页面的真实成本,不过你仍需为那些成功抓取但结果无用的页面付费,比如某个选择器发生变化后返回了空字段。
用同样一批真实目标 URL,分别通过两条路径运行一周,统计返回正确、完整数据的页面数,然后比较两者每个可用页面的成本。这个数字能比任何功能列表都更快地解决争论。API 的套餐详情见定价页面。
两者的交汇之处
即便对同一个网站而言,这个选择也并非非此即彼。一种常见且明智的做法是:对不需要渲染的页面使用普通 HTTP,把渲染和受保护的页面交给 API 处理,同时为少数需要自定义逻辑的流程保留一个小型浏览器环境。
无限滚动和”加载更多”类的信息流恰好处在这个边界上,在渲染过程中处理它们的技巧详见如何处理无限滚动与动态分页。至于 API 是如何在一次请求背后把所有这些功能组合起来的,可参见网页抓取 API 是如何工作的。
常见问题
使用 API 渲染是否更贵?
在延迟上,是的,因为浏览器比普通请求耗时更长。但在积分上不会:渲染请求与静态抓取一样,只收取一个积分。
API 能应对所有反机器人系统吗?
不能保证每次、每种系统都能应对。大多数检测都能被处理,而对于持续被拦截的目标,支持团队可以针对性地调优。在依赖它之前,先在你自己的目标上测量你自己的成功率。
使用 API 还需要自己配置代理吗?
不需要单独配置代理。API 会通过自己的 IP 池路由请求,Growth 及以上套餐提供住宅和移动 IP。
什么时候该从 API 转向自建浏览器?
当你需要 API 未提供的浏览器行为时,或者当以你的真实流量为基础、经过测算的每个可用页面成本对比更倾向于自有基础设施(包括运行它所需的工程投入)时。
结论
判断一个网站是否需要 JavaScript 渲染是相对简单的一半。更昂贵的另一半在于决定由谁来运行浏览器。自有舰队换来了灵活性,但要为容量、稳定性、维护、代理和验证挑战处理付出代价。API 则用参数、重试机制和仅按成功计费的模式换取了这份灵活性。
先确认页面是否真的需要渲染,按目标而非按公司来做选择,并以实测的每个可用页面成本来决定是自建还是购买。相关产品见网页抓取 API页面。