如何将带有 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= 的上下文中使用的]
问题是,如何在页面中正确包含 parseUrl
和 URL
函数,以便它们可以在 page.evaluate
.
的上下文中使用
此外,如您所见,我将 parseUrl
函数 放在 函数 fetchLinks
中,这并不理想,因为我无法重用它我在页面上评估的其他功能之间。我希望能够在 page.evaluate
的上下文中执行类似 window.parseUrl = parseUrl
的操作,但我也不确定该怎么做。想知道是否有人可以展示如何做这两件事:
- 如何将本地外部脚本加载到 puppeteer 页面。
- 如何将函数加载到 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
根据您的用例,您甚至可能不需要公开功能,因为您可以在浏览器本身内部完成。
我正在使用 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
.[=24= 的上下文中使用的]
问题是,如何在页面中正确包含 parseUrl
和 URL
函数,以便它们可以在 page.evaluate
.
此外,如您所见,我将 parseUrl
函数 放在 函数 fetchLinks
中,这并不理想,因为我无法重用它我在页面上评估的其他功能之间。我希望能够在 page.evaluate
的上下文中执行类似 window.parseUrl = parseUrl
的操作,但我也不确定该怎么做。想知道是否有人可以展示如何做这两件事:
- 如何将本地外部脚本加载到 puppeteer 页面。
- 如何将函数加载到 puppeteer 页面的 window。
您可以使用 page.exposeFunction
将 Node.js 环境中的函数公开给页面本身。引用文档:
The method adds a function called
name
on the page'swindow
object. When called, the function executespuppeteerFunction
in node.js and returns a Promise which resolves to the return value ofpuppeteerFunction
.
代码示例
下面的代码会将您的函数 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
根据您的用例,您甚至可能不需要公开功能,因为您可以在浏览器本身内部完成。