javascript - 如何加快傀儡师的速度?
问题描述
网页有一个按钮,puppeteer 必须在按钮变得可见时尽快单击该按钮。这个按钮并不总是可见的,它同时对每个人都可见。所以我必须不断刷新才能发现该按钮变得可见。我在下面写了这个脚本来做到这一点:
const browser = await puppeteer.launch({
headless: true,
args: ['--no-sandbox']
});
const page = await browser.newPage()
await page.setViewport({ width: 1920, height: 1080})
//I am calling my pageRefresher method here
async function pageRefresher(page,browser, url) {
try {
await page.goto(url, {waitUntil: 'networkidle2'})
try {
await page.waitForSelector('#ourButton', {timeout: 10});
await page.click('#ourButton')
console.log(`clicked!`)
await browser.close()
} catch (error) {
console.log('catch2 ' + counter + ' ' + error)
counter += 1
await pageRefresher(page, browser, url)
}
}catch (error) {
console.log('catch3' + error)
await browser.close();
}
}
如您所见,我的方法是递归的。它转到那个页面并寻找那个按钮。如果没有按钮,则它会再次调用自身以重做相同的工作,直到找到并单击该按钮。
实际上它现在运作良好。但它很慢。我正在运行此脚本,同时我在我的桌面 chrome 上打开同一页面,并且我开始手动刷新该页面。我总是赢,我总是在木偶师面前点击那个按钮。
我怎样才能加快这个过程?脚本不应该输给只有手动控制(如 F5 按钮)的人。
解决方案
脚本不应该输给只有手动控制(如 F5 按钮)的人。
发生这种情况是因为有时 puppeteer 遵循的规则比我们认为的“完全加载的网页”要严格得多。即使您作为人类可以决定您想要的元素是已经在 DOM 中(因为您看到该元素在那里)还是不在那里(因为您看不到它)。例如:即使背景图像仍在后台加载,您也会看到您的按钮不存在,或者 webfonts 仍未加载并且您有备用字体,但是 puppeteer 等待后台中的特定事件获得权限要么转到 catch 块(超时),要么抓取所需的元素(waitForSelector 成功)。这实际上取决于您访问的站点,但您可以加快识别所需元素的过程。
我给出了一些例子和想法,你可以如何做到这一点。
加快识别所需元素的方法
1.) 如果您的任务不需要每个网络连接,您可以通过替换waitUntil: 'networkidle2'
来加速页面加载,因为此事件通常发生得更早,并且在 DOM 中已经存在waitUntil: 'domcontentloaded'
时将被触发。#ourButton
page.goto
/的可能选项page.reload
:
load
- 考虑在load
事件触发时完成导航。domcontentloaded
- 考虑在DOMContentLoaded
事件触发时完成导航。networkidle0
500
- 当至少ms内没有超过 0 个网络连接时,考虑完成导航。networkidle2
500
- 考虑在至少ms内没有超过 2 个网络连接时完成导航。
你胜过剧本是因为networkidle2
太严格了。您可能需要此选项(例如,您正在访问单页应用程序或稍后您将需要来自 3rd 方网络连接的数据,例如 cookie),但如果不是强制性的,您将体验到更好的性能domcontentloaded
。
page.reload
2.) 您可以在循环中使用方法,而不是不断导航到相同的 url ,例如:
await page.goto(url, { waitUntil: 'domcontentloaded' })
let selectorExists = await page.$('#ourButton')
while (selectorExists === null) {
await page.reload({ waitUntil: 'domcontentloaded' })
console.log('reload')
selectorExists = await page.$('#ourButton')
}
await page.click('#ourButton')
// code goes on...
它的主要好处是您可以缩短和简化您的pageRefresher
功能。但是我也体验到了更好的性能(但是我没有进行基准测试,但我觉得它比重新打开页面要快得多)。
3.) 如果您的任务不需要每种资源类型,您还可以通过使用以下脚本禁用图像或 css 来加速页面加载:
await page.setRequestInterception(true)
page.on('request', (request) => {
if (request.resourceType() === 'image') request.abort()
else request.continue()
})
resourceType -s 的列表。
推荐阅读
- python - Django:删除 / 蛞蝓
- javascript - 如何将多维数组折叠成具有共同值的单个数组?
- python - pypyodbc 错误“未准备关联语句”
- html - Bootstrap 4 - 行和其他行之间的填充(768px 宽度)
- excel - 宏发送附加不同的文件到多个单独的电子邮件,vba
- ios - 当我们使用 CoreData 、 UserDefaults 、 Keychain
- ios - 如何解决应用验证“应用引用 Payload/MyApp.app/MyApp:_setAlwaysRunsAtForegroundPriority: 中的非公共选择器”?
- sql - 检查表中的重复记录
- java - Spring - 将 HttpHeaders 与 @RequestHeaders 一起使用时出现空指针异常
- r - R igraph with multiple edges