【问题标题】:How to use url module in puppeteer page.evaluate如何在 puppeteer page.evaluate 中使用 url 模块
【发布时间】:2019-02-24 18:18:55
【问题描述】:

我已经尝试了Error: Evaluation Failed: ReferenceError: util is not definedHow to pass required module object to puppeteer page.evaluate 中提到的所有内容。具体来说,我尝试过使用 browserify 转换 url.js(我也尝试过将 url.js 和 punycode.js 一起转换),并在页面环境中添加了相应的脚本(bundle.js)。

我正在尝试在 puppeteer 中使用 page.evaluate() 中的 url 模块。这是一个显示错误的非常简单的示例:

const puppeteer = require('puppeteer');

puppeteer.launch({dumpio: true}).then(async browser => {
  const page = await browser.newPage();
  const response = await page.goto('https://www.google.com');
  await page.waitFor(5000);
  const pageUrl = page.url();
  await page.addScriptTag({path: 'bundle.js'});
  await page.evaluate(pageUrl => {
    const anchors = Array.from(document.querySelectorAll('a'));
    for (let anchor of anchors) {
      const href = anchor.getAttribute('href');
      let hrefUrl;
      try {
        hrefUrl = new URL(href);
      } catch (e) {
        hrefUrl = new URL(href, pageUrl);
      }
      console.log(url.format(hrefUrl, {fragment: false}));
    }
  }, pageUrl);
  await page.close();
  await browser.close();
});

此示例生成以下错误:

(节点:23667)UnhandledPromiseRejectionWarning:错误:评估 失败:ReferenceError:未定义 url 在 pageUrl (puppeteer_evaluation_script:11:19) 在 ExecutionContext.evaluateHandle (/home/webb/node_modules/puppeteer/lib/ExecutionContext.js:97:13) 在 在 process._tickCallback (internal/process/next_tick.js:188:7)

我还需要做什么才能识别 url 模块?

【问题讨论】:

  • 你为什么不只评估并返回一个href列表,然后在节点端进行url解析。如果您仍想在客户端上执行此操作,请查看暴露函数方法:github.com/GoogleChrome/puppeteer/blob/v1.12.2/docs/…
  • 因为实际用例要复杂得多,并且要处理大量的 DOM 操作。我做了这个简单的例子只是为了说明错误以及我无法在评估中使用 url 模块。
  • 但就你的观点而言,我可以将事情分解并从一个评估中传递数据,使用 url 模块处理该数据,然后将处理后的数据传递回另一个评估。我只是希望能够在一个评估中一次完成所有操作。

标签: javascript node.js url puppeteer


【解决方案1】:

page.exposeFunction() 的变体:

'use strict';

const url = require('url');
const puppeteer = require('puppeteer');

puppeteer.launch({ dumpio: true }).then(async browser => {
  const page = await browser.newPage();
  await page.exposeFunction('formatURL', formatURL);

  const response = await page.goto('https://www.google.com');
  await page.waitFor(5000);
  const pageUrl = page.url();

  await page.evaluate(async (pageUrl) => {
    const anchors = Array.from(document.querySelectorAll('a'));
    for (const anchor of anchors) {
      const href = anchor.getAttribute('href');
      const hrefUrl = await formatURL(href, pageUrl);
      console.log(hrefUrl);
    }
  }, pageUrl);

  await page.close();
  await browser.close();
});

function formatURL(href, base) {
  try {
    return url.format(new URL(href), { fragment: false });
  } catch (e) {
    return url.format(new URL(href, base), { fragment: false });
  }
}

【讨论】:

  • 这看起来像个赢家。一个小的修改(对于其他阅读本文的人):您需要添加“const URL = require('url').URL;”能够使用 URL 对象。非常感谢您!
  • @user4487338 此外,从 Node.js 11.0.0 开始,Node.js 中的 URL is a global object 与 Web API 保持一致。
【解决方案2】:

使用page.exposeFunction 公开url 包中的所有函数。

迭代模块的导出并添加要公开的每个函数

var url = require('url');

var functionsToExpose = [];
for(let key of Object.keys(url)){
    if(typeof url[key] == 'function'){
        functionsToExpose.push({name: 'url'+key, func: url[key]});
    }
}

将它们暴露在页面上

for(let item of functionsToExpose){
    await page.exposeFunction(item.name, item.func);
}

url 包的每个函数都会被重命名。 url.parse 可使用urlparse 访问。

【讨论】:

    猜你喜欢
    • 2020-05-09
    • 1970-01-01
    • 1970-01-01
    • 2019-10-20
    • 1970-01-01
    • 2018-07-26
    • 2018-02-22
    • 1970-01-01
    • 2021-06-11
    相关资源
    最近更新 更多