【问题标题】:Can't scrape and print the links on the fly无法即时抓取和打印链接
【发布时间】:2018-10-08 21:23:11
【问题描述】:

我在node.js 中编写了一个脚本来从网页中抓取不同标题的links。当我执行以下脚本时,我在控制台中打印了undefined,而不是我所追求的links。我定义的选择器是准确的。

我不希望将links 放入一个数组并返回结果;相反,我希望即时打印它们。由于我是使用node.jspuppeteer 组合编写脚本的新手,所以我无法弄清楚我正在犯的错误。

这是我的脚本 (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')); 之类的链接?

【问题讨论】:

标签: node.js web-scraping promise puppeteer


【解决方案1】:

要在evaluate() 中运行console.log(),只需复制下面定义页面的行

page.on('console', obj => console.log(obj._text));

所以现在整个sn-p现在会是这样的

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);

希望有帮助

【讨论】:

  • 感谢您的解决方案@Atishay Jain。我的第二个脚本已经开始工作了。我不想遵守这个逻辑;相反,我想像我在第一个脚本中尝试的那样即时打印结果。
  • 抱歉,我第一次更新答案时把问题弄错了。请检查@asmitu
  • 现在这个更像了。感谢@Atishay Jain 的工作解决方案。让我们在赏金活动中再等几天。
【解决方案2】:

这个库看起来有点难用,但找到了从 github 上的这个线程获取 href 的正确方法-https://github.com/GoogleChrome/puppeteer/issues/628

我的工作代码是使用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)
}) 

【讨论】:

    【解决方案3】:

    注意事项,

    • 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 上讨论。

    【讨论】:

      猜你喜欢
      • 2013-06-03
      • 1970-01-01
      • 2021-12-08
      • 2021-01-10
      • 2023-03-16
      • 2017-01-27
      • 2021-09-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多