Как собрать все сетевые запросы и полные данные ответов при загрузке страницы в 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-адреса.