任何人都知道如何 调用 javascript 函数 来自 puppeteer 师这不是内联的,而是在 中外部.js 文件。如果它在 html->head->script 标记中内联,则它可以工作,但如果脚本标记指向外部 .js 文件,则不能
示例 HTML 文件
<html>
<head>
<script type="text/javascript">
function inlineFunction() {
window.location.replace('https://www.geeksforgeeks.org');
}
</script>
<script src="script.js" type="text/javascript">
</script>
</head>
<body>
<p>Hello</p>
<p>this is an online html</p>
<p>Link with tag a <a href="https://www.geeksforgeeks.org" name="arivalink">Href Link</a></p>
<p>Link with inline java script - <a href="#" onClick='inlineFunction();'>Inline JS link</a></p><!-- Works -->
<p>Link with external JS file w/o tagname - <a href="#" onClick='fileFunction();'>Ext JS Link</a></p><!-- Does not work -->
<p>Link with external JS file w/ tagname - <a href="#" onClick='fileFunction();' name="geeksLink">Ext JS Link</a></p><!-- Does not work -->
</body>
</html>
示例 Javascript 文件/*----------------------------------------------------*/
/* External Javascript File */
/*----------------------------------------------------*/
function fileFunction() {
window.location.replace('https://www.geeksforgeeks.org');
}
Puppeteer 代码示例const puppeteer = require('puppeteer');
async function start() {
const browser = await puppeteer.launch({
headless: false
});
const page = await browser.newPage();
//Change the path of "url" to your local path for the html file
const url = 'file:///Users/sam.gajjar/SG/Projects/headless-chrome/sample.html';
var link = '[name="link"]';
console.log("Main URL Called");
await page.goto(url);
console.log("Link via HTML tag A called");
await page.click(link);
await page.waitForTimeout(5000) // Wait 5 seconds
.then(() => page.goBack());
console.log("Callng inline JS Function");
await page.evaluate(() => inlineFunction());
await page.waitForTimeout(5000) // Wait 5 seconds
.then(() => page.goBack());
console.log("Callng extjs file Function");
await page.evaluate(() => fileFunction());
await page.waitForTimeout(5000) // Wait 5 seconds
.then(() => page.goBack());
// console.log("Callng extjs file Function w/tag name");
// const element = await page.$$('[a href="#"]');
// await page.waitForTimeout(5000)
// .then(() => page.goBack());
}
start();
最佳答案
首先,[name="link"]
应该是 [name="arivalink"]
匹配你的 DOM。我认为这是一个错字。
另外,我建议使用 Promise.all
navigation pattern而不是 waitForTimeout
这可能会导致竞争条件(尽管在这种情况下这似乎与问题无关)。
至于主要问题,外部文件工作得很好,所以这是一个红鲱鱼。您可以通过调用 page.evaluate(() => fileFunction())
来证明这一点在导航到 sample.html
之后.
真正的问题是,当您使用 window.location.replace('https://www.geeksforgeeks.org');
导航时, Chromium 不会将该操作推送到历史堆栈中。它正在替换当前的 URL,所以 page.goBack()
回到原来的about:blank
而不是 sample.html
如你所料。 about:blank
没有 fileFunction
在里面,所以 Puppeteer 扔了。
现在,当您单击 [name="link"]
使用 Puppeteer,确实会推送历史堆栈,所以 goBack
工作得很好。
您可以通过加载 sample.html
来重现此行为在浏览器中并在没有 Puppeteer 的情况下手动导航。
长话短说,如果您在浏览器上下文中使用 evaluate
调用函数运行 window.location.replace
, 你不能依赖 page.goBack
.您需要使用 page.goto
返回 sample.html
.
有一个有趣的细微差别:如果你使用 page.click
调用运行 location.replace("...")
的 JS , Puppeteer 将推送历史堆栈和page.goBack
将按预期运行。如果您使用 page.evaluate(() => location.replace("..."));
调用相同的 JS 逻辑, Puppeteer 不会将当前 URL 推送到历史堆栈和 page.goBack
不会像你期望的那样工作。 evaluate
行为更符合“手动”浏览(即作为一个在 GUI 上使用鼠标和键盘的人)。
这是演示所有这些的代码。一切都在同一个目录和node index.js
运行 Puppeteer(我使用 Puppeteer 9.0.0)。
脚本.js
const replaceLocation = () => location.replace("https://www.example.com");
const setLocation = () => location = "https://www.example.com";
示例.html<!DOCTYPE html>
<html lang="en">
<head>
<title>sample</title>
</head>
<body>
<div>
<a href="https://www.example.com">normal link</a> |
<a href="#" onclick="replaceLocation()">location.replace()</a> |
<a href="#" onclick="setLocation()">location = ...</a>
</div>
<script src="script.js"></script>
</body>
</html>
index.jsconst puppeteer = require("puppeteer");
const url = "file:///Users/sam.gajjar/SG/Projects/headless-chrome/sample.html";
const log = (() => {
let logId = 0;
return (...args) => console.log(logId++, ...args);
})();
let browser;
(async () => {
browser = await puppeteer.launch({
headless: false,
slowMo: 500,
});
const [page] = await browser.pages();
await page.goto(url);
// display the starting location
log(page.url()); // 0 sample.html
// click the normal link and pop the browser stack with goBack
await Promise.all([
page.waitForNavigation(),
page.click("a:nth-child(1)"),
]);
log(page.url()); // 1 example.com
await page.goBack();
log(page.url()); // 2 sample.html
// fire location.replace with click
await Promise.all([
page.waitForNavigation(),
page.click("a:nth-child(2)"), // pushes history (!)
]);
log(page.url()); // 3 example.com
await page.goBack();
log(page.url()); // 4 sample.html
// fire location.replace with evaluate
await Promise.all([
page.waitForNavigation(),
page.evaluate(() => replaceLocation()), // doesn't push history
]);
log(page.url()); // 5 example.com
await page.goBack();
log(page.url()); // 6 about:blank <--- here's your bug!
await page.goto(url); // go to sample.html from about:blank <-- here's the fix
log(page.url()); // 7 sample.html
// use location = and see that goBack takes us to sample.html
await Promise.all([
page.waitForNavigation(),
page.evaluate(() => setLocation()), // same behavior as page.click
]);
log(page.url()); // 8 example.com
await page.goBack();
log(page.url()); // 9 sample.html
})()
.catch(err => console.error(err))
.finally(async () => await browser.close())
;
关于javascript - Puppeteer 从外部 .js 文件调用 javascript 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67539195/