精品人伦一区二区三区蜜桃视频_日韩精品视频在线_www.色综合_久久久久久一区_aaaaaa黄色片_亚洲精品久久

使用puppeteer實現瀏覽器自動化

Puppeteer 是一個 Node 庫,它提供了一個高級 API 來通過 DevTools 協議控制 Chromium 或 Chrome。Puppeteer 默認以 headless 模式運行,但是可以通過修改配置文件運行“有頭”模式。

可以實現手動操作瀏覽器的所有功能

 

生成頁面 PDF。
抓取 SPA(單頁應用)并生成預渲染內容(即“SSR”(服務器端渲染))。
自動提交表單,進行 UI 測試,鍵盤輸入等。
創建一個時時更新的自動化測試環境。 使用最新的 JavaScript 和瀏覽器功能直接在最新版本的Chrome中執行測試。
捕獲網站的 timeline trace,用來幫助分析性能問題。
測試瀏覽器擴展。

 

安裝

安裝有瀏覽器的版本

npm i puppeteer

這個版本自帶Chromium瀏覽器,體積在300多M

2024.1更新

現在默認不會安裝Chromium,如果要安裝,運行上述代碼以后,再運行"node node_modules\puppeteer\install.js",如果提示沒有install.js,則運行"node_modules\puppeteer\install.mjs"

如果電腦有谷歌瀏覽器,可以使用下面代碼

npm i puppeteer-core

 

簡單使用

截圖

(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();
})();

 

 

 

模擬用戶登錄

(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'):在輸入框輸入文本

 

請求攔截

(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

 

獲取 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();
})();

 

植入 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 相關函數庫

 

抓取 iframe 中的元素

一個 Frame 包含了一個執行上下文(Execution Context),我們不能跨 Frame 執行函數,一個頁面中可以有多個 Frame,主要是通過 iframe 標簽嵌入的生成的。其中在頁面上的大部分函數其實是 page.mainFrame().xx 的一個簡寫,Frame 是樹狀結構,我們可以通過 frame.childFrames() 遍歷到所有的 Frame,如果想在其它 Frame 中執行函數必須獲取到對應的 Frame 才能進行相應的處理

以下是在登錄 188 郵箱時,其登錄窗口其實是嵌入的一個 iframe,以下代碼時我們在獲取 iframe 并進行登錄

(async () => {
    const browser = await puppeteer.launch({headless: false, slowMo: 50});
    const page = await browser.newPage();
    await page.goto('https://www.188.com');
    //點擊使用密碼登錄
    let passwordLogin = await page.waitForXPath('//*[@id="qcode"]/div/div[2]/a');
    await passwordLogin.click();
    for (const frame of page.mainFrame().childFrames()){
        //根據 url 找到登錄頁面對應的 iframe
        if (frame.url().includes('passport.188.com')){
            await frame.type('.dlemail', 'admin@admin.com');
            await frame.type('.dlpwd', '123456');
            await Promise.all([
                frame.click('#dologin'),
                page.waitForNavigation()
            ]);
            break;
        }
    }
    await page.close();
    await browser.close();
})();

文件的上傳和下載

在自動化測試中,經常會遇到對于文件的上傳和下載的需求,那么在 Puppeteer 中如何實現呢?

(async () => {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    //通過 CDP 會話設置下載路徑
    const cdp = await page.target().createCDPSession();
    await cdp.send('Page.setDownloadBehavior', {
        behavior: 'allow', //允許所有下載請求
        downloadPath: 'path/to/download'  //設置下載路徑
    });
    //點擊按鈕觸發下載
    await (await page.waitForSelector('#someButton')).click();
    //等待文件出現,輪訓判斷文件是否出現
    await waitForFile('path/to/download/filename');

    //上傳時對應的 inputElement 必須是<input>元素
    let inputElement = await page.waitForXPath('//input[@type="file"]');
    await inputElement.uploadFile('/path/to/file');
    browser.close();
})();

 

 

模擬選擇文件

點擊元素觸發選擇文件框,不會顯示,直接返回選擇文件

    const [fileChooser] = await Promise.all([
        page.waitForFileChooser(),
        page.click('#mydropzone'), // some button that triggers file selection
    ]);
    await fileChooser.accept(['D:\\down\\tmp.zip']);

 

 

跳轉新 tab 頁處理

在點擊一個按鈕跳轉到新的 Tab 頁時會新開一個頁面,這個時候我們如何獲取改頁面對應的 Page 實例呢?可以通過監聽 Browser 上的 targetcreated 事件來實現,表示有新的頁面創建:

let page = await browser.newPage();
await page.goto(url);
let btn = await page.waitForSelector('#btn');
//在點擊按鈕之前,事先定義一個 Promise,用于返回新 tab 的 Page 對象
const newPagePromise = new Promise(res => 
  browser.once('targetcreated', 
    target => res(target.page())
  )
);
await btn.click();
//點擊按鈕后,等待新tab對象
let newPage = await newPagePromise;

 

 

模擬不同的設備

Puppeteer 提供了模擬不同設備的功能,其中 puppeteer.devices 對象上定義很多設備的配置信息,這些配置信息主要包含 viewport 和 userAgent,然后通過函數 page.emulate 實現不同設備的模擬

const puppeteer = require('puppeteer');
const iPhone = puppeteer.devices['iPhone 6'];
puppeteer.launch().then(async browser => {
  const page = await browser.newPage();
  await page.emulate(iPhone);
  await page.goto('https://www.google.com');
  await browser.close();
});

 

其他信息

官方中文文檔

https://zhaoqize.github.io/puppeteer-api-zh_CN/#/

 

THE END
主站蜘蛛池模板: 羞羞色在线观看 | 日韩最新网址 | 91五月天| 狠狠久久综合 | 久久久久亚洲 | 亚洲国产精品久久久 | 拍真实国产伦偷精品 | 久久影音先锋 | 亚洲人成在线观看 | 欧美11一13sex性hd | 黄色成人在线观看 | 欧美成人精品在线 | 免费一区| 日韩国产欧美 | 欧美成人一级 | 91精品久久久久久综合五月天 | 国产亚洲欧美在线视频 | 伊人精品一区二区三区 | 国产三级在线观看播放 | 亚洲第一av | 蜜桃视频在线观看免费视频网站www | 久久91av| 精品国产一区二区三区久久久蜜月 | www.夜夜骑 | 日韩在线一区二区三区 | 国产目拍亚洲精品99久久精品 | 国产免费一区二区 | 视频在线观看亚洲 | 日本不卡一区二区三区 | 国产一区二区三区免费观看在线 | 自拍 亚洲 欧美 老师 丝袜 | 一区二区日韩 | 日韩精品免费在线观看 | 欧美国产日韩一区 | 黄色免费在线网址 | 国产精品精品久久久 | 精品国产免费一区二区三区演员表 | 欧美一级久久久猛烈a大片 日韩av免费在线观看 | 亚洲视频在线播放 | 成人免费观看视频 | 一级黄色片毛片 |