You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何不使用slowMo获取动态页面数据?Steam爬虫问题排查

Puppeteer获取Steam游戏数据的问题解决

问题场景

编写了一段用于获取Steam游戏标题和价格的Puppeteer代码:

async function handleAgeRestriction(p) {
  await p.evaluate(() => {
    const select = document.querySelector("#ageYear");
    const options = select.querySelectorAll("option");
    const selectedOption = [...options].find(
      (option) => option.text === "1900"
    );

    selectedOption.selected = true;
  });
  await p.click("#view_product_page_btn");
}


async function getDataFromGame() {
  const browser = await puppeteer.launch({ headless: false });

  const page = await browser.newPage();

  await page.goto(
    "https://store.steampowered.com/app/221100/"
  );

  await handleAgeRestriction(page);

  const result = await page.evaluate(() => {
    const title = document.querySelector(".apphub_AppName").innerText;
    const price = document.querySelector('.game_purchase_price').innerText;
    const bundle_title = document.querySelector('div.game_area_purchase_game > h1').innerText;
    const bundle_price = document.querySelector('.discount_final_price').innerText;

    const game = {
      title,
      price,
      bundle_title,
      bundle_price
    }
    return game;
  });

  console.log(result);

  await browser.close();
}

运行时触发以下错误:

node:internal/process/promises:279
triggerUncaughtException(err, true /* fromPromise */);
^
Error [TypeError]: Cannot read properties of null (reading 'innerText')
at evaluate

添加slowMo:1000参数后代码可正常运行,但耗时过长,且不想让用户看到浏览器运行过程。

核心原因

错误本质是页面元素尚未加载完成就执行了获取操作,slowMo靠强制延迟规避了问题,但属于低效且不严谨的方案。

解决方案

1. 启用无头模式

使用Puppeteer的新版无头模式(不显示浏览器窗口),替代旧版headless: true:

const browser = await puppeteer.launch({ headless: "new" });

2. 用等待API替代固定延迟

针对每个需要操作的元素,使用page.waitForSelector()等待元素加载完成,确保元素存在后再执行操作:

  • 年龄验证环节:先等待年份选择器和确认按钮出现
  • 数据获取环节:等待目标标题、价格元素加载完成

3. 兼容元素不存在的情况

部分游戏可能没有捆绑包信息,直接获取会导致null报错,需要做容错处理。

修改后的完整代码

async function handleAgeRestriction(p) {
  // 等待年龄选择器加载完成,超时5秒
  await p.waitForSelector("#ageYear", { timeout: 5000 });
  await p.evaluate(() => {
    const select = document.querySelector("#ageYear");
    const options = select.querySelectorAll("option");
    const selectedOption = [...options].find(
      (option) => option.text === "1900"
    );
    if (selectedOption) selectedOption.selected = true;
  });
  // 等待确认按钮加载完成再点击
  await p.waitForSelector("#view_product_page_btn", { timeout: 5000 });
  await p.click("#view_product_page_btn");
}

async function getDataFromGame() {
  // 启用新版无头模式,不显示浏览器窗口
  const browser = await puppeteer.launch({ headless: "new" });
  const page = await browser.newPage();

  // 页面跳转时等待网络空闲(确保静态资源加载完成)
  await page.goto("https://store.steampowered.com/app/221100/", { waitUntil: "networkidle0" });

  await handleAgeRestriction(page);

  // 等待核心数据元素加载完成
  await page.waitForSelector(".apphub_AppName", { timeout: 5000 });
  await page.waitForSelector(".game_purchase_price", { timeout: 5000 });

  const result = await page.evaluate(() => {
    // 用可选链处理元素不存在的情况,避免报错
    const title = document.querySelector(".apphub_AppName")?.innerText || "无标题";
    const price = document.querySelector('.game_purchase_price')?.innerText || "无价格";
    const bundle_title = document.querySelector('div.game_area_purchase_game > h1')?.innerText || "无捆绑包";
    const bundle_price = document.querySelector('.discount_final_price')?.innerText || "无捆绑包价格";

    return { title, price, bundle_title, bundle_price };
  });

  console.log(result);
  await browser.close();
}

关键优化点说明

  • waitForSelector的timeout参数设置超时时间,避免无限等待
  • 使用可选链操作符?.处理元素不存在的情况,防止报错
  • page.goto的waitUntil设置为networkidle0,确保页面静态资源加载完成后再执行后续操作

内容的提问来源于stack exchange,提问作者Tomas Madariaga

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 07:27:10