javascript - Puppeteer 从外部 .js 文件调用 javascript 函数

标签 javascript puppeteer

任何人都知道如何 调用 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.js
const 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/

相关文章:

javascript - 如何设置 SVG 内圆圈中的参数之一的样式?

javascript - 现代无窗口弹出窗口

node.js - 是否有一种通用方法可以使用 Puppeteer 消除所有模式和 cookie 警告?

JavaScript - Puppeteer 超时等于零的含义和行为

javascript - 未捕获( promise )错误: Passed function is not well-serializable

javascript - Puppeteer 无法在 Heroku 上运行

javascript - 打开一个新窗口创建一个新 session

javascript - 当promise解析时如何重新渲染React组件? |如何阻止渲染直到数据加载?

javascript - 检测 Apache Cordova 和 JQuery 何时都准备就绪

node.js - Puppeteer/Nodejs,如何等待事件条件满足