我尝试抓取亚马逊页面以获取产品价格,但抓取结果给我的金额与实际浏览器中显示的金额不同。我检查了很多次,但没有得到正确的结果。它给了我 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;
答案 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');