我正在编写一个 html,通过 puppeteer 从互联网上抓取数据,代码如下:
const puppeteer = require('puppeteer');
(async ()=>
{
const browser = await puppeteer.launch()
const page = await browser.newPage()
await page.goto("https://www.info.gov.hk/gia/wr/202404/26.htm")
const bulletin_urls = await page.$$('div.leftBody');
for(const bulletin_url of bulletin_urls)
{
try
{
const bulletin_name = await page.evaluate(el => el.textContent, bulletin_url)
console.log(bulletin_name)
const single_url = await page.evaluate(el => el.getAttribute("href"), bulletin_url)
console.log(single_url)
}
catch(err)
{
}
}
await browser.close()
}) ();
我想抓取所有新闻天气的2条信息:
我在抓取 1 时成功,在抓取 2 时失败。我得到的只是 null。我尝试将我的代码修改为
const single_url = await page.evaluate(el => el.querySelector(".NEW").getAttribute("href"), bulletin_url)
console.log(single_url)
但是,它只返回第一个网址,但不是全部网址。我该怎么做才能通过一个命令收集超链接的所有 url?任何建议将不胜感激。
您正在选择容器,而不是其中的特定元素。尝试这样做:
const puppeteer = require("puppeteer"); // ^22.7.1
const url = "<Your URL>";
let browser;
(async () => {
browser = await puppeteer.launch();
const [page] = await browser.pages();
await page.setJavaScriptEnabled(false);
await page.setRequestInterception(true);
page.on("request", req => {
if (req.url() === url) {
req.continue()
} else {
req.abort();
}
});
await page.goto(url, {waitUntil: "domcontentloaded"});
const data = await page.$$eval(".NEW", els => els.map(el => ({
text: el.textContent,
href: el.href,
})));
console.log(data);
console.log(data.length); // => 125
})()
.catch(err => console.error(err))
.finally(() => browser?.close());
这里的大部分代码都是禁用 JS 并阻止资源请求,因为数据就在静态 HTML 中,这意味着您不需要 Puppeteer。只需使用 Fetch(现在内置于 Node 中)和 Cheerio(轻量级 HTML 解析器)即可。
const cheerio = require("cheerio"); // ^1.0.0-rc.12
const url = "<Your URL>";
fetch(url)
.then(res => {
if (!res.ok) {
throw Error(res.statusText);
}
return res.text();
})
.then(html => {
const $ = cheerio.load(html);
const data = [...$(".NEW")].map(e => ({
text: $(e).text(),
href: $(e).attr("href"),
}));
console.log(data);
console.log(data.length);
})
.catch(err => console.error(err));
Puppeteer 未优化(没有任何块,有 JS,没有
{waitUntil: "domcontentloaded"}
:
real 0m4.180s
user 0m0.981s
sys 0m0.198s
Puppeteer 优化(如上图):
real 0m1.181s
user 0m0.642s
sys 0m0.171s
取来并欢呼:
real 0m0.426s
user 0m0.194s
sys 0m0.045s
重要提示:永远不要将
catch (err) {}
与空块一起使用,除非你真的想阻止错误。在本例中,您正在调试脚本,因此您最不想做的就是丢弃重要的调试信息。
此外,避免使用元素句柄。它们冗长、缓慢且容易出错。除了发出可信事件之外,没有必要使用它们,而在网络抓取中通常不需要这些事件,除非偶尔填写需要事件处理程序触发的表单。 95% 的情况下,
$$eval
是正确的选择。只需一次访问浏览器即可获取数据并退出。