Puppeteer--代碼示例(1)


1、截圖
使用 Puppeteer 既可以對某個頁面進行截圖,也可以對頁面中的某個元素進行截圖:
(async () => {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    //設置可視區域大小
    await page.setViewport({width: 1920, height: 800});
    await page.goto('https://youdata.163.com');
    //對整個頁面截圖
    await page.screenshot({
        path: './files/capture.png',  //圖片保存路徑
        type: 'png',
        fullPage: true //邊滾動邊截圖
        // clip: {x: 0, y: 0, width: 1920, height: 800}
    });
    //對頁面某個元素截圖
    let [element] = await page.$x('/html/body/section[4]/div/div[2]');
    await element.screenshot({
        path: './files/element.png'
    });
    await page.close();
    await browser.close();
})();
我們怎么去獲取頁面中的某個元素呢?
page.$('#uniqueId'):獲取某個選擇器對應的第一個元素
page.$$('div'):獲取某個選擇器對應的所有元素
page.$x('//img'):獲取某個 xPath 對應的所有元素
page.waitForXPath('//img'):等待某個 xPath 對應的元素出現
page.waitForSelector('#uniqueId'):等待某個選擇器對應的元素出現
 
2、模擬用戶登錄
(async () => {
    const browser = await puppeteer.launch({
        slowMo: 100,    //放慢速度
        headless: false,
        defaultViewport: {width: 1440, height: 780},
        ignoreHTTPSErrors: false, //忽略 https 報錯
        args: ['--start-fullscreen'] //全屏打開頁面
    });
    const page = await browser.newPage();
    await page.goto('https://demo.youdata.com');
    //輸入賬號密碼
    const uniqueIdElement = await page.$('#uniqueId');
    await uniqueIdElement.type('admin@admin.com', {delay: 20});
    const passwordElement = await page.$('#password', {delay: 20});
    await passwordElement.type('123456');
    //點擊確定按鈕進行登錄
    let okButtonElement = await page.$('#btn-ok');
    //等待頁面跳轉完成,一般點擊某個按鈕需要跳轉時,都需要等待 page.waitForNavigation() 執行完畢才表示跳轉成功
    await Promise.all([
        okButtonElement.click(),
        page.waitForNavigation()  
    ]);
    console.log('admin 登錄成功');
    await page.close();
    await browser.close();
})();
那么 ElementHandle 都提供了哪些操作元素的函數呢?
elementHandle.click():點擊某個元素
elementHandle.tap():模擬手指觸摸點擊
elementHandle.focus():聚焦到某個元素
elementHandle.hover():鼠標 hover 到某個元素上
elementHandle.type('hello'):在輸入框輸入文本
 
3、請求攔截
在有些場景下很有必要,攔截一下沒必要的請求以提高性能,我們可以在監聽 Page 的 request 事件,並進行請求攔截,前提是要開啟請求攔截 
(async () => {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    const blockTypes = new Set(['image', 'media', 'font']);
    await page.setRequestInterception(true); //開啟請求攔截
    page.on('request', request => {
        const type = request.resourceType();
        const shouldBlock = blockTypes.has(type);
        if(shouldBlock){
            //直接阻止請求
            return request.abort();
        }else{
            //對請求重寫
            return request.continue({
                //可以對 url,method,postData,headers 進行覆蓋
                headers: Object.assign({}, request.headers(), {
                    'puppeteer-test': 'true'
                })
            });
        }
    });
    await page.goto('https://demo.youdata.com');
    await page.close();
    await browser.close();
})();
那 page 頁面上都提供了哪些事件呢?
page.on('close') 頁面關閉
page.on('console') console API 被調用
page.on('error') 頁面出錯
page.on('load') 頁面加載完
page.on('request') 收到請求
page.on('requestfailed') 請求失敗
page.on('requestfinished') 請求成功
page.on('response') 收到響應
page.on('workercreated') 創建 webWorker
page.on('workerdestroyed') 銷毀 webWorker
 
4、獲取 WebSocket 響應
Puppeteer 目前沒有提供原生的用於處理 WebSocket 的 API 接口,但是我們可以通過更底層的 Chrome DevTool Protocol (CDP) 協議獲得
(async () => {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    //創建 CDP 會話
    let cdpSession = await page.target().createCDPSession();
    //開啟網絡調試,監聽 Chrome DevTools Protocol 中 Network 相關事件
    await cdpSession.send('Network.enable');
    //監聽 webSocketFrameReceived 事件,獲取對應的數據
    cdpSession.on('Network.webSocketFrameReceived', frame => {
        let payloadData = frame.response.payloadData;
        if(payloadData.includes('push:query')){
            //解析payloadData,拿到服務端推送的數據
            let res = JSON.parse(payloadData.match(/\{.*\}/)[0]);
            if(res.code !== 200){
                console.log(`調用websocket接口出錯:code=${res.code},message=${res.message}`);
            }else{
                console.log('獲取到websocket接口數據:', res.result);
            }
        }
    });
    await page.goto('https://netease.youdata.163.com/dash/142161/reportExport?pid=700209493');
    await page.waitForFunction('window.renderdone', {polling: 20});
    await page.close();
    await browser.close();
})();
 
5、植入 javascript 代碼
Puppeteer 最強大的功能是,你可以在瀏覽器里執行任何你想要運行的 javascript 代碼,下面是我在爬 188 郵箱的收件箱用戶列表時,發現每次打開收件箱再關掉都會多處一個 iframe 來,隨着打開收件箱的增多,iframe 增多到瀏覽器卡到無法運行,所以我在爬蟲代碼里加了刪除無用 iframe 的腳本:
(async () => {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto('https://webmail.vip.188.com');
    //注冊一個 Node.js 函數,在瀏覽器里運行
    await page.exposeFunction('md5', text =>
        crypto.createHash('md5').update(text).digest('hex')
    );
    //通過 page.evaluate 在瀏覽器里執行刪除無用的 iframe 代碼
    await page.evaluate(async () =>  {
        let iframes = document.getElementsByTagName('iframe');
        for(let i = 3; i <  iframes.length - 1; i++){
            let iframe = iframes[i];
            if(iframe.name.includes("frameBody")){
                iframe.src = 'about:blank';
                try{
                    iframe.contentWindow.document.write('');
                    iframe.contentWindow.document.clear();
                }catch(e){}
                //把iframe從頁面移除
                iframe.parentNode.removeChild(iframe);
            }
        }
        //在頁面中調用 Node.js 環境中的函數
        const myHash = await window.md5('PUPPETEER');
        console.log(`md5 of ${myString} is ${myHash}`);
    });
    await page.close();
    await browser.close();
})();
有哪些函數可以在瀏覽器環境中執行代碼呢?
page.evaluate(pageFunction[, ...args]):在瀏覽器環境中執行函數
page.evaluateHandle(pageFunction[, ...args]):在瀏覽器環境中執行函數,返回 JsHandle 對象
page.$$eval(selector, pageFunction[, ...args]):把 selector 對應的所有元素傳入到函數並在瀏覽器環境執行
page.$eval(selector, pageFunction[, ...args]):把 selector 對應的第一個元素傳入到函數在瀏覽器環境執行
page.evaluateOnNewDocument(pageFunction[, ...args]):創建一個新的 Document 時在瀏覽器環境中執行,會在頁面所有腳本執行之前執行
page.exposeFunction(name, puppeteerFunction):在 window 對象上注冊一個函數,這個函數在 Node 環境中執行,有機會在瀏覽器環境中調用 Node.js 相關函數庫
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM