我想学习一些网络抓取,我发现了 puppeteer 库。我选择 puppeteer 而不是其他工具,因为我有一些 JS 背景。
我还发现了这个website其目的是被抓取。我已经设法获取每本书每一页的信息。这是我所做的:
(async () => {
const browser = await puppeteer.launch({headless: false});
const page = await browser.newPage();
await page.goto(url); // http://books.toscrape.com/
const json = [];
let next = await page.$('.pager .next a'); // next button
while (next) {
// get all articles
let articles = await page.$$('.product_pod a');
// click on each, get data and go back
for (let index = 0; index < articles.length; index++) {
await Promise.all([
page.waitForNavigation(),
articles[index].click(),
]);
const data = await page.evaluate(getData);
json.push(data);
await page.goBack();
articles = await page.$$('.product_pod a');
}
// click the next button
await Promise.all([
page.waitForNavigation(),
page.click('.pager .next a'),
]);
// get the new next button
next = await page.$('.pager .next a');
}
fs.writeFileSync(file, JSON.stringify(json), 'utf8');
await browser.close();
})();
函数getData
传递至page.evaluate
返回具有所需属性的对象:
function getData() {
const product = document.querySelector('.product_page');
return {
title: product.querySelector('h1').textContent,
price: product.querySelector('.price_color').textContent,
description:
document.querySelector('#product_description ~ p')
? document.querySelector('#product_description ~ p').textContent
: '',
category:
document.querySelector('.breadcrumb li:nth-child(3) a')
? document.querySelector('.breadcrumb li:nth-child(3) a').textContent
: '',
cover:
location.origin +
document.querySelector('#product_gallery img')
.getAttribute('src').slice(5),
};
}
当我最终执行脚本时,一切都很顺利,除了最后的 json
。文件我有重复的记录。也就是说,每本书的文件中都有两个条目。我知道脚本可以更好,但您认为这种方法会发生什么?
最佳答案
您在这一行中的选择器:
let articles = await page.$$('.product_pod a');
匹配的内容超出了所需的范围。您得到 40 个而不是 20 个(还包括图像容器的 a
子标签,它们与 h3 的子 a
相同)
您想要限制为h3 a
:
let articles = await page.$$('.product_pod h3 a');
关于javascript - 为什么我在抓取时会得到重复的数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57433821/