首页 > 解决方案 > 使用 Puppeteer 刮取亚马逊价格

问题描述

我试图抓取亚马逊页面以获取产品的价格,但抓取结果给我的金额与实际浏览器中显示的金额不同。我检查了很多次,但无法得到正确的结果。它给了我 89.99 美元,而在实际网站上,该产品的价格为 58.95 美元。亚马逊是故意混淆网络爬虫和爬虫还是我的错?我在 NodeJS 中使用了 Puppeteer 和 JSDom。

节点代码:

const puppeteer = require('puppeteer');
const jsdom = require('jsdom');
const { JSDOM } = jsdom;

const url = 'https://www.amazon.com/Razer-DeathAdder-Chroma-Multi-Color-Comfortable/dp/B00MYTSDU4/ref=sr_1_2?dchild=1&keywords=Deathadder%2BChroma&qid=1625425444&sr=8-2&th=1';

async function configureBrowser() {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto(url);
    return page;
}

async function pageContent() {
    let page = await configureBrowser();
    // await page.reload();
    let html = await page.evaluate(() => document.body.innerHTML);
    await page.close();

    console.log(new JSDOM(html).window.document.querySelector('#priceblock_ourprice').textContent);

    // return new JSDOM(html).window.document.querySelector('#priceblock_ourprice').textContent;
}

module.exports = pageContent;

标签: node.jsweb-scrapingpuppeteer

解决方案


将 JSDom 与 Puppeteer 结合起来很奇怪。Puppeteer 已经拥有一整套选择器,并且可以在网页内的实际合法 DOM 上工作,因此使用像 JSDom 这样的模拟 DOM 转储和重新解析整个 HTML 有点像买一辆全新的自行车,然后随身携带而不是骑它。

笑话:如果您使用 JSDom 和 Puppeteer,您将被收取额外的 30 美元...

当页面动态注入内容时,只需单独使用 Puppeteer:

const puppeteer = require("puppeteer");

const url = "https://www.amazon.com/Razer-DeathAdder-Chroma-Multi-Color-Comfortable/dp/B00MYTSDU4/ref=sr_1_2?dchild=1&keywords=Deathadder%2BChroma&qid=1625425444&sr=8-2&th=1";

let browser;
(async () => {
  browser = await puppeteer.launch();
  const [page] = await browser.pages();
  await page.goto(url, {waitUntil: "networkidle0"});
  const selector = "#priceblock_ourprice";
  await page.waitForSelector(selector);
  const price = await page.$eval(selector, el => el.innerText);
  console.log(price); // => $58.95
})()
  .catch(err => console.error(err))
  .finally(async () => await browser.close())
;

由于在这种情况下,您想要的价格似乎直接融入了静态 HTML,因此您可以跳过 Puppeteer 并使用 JSDom 以及基本的 HTTP 请求来获取数据:

<span id="priceblock_ourprice" class="a-size-medium a-color-price priceBlockBuyingPriceString">$58.95</span>
const axios = require("axios");
const {JSDOM} = require("jsdom");

const url = "https://www.amazon.com/Razer-DeathAdder-Chroma-Multi-Color-Comfortable/dp/B00MYTSDU4/ref=sr_1_2?dchild=1&keywords=Deathadder%2BChroma&qid=1625425444&sr=8-2&th=1";

(async () => {
  const {data: html} = await axios.get(url, {
    headers: {
      "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3",
      "Accept-Encoding": "gzip",
      "Accept-Language": "en-US,en;q=0.9,es;q=0.8",
      "Upgrade-Insecure-Requests": "1",
      "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36",
      "Referer": "https://www.google.com/"
    }
  });
  const price = new JSDOM(html)
    .window
    .document
    .querySelector("#priceblock_ourprice")
    .textContent
  ;
  console.log(price); // => $58.95
})()
  .catch(err => console.error(err))
;

亚马逊一直在改变价格,可能存在地区差异。根据您运行此程序的地点和时间,您可能无法获得 58.95 美元。您的方法为我在加利福尼亚运行它提供了正确的价格。您可能在远程服务器上执行它,亚马逊根据位置或其他因素提供不同的价格。

最后,您的方法在返回时放弃了对浏览器对象的引用 configureBrowser,这意味着您有内存泄漏并且进程可能会挂起。跟踪浏览器对象并.close()在完成后调用它。


推荐阅读