如何将带有 require 语句的本地脚本注入 Puppeteer 页面

How to inject local script with require statements into Puppeteer page

我正在使用 Puppeteer 抓取网页。我想解析页面中的 URL,等等。我知道我可以将功能移出 page.evaluate,但那不是主要问题。问题是如何将任意脚本注入页面,以便可以在 page.evaluate.

中使用脚本中的 variables/functions

就我而言,我使用的是 lil-uri。我基本上是这样的:

var puppeteer = require('puppeteer')
var URL = require('lil-uri')

puppeteer.launch().then(browser => {
  browser.newPage().then(page => {
    page.goto('https://foo.com').catch(onerror).then(() => {
      page.evaluate(fetchLinks).catch(onerror)
    })
  })
  // })
})

function onerror(err) {
  console.log('ERRR', err)
}

function fetchLinks() {
  var linkEls = document.querySelectorAll('a')
  var links = []

  for (var i = 0, n = linkEls.length; i < n; i++) {
    var el = linkEls[i]

    // PARSE URL
    var url = parseUrl(el.getAttribute('href'))

    links.push(url)
  }

  return links

  function parseUrl(href) {
    // REF THE URL LIBRARY
    var url = URL(href)
    var url2 = url.path()
    var query = []
    var q = url.query()
    if (Object.keys(q).length) {
      // query.push(...)
    }
    if (query.length) {
      url2 += '?' + query.join('&')
    }
    return url2
  }
}

这不起作用,因为 require('lil-uri') 在 Node.js 脚本的范围内,而它实际上是在 page.evaluate.[=24= 的上下文中使用的]

问题是,如何在页面中正确包含 parseUrlURL 函数,以便它们可以在 page.evaluate.

的上下文中使用

此外,如您所见,我将 parseUrl 函数 放在 函数 fetchLinks 中,这并不理想,因为我无法重用它我在页面上评估的其他功能之间。我希望能够在 page.evaluate 的上下文中执行类似 window.parseUrl = parseUrl 的操作,但我也不确定该怎么做。想知道是否有人可以展示如何做这两件事:

  1. 如何将本地外部脚本加载到 puppeteer 页面。
  2. 如何将函数加载到 puppeteer 页面的 window。

您可以使用 page.exposeFunction 将 Node.js 环境中的函数公开给页面本身。引用文档:

The method adds a function called name on the page's window object. When called, the function executes puppeteerFunction in node.js and returns a Promise which resolves to the return value of puppeteerFunction.

代码示例

下面的代码会将您的函数 parseUrl 公开给页面。然后,您可以从 page.evaluate.

中通过 window.parseUrl 调用该函数
const puppeteer = require('puppeteer');

function parseUrl(href) {
    // ...
    return '...';
}

(async () => {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.exposeFunction('parseUrl', href => parseUrl(href));

    await page.evaluate(async () => {
        const url = 'http://...';
        const parsedUrl = await window.parseUrl(url);
    });
    await browser.close();
})();

关于 URLs

解析的旁注

这与您的问题没有直接关系,但您可能不一定需要解析 Node.js 环境中的 URL 。有 JavaScript API URL ,它允许您在浏览器本身内部解析 URLs,如下所示:

const url = new URL('http://www.example.org/path123');
console.log(url.pathname); // will print: /path123

根据您的用例,您甚至可能不需要公开功能,因为您可以在浏览器本身内部完成。