首页 > 解决方案 > 木偶师一张一张的给元素子截图

问题描述

我正在尝试使用 puppeteer 获取网页的屏幕截图,我想通过使用以下类型的数据一个接一个地显示每个元素来逐个截取每个元素:

p (visibility:hidden)
ol
 li (visibility:hidden)
 li (visibility:hidden)

那样的话,我把p改成可见,截图,进入ol,设置li为可见,截图,等等。

我几乎可以使它与以下功能一起使用:


    const browser = await puppeteer.launch({args: ['--window-size=1920,1080','--no-sandbox', '--disable-setuid-sandbox']});
    const page = await browser.newPage();
    await page.goto('http://mywebsite',{waitUntil: 'networkidle2'});
    const div = await page.$("[id^=t1_]");
    const bbox = await div.boundingBox();


    let nbElem=await page.evaluate(() => {
        return document.querySelector('[class$=-root]').childElementCount
    });

    for(let i=1;i<=nbElem;i++){
        await page.evaluate((i) => {
            let elem = document.querySelector('[class$=-root] > *:nth-child('+i+')')
            if(elem.tagName==="P"){
                elem.style.visibility = 'visible';
                div.screenshot({path: "test"+i+"0.png",clip: {x: bbox.x,y:bbox.y,width: bbox.width,height: bbox.height}})
            }else{
                let j=0;
                let children = elem.children;
                for(let z of children){
                    z.style.visibility='visible';
                    div.screenshot({path: "test"+i+(j++)+".png",clip: {x: bbox.x,y:bbox.y,width: bbox.width,height: bbox.height}})
                }
            }
        },i);
//        await div.screenshot({path: "test"+i+(j++)+".png",clip: {x: bbox.x,y:bbox.y,width: Math.min(bbox.width, page.viewport().width),height: Math.min(bbox.height, page.viewport().height),}})
    }

进入await page.evaluate 后,我无法调用div.screenshot,出现以下错误: (node:26413) UnhandledPromiseRejectionWarning: Error: Evaluation failed: TypeError: div.screenshot is not a function

我确实尝试使用await调用它,但又遇到了另一个错误:

await div.screenshot({path: "test"+i+"0.png",clip: {x: bbox.x,y:bbox.y,width: bbox.width,height: bbox.height}})
                ^^^^^

SyntaxError: await is only valid in async function

而在page.evaluate之后,我可以,但在这种情况下,我错过了每个 li 的“揭幕”。

在那种情况下,我绝对不知道我在用 await 和 async 的东西做什么......

我不明白如何将匿名函数转换为异步函数以适应 page.evaluate。

我应该如何在 page.evaluate 中调用 div.screenshot ?

谢谢

标签: javascriptasync-awaitpuppeteer

解决方案


实际上,您对page.evaluate真正的手段感到困惑。该page.evaluate方法是在 Chromium puppeteer 的浏览器中运行脚本的 puppeteer 函数,而不是在 puppeteer 本身中。两者都是不同的上下文,都有自己的环境,你不能共享变量或常量。

而且您不能在其中调用 div.screenshotpage.evaluate

我尝试制作一些 HTML 来重现您的案例,coba.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body class="body-root">
    <p style="visibility:hidden">Hallo</p>
    <p style="visibility:hidden">World</p>
    <p style="visibility:hidden">How Are You?</p>
    <ol>
        <li style="visibility:hidden">1</li>
        <li style="visibility:hidden">3</li>
        <li style="visibility:hidden">5</li>
        <li style="visibility:hidden">7</li>
        <li style="visibility:hidden">9</li>
        <li style="visibility:hidden">A</li>
    </ol>
    <ol>
        <li style="visibility:hidden">2</li>
        <li style="visibility:hidden">4</li>
        <li style="visibility:hidden">6</li>
        <li style="visibility:hidden">8</li>
        <li style="visibility:hidden">10</li>
        <li style="visibility:hidden">B</li>
    </ol>
</body>
</html>

给你。

const puppeteer = require ('puppeteer')

;(async () => {

    const browser = await puppeteer.launch({
        headless: false,
        devtools: true,
        args: [
            '--window-size=1920,1080',
            '--no-sandbox',
            '--disable-setuid-sandbox'
        ]
    })

    const [page] = await browser.pages ()

    await page.goto('http://localhost/testing/coba.html',{ waitUntil: 'networkidle0' })

    await page.evaluate ( () => {

        document.querySelector('[class$="-root"]').childNodes.forEach( element => {
            if (typeof (element.tagName) !== 'undefined'){

                if (element.tagName === 'P') {
                    element.style.visibility = 'visible'
                } else {
                    element.childNodes.forEach( elemChild => {
                        if (typeof (elemChild.tagName) !== 'undefined'){
                            elemChild.style.visibility = 'visible'
                        }
                    })
                }
            }
        })

    })


    const pElements = await page.$$('[class$="-root"] > p')
    for ( let num = 0; num < pElements.length; num++ ) {

        var pElementBoundingBox = await pElements[num].boundingBox ()
        pElements[num].screenshot ({ path: `p_elem_${num+1}.png`, clip: pElementBoundingBox })

    }

    const olElements = await page.$$('[class$="-root"] > ol')
    for ( let numol = 0; numol < olElements.length; numol++ ) {

        var liElements = await olElements[numol].$$('li')
        for ( let numli = 0; numli < liElements.length; numli++ ) {

            var liElementBoundingBox = await liElements[numli].boundingBox ()
            liElements[numli].screenshot ({ path: `li_elem_${numol+1}_${numli+1}.png`, clip: liElementBoundingBox })

        }
    }

})()

推荐阅读