我正在编写一段代码来获取游戏包的标题和价格,将每个包的标题和价格分开,但它返回bundle_price为null.

import puppeteer from "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/271590/");

  await handleAgeRestriction(page);

  await page.waitForSelector(".apphub_AppName");
  // await page.waitForSelector(".game_purchase_price");
  await page.waitForSelector("div.game_area_purchase_game > h1");
  await page.waitForSelector("div.discount_final_price");

  const result = await page.evaluate(() => {
    const data = document.querySelectorAll('.game_area_purchase_game');
    const game = [...data].map((bundle) => {
      const bundle_title = bundle.querySelector('div.game_area_purchase_game > h1').innerText;
      const bundle_price = bundle.querySelector("div.discount_final_price").innerText;

      return {
        bundle_title,
        bundle_price,
      }
    })
    return game;
  });

  console.log(result);

  await browser.close();
}

getDataFromGame();

我觉得这个错误很奇怪,因为如果我将"Bundle"替换为"Document",它将正确地检索价格,但它将始终是相同的价格

 const result = await page.evaluate(() => {
    const data = document.querySelectorAll('.game_area_purchase_game');
    const game = [...data].map((bundle) => {
      const bundle_title = bundle.querySelector('div.game_area_purchase_game > h1').innerText;
      const bundle_price = document.querySelector("div.discount_final_price").innerText;

      return {
        bundle_title,
        bundle_price,
      }
    })
    return game;
  });

  console.log(result);

(这是一个例子,它不会给我一个错误,但价格将是相同的所有Bundle .

推荐答案

错误(Error [TypeError]: Cannot read properties of null (reading 'textContent'))的原因是某些包没有.discount_final_price个元素.取而代之的是,他们有一个下拉列表,让你从几个不同价格的选项中 Select 一个.

您可以使用一个条件来处理.discount_final_price总是存在的可能性,而不是假设总是存在.discount_final_price,然后获取下拉列表:

const result = await page.$$eval(
  ".game_area_purchase_game",
  els =>
    els.map(bundle => {
      const bundle_title = bundle
        .querySelector("h1")
        ?.textContent.trim();
      const bundle_price = bundle.querySelector(
        ".discount_final_price"
      )?.textContent;

      if (bundle_price) {
        return {
          bundle_title,
          bundle_price,
        };
      }

      bundle
        .querySelector(
          ".game_area_purchase_game_dropdown_selection"
        )
        .click();
      return {
        bundle_title,
        bundle_prices: [
          ...bundle.querySelectorAll(
            ".game_area_purchase_game_dropdown_menu_item_text"
          ),
        ].map(e => e.textContent)
      };
    })
);

现在的输出如下所示:

[
  {
    bundle_title: 'Buy Shark Cash Cards',
    bundle_prices: [
      'Tiger Shark: GTA$250,000 - $4.99',
      'Bull Shark: GTA$600,000 - $9.99',
      'Great White Shark: GTA$1,500,000 - $19.99',
      'Whale Shark: GTA$4,250,000 - $49.99',
      'Megalodon Shark: GTA$10,000,000 - $99.99'
    ]
  },
  {
    bundle_title: 'Buy Grand Theft Auto V: Premium Edition & Great White Shark Card Bundle',
    bundle_price: '$19.80'
  },
  {
    bundle_title: 'Buy Grand Theft Auto V: Premium Edition & Megalodon Shark Card Bundle',
    bundle_price: '$36.40'
  },
  {
    bundle_title: 'Buy Grand Theft Auto V: Premium Edition',
    bundle_price: '$29.98'
  }
]

您可以进一步处理此列表,并使用e.textContent.split(" - ").at(-1)从每个可扩展项目中提取价格.

Javascript相关问答推荐

我应该在redux reducer中调用其他reducer函数吗?

使用axios.获取实时服务器时的404响应

docx.js:如何在客户端使用文档修补程序

D3 Scale在v6中工作,但在v7中不工作

如何在模块层面提供服务?

显示图—如何在图例项上添加删除线效果?

如何使onPaste事件与可拖动的HTML元素一起工作?

使用Google API无法进行Web抓取

禁用.js文件扩展名并从目录导入隐式根index.js时,找不到NodeJS导入模块

如何在DYGRAPS中更改鼠标事件和键盘输入

使用RxJS from Event和@ViewChild vs KeyUp事件和RxJS主题更改输入字段值

Node.js错误: node 不可单击或不是元素

判断函数参数的类型

使用Reaction窗体挂钩注册日历组件

在JavaScript中将Base64转换为JSON

由于http.get,*ngIf的延迟很大

如何将值从后端传递到前端

react :图表负片区域不同 colored颜色

在JS/TS中构造RSA公钥

在ReactJS上挂载组件时获得多个身份验证请求