【问题标题】:Inject jQuery into Puppeteer page将 jQuery 注入 Puppeteer 页面
【发布时间】:2018-04-09 19:05:39
【问题描述】:

我正在尝试将 jQuery 注入我的 Puppeteer 页面,因为 document.querySelector 不适合我:

async function inject_jquery(page){
  await page.evaluate(() => {
    var jq = document.createElement("script")
    jq.src = "https://code.jquery.com/jquery-3.2.1.min.js"
    document.querySelector("head").appendChild(jq)
  })
  const watchDog = page.waitForFunction('window.jQuery !== undefined');
  await watchDog;
}

结果主要是超时。有人有解决办法吗?

【问题讨论】:

  • 你试过document.getElementsByTagName('head')[0].appendChild(jq) 吗?此外,由于您正在设置src,因此侦听脚本元素的load 事件然后返回可能会更加健壮。

标签: javascript jquery node.js google-chrome-devtools puppeteer


【解决方案1】:

从 CDN 注入 jQuery(受上面@browserless 答案的启发):

// go to page
await page.goto(url_str);
        
// inject jQuery
var jquery_ev_fn = await page.evaluate(function(){
    return window.fetch('https://code.jquery.com/jquery-3.4.1.min.js').then(function(res){
        return res.text();
    });
});
await page.evaluate(jquery_ev_fn);

注入本地jQuery:

// get local jQuery and inject it
var jquery_code_str = fs.readFileSync('/path/to/local/jquery.js', 'utf8');

// go to page
await page.goto(url_str);
        
// inject jQuery
var jquery_ev_fn = await page.evaluate(function(code_str){
    return code_str;
}, jquery_code_str);
await page.evaluate(jquery_ev_fn);

【讨论】:

    【解决方案2】:

    目前找到的最好的解决方案,由于浏览器源策略,URL插入可能无法正常工作,因此我们插入本地文件内容而不是URL。

    const fs = require('fs');
    const path = require('path');
    
    const addJQueryToPage = async (page) => {
        const file = fs.readFileSync(path.resolve(__dirname, 'jquery-file-in-same-directory.min.js'), 'utf8');
        await page.addScriptTag({ content: file });
        await page.evaluate(_ => {
            $.noConflict();
        });
    }
    

    【讨论】:

      【解决方案3】:

      您可以使用以下方法将jQuery添加到使用page.evaluate()的页面中:

      await page.evaluate(async () => {
        const script = document.createElement('script');
        script.src = 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js';
        const promise = new Promise((resolve, reject) => {
          script.onload = resolve;
          script.onerror = reject;
        });
        document.head.appendChild(script);
        await promise;
      });
      

      【讨论】:

        【解决方案4】:

        我刚刚发布了我的 puppeteer jquery 集成here

        代码示例:

        let browser = await launch({headless: true});
        let pageOrg = await browser.newPage();
        let page = pageExtand(pageOrg);
        // append a <H1>
        await page.jQuery('body').append(`<h1>Title</h1>`);
        // get the H1 value
        let title = await page.jQuery('h1').text();
        // chain calls
        let text = await page.jQuery('body button:last')
                  .closest('div')
                  .find('h3')
                  .css('color', 'yellow')
                  .parent()
                  .find(':last')
                  .text();
        

        尚未映射所有 jQuery 函数,因此如果您需要更多函数,请打开问题(每个调用都需要按名称和参数数量添加)。

        【讨论】:

          【解决方案5】:

          有些网站不允许您注入脚本标签,因此您必须先注入其中的内容,然后它才会允许您这样做。如果是这种情况,您可以使用evaluate 方法从 CDN 中获取脚本内容并手动注入:

          const jquery = await page.evaluate(() => window.fetch('https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js').then((res) => res.text()));
          await page.goto(YOUR_PAGE_HERE);
          await page.evaluate(jquery);
          

          如果你想在野外看到一个例子,这用于为browserless here(我是这个工具的作者)抓取 puppeteer 的文档。

          【讨论】:

            【解决方案6】:

            如果你有这样的情况,如果你把你的脚本注入到你的html页面标题中,它会变得更容易管理

            <script type="text/javascript" src="abc.min.js"></script>
            

            现在您可以轻松地在 page.evaluate(function(){ })

            中调用它的函数

            【讨论】:

              【解决方案7】:

              对于那些希望注入本地 jQuery 副本的人:

              await page.addScriptTag({path: require.resolve('jquery')})

              【讨论】:

              • 我在 ES6 上,没有'require' :)
              • 现在有效:await page.addScriptTag({path: 'myScript.js'})
              【解决方案8】:

              我正在这样做:

              await page.addScriptTag({ url: 'https://code.jquery.com/jquery-3.2.1.min.js' });
              const title = await page.evaluate(() => {
                const $ = window.$; //otherwise the transpiler will rename it and won't work
                return $('h1 > span').text();
              });
              

              【讨论】:

                【解决方案9】:

                我已经使用page.addScriptTag 注入js 文件。

                ...
                await page.addScriptTag({url: 'https://code.jquery.com/jquery-3.2.1.min.js'})
                ...
                

                page.addScriptTag - 文档

                使用puppeteer: 0.12.0的工作示例

                import { launch } from 'puppeteer'
                (async () => {
                    const browser = await launch({headless: false});
                    const page = await browser.newPage();
                    await page.goto('https://example.com', {waitUntil: 'networkidle'});
                    await page.addScriptTag({url: 'https://code.jquery.com/jquery-3.2.1.min.js'});
                    await page.close();
                    await browser.close();
                })();
                

                【讨论】:

                • 这也给了我:未处理的拒绝:Promise Promise { 错误:协议错误(Runtime.callFunctionOn):执行上下文被破坏。未定义
                • 没关系,我需要在该部分之前添加一个await page.waitForNavigation()。这是最好的解决方案。
                【解决方案10】:

                这对我有用。

                async function inject_jquery(page){
                      await page.evaluate(() => {
                        var jq = document.createElement("script")
                        jq.setAttribute('type','text/javascript');
                        jq.src = "https://code.jquery.com/jquery-3.2.1.min.js"
                        return new Promise( (resolve) => {
                            jq.addEventListener("load", ()=> {
                                resolve();
                            });
                            document.getElementsByTagName("head")[0].appendChild(jq);
                        });
                      })
                      const watchDog = page.waitForFunction('window.jQuery !== undefined');
                      await watchDog;
                    }
                

                【讨论】:

                • 这给了我:未处理的拒绝:Promise Promise { 错误:协议错误(Runtime.callFunctionOn):执行上下文被破坏。未定义
                • 在调用inject_jquery 时,您的页面对象是否仍然有效?你能分享调用代码吗?至少出于学术原因,此答案可能会解释您的脚本失败的原因。我相信nilobarp的解决方案更简单
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2012-06-21
                • 1970-01-01
                • 2019-09-25
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-11-25
                相关资源
                最近更新 更多