我已经在node.js
中编写了一个脚本,以从网页中抓取links
的不同标题。当我执行以下脚本时,将在控制台中打印undefined
而不是我后面的links
。我定义的选择器是准确的。
我不希望将links
放入数组并返回结果;相反,我希望即时打印它们。由于我刚接触node.js
和puppeteer
来编写脚本,因此我无法弄清自己犯的错误。
这是我的脚本(Link to that site):
const puppeteer = require('puppeteer');
function run () {
return new Promise(async (resolve, reject) => {
try {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto("https://stackoverflow.com/questions/tagged/web-scraping");
let url = await page.evaluate(() => {
let items = document.querySelectorAll('a.question-hyperlink');
items.forEach((item) => {
//would like to keep the following line intact
console.log(item.getAttribute('href'));
});
})
browser.close();
return resolve(url);
} catch (e) {
return reject(e);
}
})
}
run().then(console.log).catch(console.error);
如果我考虑声明一个空数组
results
并在其中存储已抓取的链接并最终返回results
,则以下脚本可以正常工作,但我不希望这样。我想坚持我上面尝试的方式,就像即时打印结果一样。
const puppeteer = require('puppeteer');
function run () {
return new Promise(async (resolve, reject) => {
try {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto("https://stackoverflow.com/questions/tagged/web-scraping");
let urls = await page.evaluate(() => {
let results = [];
let items = document.querySelectorAll('a.question-hyperlink');
items.forEach((item) => {
results.push({
url: item.getAttribute('href'),
});
});
return results;
})
browser.close();
return resolve(urls);
} catch (e) {
return reject(e);
}
})
}
run().then(console.log).catch(console.error);
再一次:我的问题是如何在不将其存储在数组中的情况下即时打印类似console.log(item.getAttribute('href'));
的链接?
答案 0 :(得分:2)
要在console.log()
中运行evaluate()
,只需在定义页面的位置复制下面的行
page.on('console', obj => console.log(obj._text));
所以现在整个片段现在都是这样
const puppeteer = require('puppeteer');
function run () {
return new Promise(async (resolve, reject) => {
try {
const browser = await puppeteer.launch();
const page = await browser.newPage();
page.on('console', obj => console.log(obj._text));
await page.goto("https://stackoverflow.com/questions/tagged/web-scraping");
let url = await page.evaluate(() => {
let items = document.querySelectorAll('a.question-hyperlink');
items.forEach((item) => {
//would like to keep the following line intact
console.log(item.getAttribute('href'));
});
})
browser.close();
return resolve(url);
} catch (e) {
return reject(e);
}
})
}
run().then(console.log).catch(console.error);
希望获得帮助
答案 1 :(得分:1)
该库看起来有点尴尬,但在github- https://github.com/GoogleChrome/puppeteer/issues/628
上找到了从该线程获取href的正确方法。我要使用的工作代码是使用await page.$$eval
async function getStackoverflowLinks(){
return new Promise(async(resolve, reject)=>{
console.log(`going to launch chromium via puppeteer`)
const browser = await puppeteer.launch()
console.log(`creating page/tab`)
const page = await browser.newPage()
await page.goto('https://stackoverflow.com/questions/tagged/web-scraping')
console.log("fetched SO web-scraping, now parsing link href")
let matches = await page.$$eval('a.question-hyperlink', hrefs=>hrefs.map((a)=>{
return a.href
})) // $$eval and map version, $$eval returns an array
console.log("matches = ", matches.length)
await browser.close()
resolve(matches)
})
}
getStackoverflowLinks()
.then(hrefs=>{
console.log("hrefs: ", hrefs)
})
答案 2 :(得分:0)
注意事项
async
函数将返回诺言。new Promise
也将返回承诺。请注意,您只需使用.console
事件即可即时打印它们。用法
page.on("console", msg => console.log(msg.text()));
await page.evaluate(async => {
console.log("I will be printed on node console too")
})
已在this answer上讨论了高级用法。