我正试图从一个网页上得到一个XHR的响应。我找到了
await page.waitForResponse(url);
或
await page.waitForResponse((res) => {
if (res.url() === myUrl) return true;
});
方法,但它总是对我试图得到的url响应超时。
但是,如果我
page.on('response', (res) => {
if (res.url() === myUrl) {
// do what I want with the response
}
})
找到正确的响应,我可以检索数据。
经过一些调试后,waitForResponse()似乎没有返回任何XHR /res。
有什么想法吗?
编辑:示例。在这种情况下,它需要使用puppeteer-extra-plugin-stealth
和puppeteer-extra
包,否则,该URL将返回状态代码'403':
import StealthPlugin from 'puppeteer-extra-plugin-stealth';
import UserAgent from 'user-agents';
import puppeteer from 'puppeteer-extra';
import { Page } from 'puppeteer';
const wantedUrl = 'https://www.nike.com.br/DataLayer/dataLayer';
const workingFunction = async (page: Page) => {
let reqCount = 0;
let resCount = 0;
page.on('request', req => {
reqCount++;
if (req.url() == wantedUrl) {
console.log('The request I need: ', req.url());
console.log(reqCount);
}
});
page.on('response', async res => {
resCount++;
if (res.url() == wantedUrl) {
console.log('The response I need:', await res.json());
console.log(resCount);
}
});
await page.goto('https://www.nike.com.br/tenis-nike-sb-dunk-low-pro-unissex-153-169-229-284741', {
timeout: 0,
});
};
const notWorkingFunction = async (page: Page) => {
let resCount = 0;
await page.goto('https://www.nike.com.br/tenis-nike-sb-dunk-low-pro-unissex-153-169-229-284741');
const res = await page.waitForResponse(
res => {
resCount++;
console.log(res.url());
console.log(resCount);
if (res.url() === wantedUrl) {
return true;
}
return false;
},
{ timeout: 0 }
);
return res;
};
(async () => {
puppeteer.use(StealthPlugin());
const browser = await puppeteer.launch({});
const page = await browser.newPage();
const userAgent = new UserAgent({ deviceCategory: 'desktop' });
await page.setUserAgent(userAgent.random().toString());
try {
// workingFunction(page);
const res = await notWorkingFunction(page);
} catch (e) {
console.log(e);
}
})();
发布于 2022-03-18 01:33:55
page.on
版本之所以工作,是因为它在执行导航之前设置了请求/响应处理程序。另一方面,waitForResponse
版本一直等到"load"
事件触发(page.goto()
的默认解析点),然后才开始跟踪调用page.waitForResponse
. MDN says of the load
event的响应。
整个页面加载完后会触发
load
事件,包括所有依赖的资源,如样式表和图像。这与DOMContentLoaded
形成了鲜明的对比,后者在加载页面DOM后立即触发,而无需等待资源完成加载。
基于此,我们可以推断,当load
事件触发和waitForResponse
函数最终开始侦听流量时,它已经错过了所需的响应,因此它只是等待了很久!
解决方案是在page.waitForResponse
调用之前(或者在同一时间)为goto
创建承诺,以便在启动导航时不会丢失任何通信量。
我还建议在"domcontentloaded"
调用中使用goto
。"domcontentloaded"
在木偶词典中使用不足--当你只是在寻找一种资源的时候,等待所有资源的到来是没有意义的。默认的"load"
或经常使用的"networkidleN"
设置更适合于用例,比如截取页面时,您希望整个页面看起来像用户所看到的那样。要明确的是,这不是解决问题的方法,只是一个优化,而且从文档中看也不太明显,这是合适的。
下面是一个很小的例子(我使用的是JS,而不是TS):
const puppeteer = require("puppeteer-extra"); // ^3.2.3
const StealthPlugin = require("puppeteer-extra-plugin-stealth"); // ^2.9.0
const UserAgent = require("user-agents"); // ^1.0.958
puppeteer.use(StealthPlugin());
let browser;
(async () => {
browser = await puppeteer.launch();
const [page] = await browser.pages();
const userAgent = new UserAgent({deviceCategory: "desktop"});
await page.setUserAgent(userAgent.random().toString());
const url = "https://www.nike.com.br/tenis-nike-sb-dunk-low-pro-unissex-153-169-229-284741";
const wantedUrl = "https://www.nike.com.br/DataLayer/dataLayer";
const [res] = await Promise.all([
page.waitForResponse(res => res.url() === wantedUrl, {timeout: 90000}),
page.goto(url, {waitUntil: "domcontentloaded"}),
]);
console.log(await res.json());
})()
.catch(err => console.error(err))
.finally(() => browser?.close())
;
https://stackoverflow.com/questions/71503214
复制相似问题