【问题标题】:Puppeteer wrong result with evaluate() & exposeFunction()使用评估()和暴露函数()的 Puppeteer 错误结果
【发布时间】:2019-06-27 16:05:42
【问题描述】:

我运行了以下内容,它似乎收集了大量链接,但是在使用 collectLinks1 实际检查该站点时,我得到了所有有效链接,但使用 collectLinks2 我得到了 59 次 http://pieroxy.net/blog/2014/11/18/[ 迭代

我是 Puppeteer 的新手,我不知道为什么 collectLinks2 没有链接。

const { parse, resolve } = require('url');
const trim = require('lodash/trim');
const startsWith = require('lodash/startsWith');
const includes = require('lodash/includes');


// https://github.com/GoogleChrome/puppeteer
const puppeteer = require('puppeteer');
// https://github.com/gwuhaolin/chrome-finder
const findChrome = require('chrome-finder'); 


function resolveUrl(url, baseUrl) {
  url = trim(url);
  if (!url) return null;
  if (startsWith(url, '#')) return null;
  const { protocol } = parse(url);
  if (includes(['http:', 'https:'], protocol)) {
    return url.split('#')[0];
  } if (!protocol) {
    return resolve(baseUrl, url).split('#')[0];
  }
  return null;
}

async function collectLinks1(htmlPage) {
  const baseUrl = htmlPage.url();
  const links = [];
  const assetUrls = await htmlPage.$$eval('a[href]', assetLinks => assetLinks.map(link => link.href));

  assetUrls.forEach(link => {
    const _link = resolveUrl(link, baseUrl);
    if (_link) links.push(_link);
  });

  return links;
}

async function collectLinks2(htmlPage) {
  const baseUrl = htmlPage.url();
  const links = [];

  await htmlPage.exposeFunction('pushToLinks', link => {
    const _link = resolveUrl(link, baseUrl);
    if (_link) links.push(_link);
  });

  await htmlPage.evaluate(() => {
    function findLinks(document) {
      document.querySelectorAll('a[href]')
        .forEach(link => {
          window.pushToLinks(link.href);
        });
    }
    findLinks(window.document);
  });

  return links;
}

const crawl = async url => {
  try {
    console.log(`Crawling ${url}`);

    const browser = await puppeteer.launch({
      headless: false,
      executablePath: findChrome(),
    });
    const page = await browser.newPage();

    await page.goto(url);

    // OK
    const links1 = await collectLinks1(page);
    links1.forEach(link => { console.log(link); });

    // KO
    const links2 = await collectLinks2(page);
    links2.forEach(link => { console.log(link); });

    await browser.close();
  } catch (err) {
    console.log(err);
  }
};

crawl('http://pieroxy.net/blog/2014/11/18/user_agent_detection_in_java.html');

【问题讨论】:

    标签: node.js web-scraping puppeteer evaluate


    【解决方案1】:

    你需要awaitpage.exposeFunction定义的函数,因为它返回一个Promise。由于您只是调用函数而不等待其结果,因此您的 page.evaluate 调用将在脚本完成执行之前解决。

    解决方案

    您应该使用循环而不是forEach,来遍历所有项目并将它们一个接一个地传递到页面。

    async function collectLinks2(htmlPage) {
      // ...
    
      await htmlPage.evaluate(async () => {
        async function findLinks(document) {
          for (const link of document.querySelectorAll('a[href]')) {
            await window.pushToLinks(link.href);
          }
        }
        await findLinks(window.document);
      });
      return links;
    }
    

    【讨论】:

    • await window.pushToLinks(link.href); 解析错误:不能在异步函数之外使用关键字 'await'
    • @LeMoussel 我在代码中缺少async。可以再试一次吗?
    • async 没有更多错误。但是,我们仍然有 http://pieroxy.net/blog/2014/11/18/[ 作为结果。
    猜你喜欢
    • 2019-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-04
    • 1970-01-01
    • 2022-11-30
    • 1970-01-01
    相关资源
    最近更新 更多