我的Node.js puppeteer脚本成功填写了一个表单,但是在返回修改后的页面内容之前,该页面仅在 some 个元素上接受一次“ click”事件。这是脚本:
const fetchContracts = async (url) => {
const browser = await pupeteer.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox']});
const page = await browser.newPage();
const pendingXHR = new PendingXHR(page);
await page.goto(url, { waitUntil: 'networkidle2' });
await Promise.all([
page.click("#agree_statement"),
page.waitForNavigation()
]);
await page.click(".form-check-input");
await Promise.all([
page.click(".btn-primary"),
page.waitForNavigation()
]);
/// MY PROBLEM OCCURS HERE
/// Sometimes these clicks do not register....
await page.click('#filedReports th:nth-child(5)')
await pendingXHR.waitForAllXhrFinished();
await page.click('#filedReports th:nth-child(5)');
await pendingXHR.waitForAllXhrFinished();
/// And my bot skips directly here....
let html = await page.content();
await page.close();
await browser.close();
return html;
}
“ pendingXHR”模块是一个导入,我从this库的代码中拉入了顶部:
const { PendingXHR } = require('pending-xhr-puppeteer');
该脚本可以在我的本地计算机上运行,并且在我将该脚本上载到Digital Ocean时可以运行 some 。根据我正在爬网的页面,这些单击会启动XHR请求,而我正试图等待这些请求。这是证明:
所以我的问题是:
为什么在从页面中提取html然后返回html之前,即使我正在等待它们并等待XHR请求,这些点击还是会不注册?以及为什么与此不一致(有时在 处注册了点击,有时却没有注册)?
感谢您的帮助。
答案 0 :(得分:1)
您是否尝试执行以下解决方法:
await page.waitfor(1000);// this line will wait for 1 Sec
这样,您可以确定它已加载 更好的方法是将page.click在Promise.all中。
await Promise.all([
await page.click('#filedReports th:nth-child(5)'),
await pendingXHR.waitForAllXhrFinished()
]);
PS:您缺少分号
/// MY PROBLEM OCCURS HERE
/// Sometimes these clicks do not register....
\/
await page.click('#filedReports th:nth-child(5)')
await pendingXHR.waitForAllXhrFinished(); /\
await page.click('#filedReports th:nth-child(5)');
await pendingXHR.waitForAllXhrFinished();
答案 1 :(得分:1)
简短的回答:单击将导致AJAX请求延迟,因此pendingXHR.waitForAllXhrFinished()
将立即解决,因为在执行该功能时没有任何请求发生。请改用page.waitForResponse('.../data/')
。
您期望发生以下事件:
pendingXHR.waitForAllXhrFinished()
被执行pendingXHR.waitForAllXhrFinished()
解决page.content()
被执行问题是您使用的waits for the currently pending requests库(PendingXHR)会在解析后立即解析。在我能想到的两种情况下,这行不通:
1。 AJAX请求是异步启动的
在这种情况下,事件的顺序如下:
pendingXHR.waitForAllXhrFinished()
被执行pendingXHR.waitForAllXhrFinished()
立即解决(因为没有请求)page.content()
被执行(为时过早!) 2。 UI会异步修改表格
在这种情况下,事件的顺序如下:
pendingXHR.waitForAllXhrFinished()
被执行pendingXHR.waitForAllXhrFinished()
解决page.content()
(为时过早!) 发生不一致的情况是因为有时事件可能以正确的顺序发生,因为在这种情况下,毫秒可以决定先发生什么。
如果不查看页面代码,就无法确定是哪种情况(实际上可能是两种情况),但是我猜这是第一种情况,因为我完全可以看到表库在等待任何情况双击/拖动/等。在发出AJAX请求之前发生。
可以使用page.waitForResponse
而不是pendingXHR.waitForAllXhrFinished
来解决第一个问题,因为这可以确保对data/
的请求确实发生了。
解决第二种情况(如果需要)并不是那么简单,但是可以通过使用page.waitFor(10)
引入固定的等待时间来完成。
通过修复两种情况,新代码如下:
await Promise.all([ // wait for the response to happen and click
page.waitForResponse('.../data/'), // use the actual URL here
page.click('...'),
]);
await page.waitFor(10); // wait for any asynchronous rerenders that might happen
let html = await page.content();