为了账号安全,请及时绑定邮箱和手机立即绑定

如何加快傀儡师的速度?

如何加快傀儡师的速度?

POPMUISE 2022-11-11 13:26:42
网页有一个按钮,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 hereasync 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 按钮)的人。
查看完整描述

3 回答

?
婷婷同学_

TA贡献1844条经验 获得超8个赞

脚本不应该输给只有手动控制(如 F5 按钮)的人。

发生这种情况是因为有时 puppeteer 遵循的规则比我们认为的“完全加载的网页”要严格得多。即使您作为人类可以决定您想要的元素是已经在 DOM 中(因为您看到该元素在那里)还是不在那里(因为您看不到它)。例如:即使背景图像仍在后台加载,您也会看到您的按钮不存在,或者 webfonts 仍未加载并且您有备用字体,但 puppeteer 等待后台的特定事件获得权限要么转到 catch 块(超时),要么抓取所需的元素(waitForSelector 成功)。这实际上取决于您访问的站点,但您可以加快识别所需元素的过程。

我给出了一些例子和想法,你可以如何做到这一点。


加快识别所需元素的方法

1.) 如果您的任务不需要每个网络连接,您可以通过替换waitUntil: 'networkidle2'来加快页面加载速度,因为此事件通常发生得更早,并且在 DOM 中已经存在waitUntil: 'domcontentloaded'时将被触发。#ourButton

page.goto/的可能选项page.reload

  • load- 考虑在load事件触发时完成导航。

  • domcontentloaded- 考虑在DOMContentLoaded事件触发时完成导航。

  • networkidle0500- 当至少ms内没有超过 0 个网络连接时,考虑完成导航。

  • networkidle2500- 考虑在至少ms内没有超过 2 个网络连接时完成导航。

你胜过剧本是因为networkidle2太严格了。您可能需要此选项(例如,您正在访问单页应用程序或稍后您将需要来自 3rd 方网络连接的数据,例如 cookie),但如果不是强制性的,您将体验到更好的性能domcontentloaded

page.reload2.) 您可以在循环中使用方法,而不是不断导航到相同的 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()

})


查看完整回答
反对 回复 2022-11-11
?
翻翻过去那场雪

TA贡献2065条经验 获得超14个赞

尝试不等待 goto:


page.goto(url) // no await because it doesn't have to resolve fully

await page.waitForSelector('#ourButton') // await this because we need it to be there

有些人为此喜欢 Promise.race,但这种方式更简单


查看完整回答
反对 回复 2022-11-11
?
三国纷争

TA贡献1804条经验 获得超7个赞

使用该page.$eval()方法,您可以像这样短:


await page.goto(url);

page.$eval('button-selector', button => button.click());

通过这样做,您可以将搜索所需按钮并单击它的操作组合成一行。您必须等待page.goto()说明,因为您需要在使用前完全加载页面page.$eval()


第一个参数是您需要用来在您的情况下获得按钮的选择器。HTMLElement


这HTMLElement将通过在将其作为参数传递给以下参数中定义的函数之前document.querySelector()使用提供的选择器whitin 页面上下文运行来检索。


第二个参数是要在页面上下文中执行的函数,它将HTMLElement匹配前一个选择器作为参数


如果没有找到与提供的选择器匹配的元素,该page.$eval()指令将引发错误。


您可以通过两种方式解决此问题:


通过在使用该方法HTMLElement之前测试您是否存在来防止错误触发。page.$eval()

await page.goto(url);

if (await page.$('button-selector') != null) // await because page.$() returns a promise

    page.$eval('button-selector', button => button.click());


仅使用的替代方法page.$()是:


await page.goto(url);

if ((button = await page.$('button-selector')) != null)    

        button.click();

请务必将条件的左侧部分封装在内部,( )否则button值将是trueor false。


发生错误时捕获错误:

您可以使用它来确定何时重新加载页面

await page.goto(url);

page.$eval('button-selector', button => button.click())

    .catch((err) => {

        // log the error here or do some other stuff

    });


经过一些测试,看起来我们不能使用try ... catch块来捕获page.$eval()方法上的错误,所以上面的例子是这样做的唯一方法。


有关更多信息,您可以查看 puppeteer API 页面的page.$eval()


查看完整回答
反对 回复 2022-11-11
  • 3 回答
  • 0 关注
  • 102 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号