【问题标题】:Manually change response URL during Puppeteer request interception在 Puppeteer 请求拦截期间手动更改响应 URL
【发布时间】:2018-07-30 14:58:36
【问题描述】:

对于特定用例,我很难使用 puppeteer 导航相对 url。您可以在下面看到基本设置和描述问题的伪示例。

基本上我想更改浏览器认为他所在的当前网址。

我已经尝试过的:

  1. 通过自己解析所有相关 URL 来操作响应正文。与一些基于 javascript 的链接发生冲突。
  2. 如果请求 url 与响应 url 不匹配,则触发新 page.goto(response.url) 并返回上一个请求的响应。好像不能输入自定义选项,所以不知道哪个请求是假page.goto。

有人可以帮我一把吗?提前致谢。

设置:

const browser = await puppeteer.launch({
    headless: false,
});

const [page] = await browser.pages();

await page.setRequestInterception(true);

page.on('request', (request) => {
    const resourceType = request.resourceType();

    if (['document', 'xhr', 'script'].includes(resourceType)) {

        // fetching takes place on an different instance and handles redirects internally
        const response = await fetch(request);

        request.respond({
             body: response.body,
             statusCode: response.statusCode,
             url: response.url // no effect
        });
    } else {
        request.abort('aborted');
    }
});

导航:

await page.goto('https://start.de');

// redirects to https://redirect.de
await page.click('a'); 

// relative href '/demo.html' resolves to https://start.de/demo.html instead of https://redirect.de/demo.html
await page.click('a'); 

更新 1

解决方案 通过 window.location 操作浏览器历史记录方向。

await page.goto('https://start.de');

// redirects to https://redirect.de internally
await page.click('a'); 

// changing current window location
await page.evaluate(() => {
    window.location.href = 'https://redirect.de';
});

// correctly resolves to https://redirect.de/demo.html instead of https://start.de/demo.html
await page.click('a');

【问题讨论】:

  • 当您说“更改响应 URL”时,您是想重定向到不同的 URL,还是只是想 replace the state 欺骗浏览器?另外,你能添加你的fetch函数的来源吗?
  • 我试图替换状态。不幸的是 replaceState() 不起作用,因为它只适用于相同的来源。但我可以直接更改位置。感谢@GrantMiller 为我指明了正确的方向。

标签: javascript web-scraping puppeteer


【解决方案1】:

当您匹配要编辑其正文的请求时,只需获取 URL 并使用“node-fetch”或“请求”模块进行调用,当您收到正文编辑时,它会将其作为响应发送到原始请求。

例如:

const requestModule = require("request");
const cheerio = require("cheerio");

page.on("request", async (request) => {
  // Match the url that you want
  const isMatched = /page-12/.test(request.url());

  if (isMatched) {
    // Make a new call
    requestModule({
      url: request.url(),
      resolveWithFullResponse: true,
    })
      .then((response) => {
        const { body, headers, statusCode, statusMessage } = response;
        const contentType = headers["content-type"];

        // Edit body using cheerio module
        const $ = cheerio.load(body);
        $("a").each(function () {
          $(this).attr("href", "/fake_pathname");
        });

        // Send response
        request.respond({
          ok: statusMessage === "OK",
          status: statusCode,
          contentType,
          body: $.html(),
        });
      })
      .catch(() => request.continue());
  } else request.continue();
});

【讨论】:

  • 我收到requestModule(...).then is not a function
  • @NinoŠkopac 你安装了“请求”模块吗?
  • 当然。我的用例是更改 AJAX 调用的 URL,我通过在请求事件侦听器中直接编辑 request._url 甚至不调用 request.continue() 来做到这一点 - 这是它在最新 Puppeteer 版本中工作的唯一方法,否则,我不断收到“请求已被处理”错误,可能是由于第 3 方代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-22
  • 2020-09-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多