使用 Puppeteer 抓取亚马逊价格

时间:2021-07-04 20:48:21

标签: node.js web-scraping puppeteer

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

NodeJS 代码:

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;

2 个答案:

答案 0 :(得分:2)

将 JSDom 与 Puppeteer 结合起来很奇怪。 Puppeteer 已经有一套完整的选择器,可以处理网页内实际合法的 DOM,所以使用模拟 DOM(如 JSDom)转储和重新解析整个 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()

答案 1 :(得分:1)

如果 ggorlen 的回答没有帮助,您可以仅使用 puppeteer 尝试这种方式。

const puppeteer = require("puppeteer");

const scrape = async (url) => {
  let browser, page;

  try {
    console.log('opening browser');
    browser = await puppeteer.launch();
    page = await browser.newPage();
    await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 60000 });

    await page.waitForSelector('#priceblock_ourprice', { visible: true });

    const data = await page.evaluate(() => {
      return [
        JSON.stringify(document.getElementById('priceblock_ourprice').innerText)
      ];
    });

    const [price] = [ JSON.parse(data[0]) ];

    console.log({ price });
    return { price };

  } catch (error) {
    console.log('scrape error', error.message);
  } finally {
    if (browser) {
      await browser.close();
      console.log('closing browser');
    }
  }
}

scrape('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');