【问题标题】:How to inject local script with require statements into Puppeteer page如何将带有 require 语句的本地脚本注入 Puppeteer 页面
【发布时间】:2019-09-25 11:17:27
【问题描述】:

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

就我而言,我使用的是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 的上下文中使用的。

问题是,如何在页面中正确包含parseUrlURL函数,以便在page.evaluate的上下文中使用它们。

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

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

【问题讨论】:

    标签: javascript node.js web-crawler puppeteer


    【解决方案1】:

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

    该方法在页面的window 对象上添加了一个名为name 的函数。调用时,该函数在 node.js 中执行 puppeteerFunction 并返回一个 Promise,该 Promise 解析为 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();
    })();
    
    

    关于 URL 解析的旁注

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

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

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

    【讨论】:

      猜你喜欢
      • 2016-01-15
      • 1970-01-01
      • 1970-01-01
      • 2018-04-09
      • 1970-01-01
      • 2013-04-26
      • 2013-02-01
      • 1970-01-01
      • 2015-02-28
      相关资源
      最近更新 更多