puppeteer pdf 未在 page.evaluate 中调用 setTimeout

问题描述 投票:0回答:1

我正在使用节点 v20.15.0 并有一个 puppeteer 文件,该文件会转到一个页面,该页面包含大约 200-300 个图像,当您向下滚动页面时,这些图像会延迟加载。

我创建了一些可以在浏览器中运行的js,如果我直接在浏览器中运行它,但是当我尝试在 page.evaluate 中运行相同的东西时,setTimeout 将被忽略。

基本上它会将页面滚动 500 像素,等待 1.25 秒让所有内容加载,然后使用 setTimeout 递归调用scroll_page 再次滚动。由于某种原因,它只是跳过 page.evaluate 内的 setTimeout 调用并退出 page.evaluate 并在此之后继续。

var browser;

var puppeteer_options = {
    headless: true, 
    ignoreHTTPSErrors: true, 
    args: ['--no-sandbox', '--disable-setuid-sandbox', '--single-process', '--no-zygote', '--disable-dev-shm-usage', '--shm-size=4gb'], 
    defaultViewport: {width: 1920, height: 1080},
}

browser = await puppeteer.launch(puppeteer_options);

var page = await browser.newPage();

var url = gp_args['url'];

await page.goto(url, {waitUntil: 'networkidle2'});  
await page.setDefaultNavigationTimeout(0)

//enable logging inside page.evaluate
    await page.exposeFunction('logInNodeJs', (value) => console.log(value));

//scroll down the page to get all html
    var retval = await page.evaluate(async () => {
        var retval = {}
        
        var el = document.documentElement

        logInNodeJs('scrollHeight: ' + el.scrollHeight)

        var cur_scroll_top = el.scrollTop
        logInNodeJs('cur_scroll_top start: ' + cur_scroll_top)
        var prev_scroll_top = cur_scroll_top
        logInNodeJs('prev_scroll_top start: ' + prev_scroll_top)

        scroll_page({
            el: el, 
            cur_scroll_top: cur_scroll_top, 
            prev_scroll_top: prev_scroll_top,
            safety: 0,
        })

        function scroll_page(options)
        {
            var el = options.el
            var cur_scroll_top = options.cur_scroll_top
            var prev_scroll_top = options.prev_scroll_top
            var safety = options.safety
            
            el.scrollTop += 500
            
            
            var cur_scroll_top = el.scrollTop
            logInNodeJs('cur_scroll_top: ' + cur_scroll_top + ' previous: ' + prev_scroll_top)
            
            
            if(cur_scroll_top == prev_scroll_top)
            {
                logInNodeJs('end reached!')
                //end_page_flag = true
            }
            else
            {
                var prev_scroll_top = cur_scroll_top
                logInNodeJs('prev_scroll_top: ' + prev_scroll_top)
                
                safety += 1
                if(safety < 20)
                {
                    setTimeout(function(){scroll_page({
                        el: el, 
                        cur_scroll_top: cur_scroll_top, 
                        prev_scroll_top: prev_scroll_top,
                        safety: safety,
                    })}, 1250)
                }
            }
        }
    
        
        return retval
    })

“安全”只是为了调试,试图防止无限循环的发生,也为了让它在测试时运行得更快。当我在浏览器中运行它时,没有使用安全性,并且它运行得很好。

还有其他方法可以在 page.evaluate 中递归调用scroll_page 吗?

javascript debugging puppeteer freeze
1个回答
0
投票

这里有很多问题,但我将添加一个简单的示例来说明您的主要问题。

evaluate
等待从回调返回的任何 Promise,但是如果您没有从回调返回 Promise,则它不会等待。
evaluate
不知道您触发了
setTimeout
——异步回调没有与主 Promise 链链接,因此无法等待它。

您可以将其与循环和承诺的超时连接起来:

import puppeteer from "puppeteer"; // ^22.7.1

const html = `<!DOCTYPE html><html><body>
<script>
for (let i = 0; i < 100; i++) {
  document.body.innerHTML += '<h1>hello world</h1>';
}
document.body.innerHTML += '<h1>BOTTOM</h1>';
</script>
</body></html>`;

let browser;
(async () => {
  browser = await puppeteer.launch({headless: false});
  const [page] = await browser.pages();

  // https://stackoverflow.com/a/60075804
  page.on('console', async e => {
    const args = await Promise.all(e.args().map(a => a.jsonValue()));
    console.log(...args);
  });
  await page.setContent(html);
  await page.evaluate(async () => {
    const doc = document.documentElement;

    for (;;) {
      console.log(doc.scrollTop);
      const lastScrollTop = doc.scrollTop;
      doc.scrollTop += 500;

      if (lastScrollTop === doc.scrollTop) {
        break;
      }

      await new Promise(r => setTimeout(r, 1250));
    }
  });

  console.log("done");
  await page.screenshot({path: "proof.png"});
})()
  .catch(err => console.error(err))
  .finally(() => browser?.close());

退一步讲,使用 Puppeteer 滚动可能会更好——只需按向下翻页键即可。

© www.soinside.com 2019 - 2024. All rights reserved.