使用无头 Chrome 以编程方式捕获 AJAX 流量
Programmatically capturing AJAX traffic with headless Chrome
Chrome 正式支持 运行 无头模式浏览器(包括通过 Puppeteer API and/or CRI 库进行编程控制)。
我搜索了整个文档,但我还没有找到如何以编程方式从实例中捕获 AJAX 流量(即从代码启动 Chrome 的实例,导航到一个页面,并访问后台 response/request 调用和原始数据(全部来自代码,未使用开发人员工具或扩展)。
您有任何建议或示例来详细说明如何实现这一目标吗?谢谢!
我终于找到了如何做我想做的事。它可以用 chrome-remote-interface
(CRI) 和 node.js
来完成。我附上了所需的最少代码。
const CDP = require('chrome-remote-interface');
(async function () {
// you need to have a Chrome open with remote debugging enabled
// ie. chrome --remote-debugging-port=9222
const protocol = await CDP({port: 9222});
const {Page, Network} = protocol;
await Page.enable();
await Network.enable(); // need this to call Network.getResponseBody below
Page.navigate({url: 'http://localhost/'}); // your URL
const onDataReceived = async (e) => {
try {
let response = await Network.getResponseBody({requestId: e.requestId})
if (typeof response.body === 'string') {
console.log(response.body);
}
} catch (ex) {
console.log(ex.message)
}
}
protocol.on('Network.dataReceived', onDataReceived)
})();
更新
正如@Alejandro 在评论中指出的那样,resourceType
是一个函数,return 值是小写的
page.on('request', request => {
if (request.resourceType() === 'xhr')
// do something
});
原回答
Puppeteer 的 API 让这一切变得非常简单:
page.on('request', request => {
if (request.resourceType === 'XHR')
// do something
});
您也可以使用 setRequestInterception
拦截请求,但如果您不打算修改请求,则本例中不需要它。
有一个 example of intercepting image requests 可以改编。
resourceType
被定义为 here.
Puppeteer 的侦听器可以帮助您通过 response
和 request
事件捕获 xhr 响应。
您应该先检查 request.resourceType()
是 xhr
还是 fetch
。
listener = page.on('response', response => {
const isXhr = ['xhr','fetch'].includes(response.request().resourceType())
if (isXhr){
console.log(response.url());
response.text().then(console.log)
}
})
const browser = await puppeteer.launch();
const page = await browser.newPage();
const pageClient = page["_client"];
pageClient.on("Network.responseReceived", event => {
if (~event.response.url.indexOf('/api/chart/rank')) {
console.log(event.response.url);
pageClient.send('Network.getResponseBody', {
requestId: event.requestId
}).then(async response => {
const body = response.body;
if (body) {
try {
const json = JSON.parse(body);
}
catch (e) {
}
}
});
}
});
await page.setRequestInterception(true);
page.on("request", async request => {
request.continue();
});
await page.goto('http://www.example.com', { timeout: 0 });
Chrome 正式支持 运行 无头模式浏览器(包括通过 Puppeteer API and/or CRI 库进行编程控制)。
我搜索了整个文档,但我还没有找到如何以编程方式从实例中捕获 AJAX 流量(即从代码启动 Chrome 的实例,导航到一个页面,并访问后台 response/request 调用和原始数据(全部来自代码,未使用开发人员工具或扩展)。
您有任何建议或示例来详细说明如何实现这一目标吗?谢谢!
我终于找到了如何做我想做的事。它可以用 chrome-remote-interface
(CRI) 和 node.js
来完成。我附上了所需的最少代码。
const CDP = require('chrome-remote-interface');
(async function () {
// you need to have a Chrome open with remote debugging enabled
// ie. chrome --remote-debugging-port=9222
const protocol = await CDP({port: 9222});
const {Page, Network} = protocol;
await Page.enable();
await Network.enable(); // need this to call Network.getResponseBody below
Page.navigate({url: 'http://localhost/'}); // your URL
const onDataReceived = async (e) => {
try {
let response = await Network.getResponseBody({requestId: e.requestId})
if (typeof response.body === 'string') {
console.log(response.body);
}
} catch (ex) {
console.log(ex.message)
}
}
protocol.on('Network.dataReceived', onDataReceived)
})();
更新
正如@Alejandro 在评论中指出的那样,resourceType
是一个函数,return 值是小写的
page.on('request', request => {
if (request.resourceType() === 'xhr')
// do something
});
原回答
Puppeteer 的 API 让这一切变得非常简单:
page.on('request', request => {
if (request.resourceType === 'XHR')
// do something
});
您也可以使用 setRequestInterception
拦截请求,但如果您不打算修改请求,则本例中不需要它。
有一个 example of intercepting image requests 可以改编。
resourceType
被定义为 here.
Puppeteer 的侦听器可以帮助您通过 response
和 request
事件捕获 xhr 响应。
您应该先检查 request.resourceType()
是 xhr
还是 fetch
。
listener = page.on('response', response => {
const isXhr = ['xhr','fetch'].includes(response.request().resourceType())
if (isXhr){
console.log(response.url());
response.text().then(console.log)
}
})
const browser = await puppeteer.launch();
const page = await browser.newPage();
const pageClient = page["_client"];
pageClient.on("Network.responseReceived", event => {
if (~event.response.url.indexOf('/api/chart/rank')) {
console.log(event.response.url);
pageClient.send('Network.getResponseBody', {
requestId: event.requestId
}).then(async response => {
const body = response.body;
if (body) {
try {
const json = JSON.parse(body);
}
catch (e) {
}
}
});
}
});
await page.setRequestInterception(true);
page.on("request", async request => {
request.continue();
});
await page.goto('http://www.example.com', { timeout: 0 });