Как собрать все сетевые запросы и полные данные ответов при загрузке страницы в Chrome?

Используя Puppeteer, я хотел бы загрузить URL-адрес в Chrome и получить следующую информацию:

  • URL запроса
  • заголовки запроса
  • запросить данные
  • текст заголовков ответов (включая дубликаты заголовков, такие как set-cookie)
  • переданный размер ответа (т.е. сжатый размер)
  • полное тело ответа

Захват полного тела ответа - вот что вызывает у меня проблемы.

Вещи, которые я пробовал:

  • Получение содержимого ответа с помощью response.buffer - это не работает, если есть перенаправления в любой точке, так как буферы стираются при навигации
  • перехват запросов и использование getResponseBodyForInterception - это означает, что я больше не могу получить доступ к encodedLength, и у меня также были проблемы с получением правильных заголовков запросов и ответов в некоторых случаях
  • Использование локального прокси-сервера работает, но это значительно замедляет время загрузки страницы (а также меняет поведение, например, при ошибках сертификата)

В идеале решение должно оказывать лишь незначительное влияние на производительность и не иметь функциональных отличий от обычной загрузки страницы. Я также хотел бы избежать разветвления Chrome.

Ответ 1

Вы можете включить перехват запроса с помощью page.setRequestInterception() для каждого запроса, а затем внутри page.on('request') вы можете использовать модуль request-promise-native чтобы выступать в роли посредника для сбора данных ответа прежде чем продолжить запрос с request.continue() в Puppeteer.

Вот полный рабочий пример:

'use strict';

const puppeteer = require('puppeteer');
const request_client = require('request-promise-native');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  const result = [];

  await page.setRequestInterception(true);

  page.on('request', request => {
    request_client({
      uri: request.url(),
      resolveWithFullResponse: true,
    }).then(response => {
      const request_url = request.url();
      const request_headers = request.headers();
      const request_post_data = request.postData();
      const response_headers = response.headers;
      const response_size = response_headers['content-length'];
      const response_body = response.body;

      result.push({
        request_url,
        request_headers,
        request_post_data,
        response_headers,
        response_size,
        response_body,
      });

      console.log(result);
      request.continue();
    }).catch(error => {
      console.error(error);
      request.abort();
    });
  });

  await page.goto('https://example.com/', {
    waitUntil: 'networkidle0',
  });

  await browser.close();
})();

Ответ 2

Я бы посоветовал вам найти быстрый прокси-сервер, который позволяет записывать логи запросов вместе с актуальным контентом.

Цель установки - позволить прокси-серверу просто написать файл журнала, а затем проанализировать журнал в поисках необходимой информации.

Не перехватывать запросы во время работы прокси (это приведет к замедлению)

Проблемы с производительностью (с настройкой прокси-сервера в качестве регистратора), с которыми вы можете столкнуться, в основном связаны с поддержкой TLS, пожалуйста, обратите внимание, чтобы разрешить быстрое рукопожатие TLS, протокол HTTP2 в настройке прокси

Например, тесты Squid показывают, что он способен обрабатывать сотни RPS, которых должно быть достаточно для тестирования.

Ответ 3

Решение только для кукольников

Это может быть сделано с одним кукловодом. Проблема, которую вы описываете, заключается в том, что response.buffer очищается при навигации, можно обойти, обрабатывая каждый запрос один за другим.

Как это устроено

Код ниже использует page.setRequestInterception для перехвата всех запросов. Если в настоящее время запрос обрабатывается/находится в ожидании, новые запросы помещаются в очередь. Затем response.buffer() можно использовать без проблем, поскольку другие запросы могут асинхронно очищать буфер, поскольку параллельных запросов нет. Как только обработанный в настоящее время запрос/ответ будет обработан, будет обработан следующий запрос.

Код

const puppeteer = require('puppeteer');

(async () => {
    const browser = await puppeteer.launch();
    const [page] = await browser.pages();

    const results = []; // collects all results

    let paused = false;
    let pausedRequests = [];

    const nextRequest = () => { // continue the next request or "unpause"
        if (pausedRequests.length === 0) {
            paused = false;
        } else {
            // continue first request in "queue"
            (pausedRequests.shift())(); // calls the request.continue function
        }
    };

    await page.setRequestInterception(true);
    page.on('request', request => {
        if (paused) {
            pausedRequests.push(() => request.continue());
        } else {
            paused = true; // pause, as we are processing a request now
            request.continue();
        }
    });

    page.on('requestfinished', async (request) => {
        const response = await request.response();

        const responseHeaders = response.headers();
        let responseBody;
        if (request.redirectChain().length === 0) {
            // body can only be access for non-redirect responses
            responseBody = await response.buffer();
        }

        const information = {
            url: request.url(),
            requestHeaders: request.headers(),
            requestPostData: request.postData(),
            responseHeaders: responseHeaders,
            responseSize: responseHeaders['content-length'],
            responseBody,
        };
        results.push(information);

        nextRequest(); // continue with next request
    });
    page.on('requestfailed', (request) => {
        // handle failed request
        nextRequest();
    });

    await page.goto('...', { waitUntil: 'networkidle0' });
    console.log(results);

    await browser.close();
})();

Ответ 4

перейдите в Chrome, нажмите F12, затем перейдите на вкладку "сеть", вы можете увидеть там все http-запросы, которые отправляет веб-сайт, вы сможете увидеть детали, которые вы упомянули.

Ответ 5

Я бы предложил использовать инструмент, а именно " скрипач ". Он будет захватывать всю информацию, которую вы упомянули при загрузке URL-адреса.