在使用puppeteer进行脚本评估之前注入HTML

时间:2019-01-31 15:16:03

标签: javascript node.js puppeteer

我想使用puppeteer将HTML注入页面的特定元素中。

必须在执行任何JavaScript之前注入HTML。

我认为有两种方法可以做到这一点:

  1. 使用DestinationSignal
  2. 注入HTML

此函数为"is invoked after the document was created",但我无法从中访问DOM元素。例如:

page.evaluateOnNewDocument

当我访问页面时,此脚本仅输出换行符。

  1. 在插入HTML之前,使用const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); page.on('console', consoleObj => console.log(consoleObj.text())); await page.evaluateOnNewDocument( () => { const content = document.querySelector('html'); console.log(content); } ); await page.goto(process.argv[2]); await browser.close(); })(); 阻止javascript执行。尽管是per the docs,但在我重新打开它后,它并没有开始执行JavaScript。例如:

我的脚本看起来像这样:

page.setJavaScriptEnabled

或者,也可以执行类似this的操作,尽管对于一个相当简单的请求来说似乎太复杂了。

有没有一种更容易被我忽略的方法?

欢呼

3 个答案:

答案 0 :(得分:0)

看来这实际上是一个非常受欢迎的请求,我也许应该在发布我的问题之前进行更彻底的搜索。

尽管如此,我还是选择了aslushnikov here提出的解决方案。

下面的代码正是我测试该想法的结果,我敢肯定还有很大的改进空间。

我做了一个简单的功能来执行XHR:

const requestPage = async (url) => {
  return new Promise(function (resolve, reject) {
    let xhr = new XMLHttpRequest();
    xhr.open('GET', url);
    xhr.setRequestHeader('Ignore-Intercept', 'Value');
    xhr.onload = function () {
      if (this.status >= 200 && this.status < 300) {
        const response = {};
        xhr.getAllResponseHeaders()
          .trim()
          .split(/[\r\n]+/)
          .map(value => value.split(/: /))
          .forEach(keyValue => {
              response[keyValue[0].trim()] = keyValue[1].trim();
          });
        resolve({ ...response, body: xhr.response });
      } else {
        reject({
            status: this.status,
            statusText: xhr.statusText
        });
      }
    };
    xhr.onerror = function () {
      reject({
          status: this.status,
          statusText: xhr.statusText
      });
    };
    xhr.send();
  });
};

然后我将此功能暴露给页面。

然后我使用此功能执行XHR,而不是允许请求继续进行,并将其结果用作对请求的响应。

await page.setRequestInterception(true);
page.on('request', async (request) => {
  if (
    request.url() === url
    && (
      typeof request.headers()['access-control-request-headers'] === 'undefined'
      || !request.headers()['access-control-request-headers'].match(/ignore-intercept/gi)
    ) && typeof request.headers()['ignore-intercept'] === 'undefined'
  ) {
    const response = await page.evaluate(`requestPage('${url}')`);
    response.body += "hello";
    request.respond(response);
  } else {
    request.continue();
  }
});

await page.goto(`data:text/html,<iframe style='width:100%; height:100%' src=${url}></iframe>`);

令人讨厌的是,除非所需的页面位于iframe中,否则似乎无法使用page.evaluate。 (因此await page.goto(`data:text/html....

答案 1 :(得分:0)

您可以使用Page.evaluateOnNewDocument运行可在其中操纵DOM的JS。

https://pptr.dev/#?product=Puppeteer&version=v5.2.1&show=api-pageevaluateonnewdocumentpagefunction-args

答案 2 :(得分:0)

通过以下代码片段,我能够增强身体。 我用它来嘲讽。

const browser = await puppeteer.launch();
browser.on('targetchanged', async target => {
  const targetPage = await target.page();
  const client = await targetPage.target().createCDPSession();
  await client.send('Runtime.evaluate', {
    expression: `
      window.document.addEventListener("DOMContentLoaded", function () {
        const container = window.document.createElement('span');
        container.innerText = "Hello World!";
        window.document.body.appendChild(container);
      });
    `,
  });
});

我不完全确定 targetchanged 是什么。我从摆弄它的假设是,当浏览器转到特定页面“目标”时,但我可能是错的。

其他资源