Scarnox · Blog

如何抓取由 JavaScript 渲染的网站

许多现代网站发送的 HTML 文档几乎是空的,内容由浏览器通过 JavaScript 构建。如果你的抓取器获取了页面却找不到任何商品、价格或文章正文,内容其实是存在的,只是来得更晚。本指南说明如何判断你拿到的是哪一类页面,如何在有可行方案时找到比浏览器更快的途径,以及如何用 Python 的 Playwright 抓取渲染后的页面。最后会说明,渲染后的页面出现验证码时该怎么办。

第 1 步:检查内容是否在 HTML 中

在浏览器中用 view-source: 打开页面,或者用普通的 HTTP 请求获取页面,然后在源码中搜索屏幕上能看到的一段文字。常见的结果有三种:

第 2 步:如果存在 JSON 接口就调用它

当页面从某个接口获取数据时,直接调用该接口通常是最好的选择。它比渲染后的页面更小、更快、更稳定。复制请求 URL,检查网站要求的请求头,然后从脚本中尝试调用。只有在网站条款允许的情况下才这样做,并且要遵守网站期望的速率限制或认证方式。未公开的接口可能在没有通知的情况下变更,因此请让你的解析器在响应结构改变时明确报错,而不是悄悄出错。

第 3 步:必要时渲染页面

如果内容确实需要浏览器才能呈现,就驱动一个无头浏览器。Playwright 是 Python 中的一个好选择。下面的示例打开一个商品列表,等待内容出现,然后读取每张卡片中的文字:

from playwright.sync_api import sync_playwright

URL = "https://example.com/products"  # 你有权抓取的页面

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    page = browser.new_page()
    page.goto(URL, wait_until="domcontentloaded", timeout=60_000)
    # 等待能证明数据已加载的元素出现。
    page.wait_for_selector(".product-card", timeout=30_000)
    titles = page.locator(".product-card h2").all_inner_texts()
    browser.close()

for title in titles:
    print(title)

等待特定选择器,远比使用固定的 sleep 可靠。固定的停顿在网速慢的日子可能不够,在网速快的日子又会白白浪费时间。请选择那个只有在数据加载完成后才会出现的元素。

第 4 步:处理无限滚动和分页

有些页面在你滚动时加载更多条目。滚动到底部,等待条目数量增长,并在数量不再增长时停止。带编号的分页则更简单:找到下一页的链接,点击进入,并在最后一页停止。务必设置最大页数或滚动次数,避免程序的 bug 让抓取器永远运行下去。

def scroll_until_done(page, selector: str, max_rounds: int = 20) -> int:
    previous = -1
    for _ in range(max_rounds):
        count = page.locator(selector).count()
        if count == previous:
            break
        previous = count
        page.mouse.wheel(0, 4000)
        page.wait_for_timeout(1500)  # 留出时间让下一批内容加载
    return previous

第 5 步:保持浏览器的开销可控

渲染的开销很大。屏蔽你不需要的图片、字体和媒体资源,并且复用同一个浏览器来访问多个页面,而不是每次都启动一个新的浏览器。完成后关闭页面和上下文,这样在长时间运行时内存不会持续增长。

def block_heavy_assets(route):
    if route.request.resource_type in ("image", "font", "media"):
        route.abort()
    else:
        route.continue_()

page.route("**/*", block_heavy_assets)

第 6 步:渲染页面出现验证码时

有时渲染后的页面会在显示任何内容之前先出现验证码。如果这个验证码是 PopularCaptcha(Scarnox 目前上线的验证码类型),你就从页面中读取 sitekey,请求一个 token,然后把 token 放入网站期望的表单字段中。PopularCaptcha Python 指南会逐步讲解这一步。其他控件尚未上线,因此在规划之前,请先查看验证码类型详解。

对浏览器本身也要小心。明显看起来是自动化的无头浏览器,可能会触发更多检查,而不是更少。请阅读无头浏览器检测,了解需要注意的信号,并优先选择速度更慢、加载次数更少的方式。

负责任地抓取

下一步

免费试用额度,无需信用卡:注册账户,并在你自己的页面上测试 PopularCaptcha 流程。当前费率请查看定价页面。