資源鏈接
Puppeteer官方文檔:https://github.com/GoogleChrome/puppeteer
puppeteer社區:https://slack.com/
安裝
// 安裝puppeteer cnpm i puppeteer
// 安裝puppeteer-core cnpm i puppeteer-core
常用方法或屬性
1. puppeteer.launch([options])
//Puppeteer 模塊提供了一種啟動 Chromium 實例的方法。 下面就是使用 Puppeteer 進行自動化的一個典型示例: const puppeteer = require('puppeteer'); puppeteer.launch().then(async browser => { const page = await browser.newPage(); await page.goto('https://www.google.com'); // 其他操作... await browser.close(); });
2.Browser
當 Puppeteer 連接到一個 Chromium 實例的時候會通過 puppeteer.launch 或 puppeteer.connect 創建一個 Browser 對象。
//下面是使用 Browser 創建 Page 的例子 const puppeteer = require('puppeteer'); puppeteer.launch().then(async browser => { // 存儲節點以便能重新連接到 Chromium const browserWSEndpoint = browser.wsEndpoint(); // 從 Chromium 斷開和 puppeteer 的連接 browser.disconnect(); // 使用節點來重新建立連接 const browser2 = await puppeteer.connect({browserWSEndpoint}); // 關閉 Chromium await browser2.close(); });
//一個斷開連接和重連到 Browser 的例子: const puppeteer = require('puppeteer'); puppeteer.launch().then(async browser => { // 存儲節點以便能重新連接到 Chromium const browserWSEndpoint = browser.wsEndpoint(); // 從 Chromium 斷開和 puppeteer 的連接 browser.disconnect(); // 使用節點來重新建立連接 const browser2 = await puppeteer.connect({browserWSEndpoint}); // 關閉 Chromium await browser2.close(); });
3.Page
Page 提供操作一個 tab 頁或者 extension background page 的方法。一個 Browser 實例可以有多個 Page 實例。
下面的例子創建一個 Page 實例,導航到一個 url ,然后保存截圖:
const puppeteer = require('puppeteer'); puppeteer.launch().then(async browser => { const page = await browser.newPage(); await page.goto('https://example.com'); await page.screenshot({path: 'screenshot.png'}); await browser.close(); });
4.Keyboard
Keyboard 提供一個接口來管理虛擬鍵盤. 高級接口為 keyboard.type, 其接收原始字符, 然后在你的頁面上生成對應的 keydown, keypress/input, 和 keyup 事件.
為了更精細的控制(虛擬鍵盤), 你可以使用 keyboard.down, keyboard.up 和 keyboard.sendCharacter 來手動觸發事件, 就好像這些事件是由真實的鍵盤生成的.
//持續按下 Shift 來選擇一些字符串並且刪除的例子: await page.keyboard.type('Hello World!'); await page.keyboard.press('ArrowLeft'); await page.keyboard.down('Shift'); for (let i = 0; i < ' World'.length; i++) await page.keyboard.press('ArrowLeft'); await page.keyboard.up('Shift'); await page.keyboard.press('Backspace'); // 結果字符串最終為 'Hello!'
//按下A的例子 await page.keyboard.down('Shift'); await page.keyboard.press('KeyA'); await page.keyboard.up('Shift');
5. Mouse
Mouse 類在相對於視口左上角的主框架 CSS 像素中運行。
每個 page 對象都有它自己的 Mouse 對象,使用見 page.mouse。
// 使用 ‘page.mouse’ 追蹤 100x100 的矩形。 await page.mouse.move(0, 0); await page.mouse.down(); await page.mouse.move(0, 100); await page.mouse.move(100, 100); await page.mouse.move(100, 0); await page.mouse.move(0, 0); await page.mouse.up();
實戰
實戰01:跳轉指定頁面
源碼:跳轉到百度首頁
const puppeteer=require('puppeteer'); (async ()=>{ const browser = await puppeteer.launch({headless:false,defaultViewport:{width:1000,height:800}}); const page= await browser.newPage(); await page.goto("https://www.baidu.com"); })();
實戰02:輸入文本與元素點擊
代碼:在百度中搜索
const puppeteer=require('puppeteer'); (async ()=>{ const browser = await puppeteer.launch({headless:false,defaultViewport:{width:1000,height:800}}); const page= await browser.newPage(); await page.goto("https://www.baidu.com"); //跳轉頁面 const input_text= await page.$("#kw"); //獲取百度首頁的搜索框。page.$()用來查找元素 await input_text.type("Hello Word!"); //type()輸入內容 const btn_click=await page.$("#su"); //獲取百度首頁的搜索按鈕。 await btn_click.click(); //點擊搜索按鈕。 })();
實戰03:獲取文本元素值
源碼:獲取百度詞條的值
const puppeteer=require('puppeteer'); (async ()=>{ const browser = await puppeteer.launch({headless:false,defaultViewport:{width:1000,height:800}}); const page= await browser.newPage(); await page.goto("https://www.baidu.com"); //跳轉頁面 const input_text= await page.$("#kw"); //獲取百度首頁的搜索框。page.$()用來查找元素 await input_text.type("Hello Word!"); //type()輸入內容 const btn_click=await page.$("#su"); //獲取百度首頁的搜索按鈕。 await btn_click.click(); //點擊搜索按鈕。 await page.waitFor('div#content_left > .result-op.c-container.xpath-log',{visible:true});//由於獲取元素是異步操作,需要等待該元素加載出來 let resultText= await page.$eval('div#content_left > .result-op.c-container.xpath-log',ele=>{return ele.innerHTML})//獲取元素並返回元素下的innerHTML。 .$eval表示獲取單個元素 console.log("result is ",resultText);//在控制台打印出值。 })();
實戰04:puppeteer文件上傳操作
代碼:在百度首頁上傳圖片
const puppeteer=require('puppeteer'); (async ()=>{ const browser = await puppeteer.launch({headless:false,defaultViewport:{width:1000,height:800}}); const page = await browser.newPage(); await page.goto('https://www.baidu.com'); await page.waitForSelector('span.soutu-btn'); //等待選擇元素出現 const soutuBtn=await page.$('span.soutu-btn'); //獲取圖片按鈕 await soutuBtn.click(); //點擊展開圖片按鈕 await page.waitForSelector('input.upload-pic'); //等待上傳按鈕出現 const uploadPic=await page.$('input.upload-pic'); //獲取上傳按鈕 await uploadPic.uploadFile('C:\\Capture.PNG'); //上傳圖片。注意:路徑要用雙斜杠。 })();
實戰05:puppeteer處理多個元素
代碼:打印京東上的手機信息
const puppeteer = require('puppeteer'); (async()=>{ const browser=await puppeteer.launch({headless:false,defaultViewport:{width:1000,height:800}}); const page =await browser.newPage(); await page.goto('https://www.jd.com'); await page.waitFor("#key"); const inputText=await page.$("#key"); await inputText.type("手機"); await page.keyboard.press('Enter'); await page.waitForSelector("ul.gl-warp > li"); const items=await page.$$eval("ul.gl-warp > li",eles=>eles.map(ele=>ele.innerText)); console.log("手機列表=",items); })();
實戰06:puppeteer切換iframe進行操作
iframe跟page的用法類似。使用前需要切換到iframe里面並用src定位要操作的iframe。
操作可參考:https://github.com/GoogleChrome/puppeteer/blob/v1.20.0/docs/api.md#class-frame
代碼:自動在阿里雲的注冊iframe里面填寫注冊信息
const puppeteer = require('puppeteer'); (async()=>{ const browser = await puppeteer.launch({headless:false,defaultViewport:{width:1000,height:800}}); const page = await browser.newPage(); await page.goto("https://account.aliyun.com/register/register.html"); //切換iframe const frame= await page.frames().find(frame=>frame.url().includes("https://passport.aliyun.com"));//切換iframe,並找到對應src的iframe await frame.waitFor("input#nick"); //等待輸入框加載完成 const nick =await frame.$("input#nick");//獲取輸入框 await nick.type("測試用戶");//輸入數據 })();
實戰07:puppeteer拖拽操作阿里雲驗證碼
代碼:自動操作阿里雲驗證滑動模塊
const puppeteer = require('puppeteer'); (async()=>{ const browser = await puppeteer.launch({headless:false,defaultViewport:{width:1000,height:800},ignoreDefaultArgs:["--enable-automation"]});//在有些頁面可能需要將automation提示去掉。使用ignoreDefaultArgs:["--enable-automation"]參數 const page = await browser.newPage(); await page.goto("https://account.aliyun.com/register/register.html"); //切換iframe const frame= await page.frames().find(frame=>frame.url().includes("https://passport.aliyun.com"));//切換iframe,並找到對應src的iframe await frame.waitForSelector("span#nc_1_n1z");//等待滑動塊加載完成 const span =await frame.$("span#nc_1_n1z"); //獲取滑動元素 const spanInfo=await span.boundingBox(); //獲取滑動塊的信息,包括位置(x,y)以及寬和高 //console.log(spanInfo); await frame.waitForSelector("div#nc_1_n1t"); //等待包裹滑塊的div加載完成 const outDiv=await frame.$("div#nc_1_n1t"); //獲取包裹滑塊的div const outDivInfo=await outDiv.boundingBox(); //獲取包裹滑塊的div的信息,包括位置(x,y)以及寬和高 //console.log(outDivInfo); await page.mouse.move(spanInfo.x,spanInfo.y);//將鼠標移動到滑塊位置 await page.mouse.down(); //將鼠標按下(默認是左鍵) for(var i=0;i<outDivInfo.width;i++){ page.mouse.move(spanInfo.x+i,spanInfo.y);//讓鼠標向左移動outDivInfo的寬度距離 } await page.mouse.up(); //將鼠標松開 })();
實戰08:puppeteer自動抓取百度新聞上的語句並自動登錄微博賬戶發一條微博
代碼:這個實戰似乎翻車了,被微博檢測到自動化而被要求輸入驗證碼
const puppeteer = require('puppeteer'); const config=require('./config'); //為了保護我的個人隱私,所以我把賬號和密碼保存在了config文件中 (async ()=>{ // console.log(config.username); // console.log(config.password); const browser = await puppeteer.launch({ headless:false, defaultViewport:{width:1280,height:800}, ignoreDefaultArgs:["--enable-automation"],//移除自動化,防止頁面生成驗證碼 slowMo:200,//輸入延遲時間 args:['--window-size:1280,800'],//調整窗口大小 }); const page= await browser.newPage(); await page.goto('https://news.baidu.com/',{waitUntil:"networkidle2"});//第一個參數是要前往的地址url,第二個參數是保證頁面全部加載 await page.waitForSelector('#imgTitle>a>strong'); const newsText=await page.$eval("#imgTitle>a>strong",ele=>ele.innerText);//匹配第一個元素 // console.log(newsText); await page.goto('https://weibo.com',{waitUntil:"networkidle2"}); await page.waitFor(5*1000);//防止被檢測 await page.reload();//防止被檢測 await page.waitForSelector('#loginname'); //等待賬號輸入框加載完成 const inputText=await page.$('#loginname'); //獲取賬號輸入框元素 await inputText.click(); //防止被檢測,具體情況具體分析 await inputText.type(config.username); await page.waitForSelector('input[name="password"]'); //等待密碼輸入框加載完成 const inputPwd=await page.$('input[name="password"]'); //獲取密碼輸入框 await inputPwd.click();//防止被檢測,具體情況具體分析 await inputPwd.type(config.password); await page.waitForSelector('a[action-type="btn_submit"]'); //等待確認按鈕加載 const submit=await page.$('a[action-type="btn_submit"]'); //獲取確認按鈕 await submit.click(); //點擊 })();
實戰09:puppeteer模擬快捷鍵
代碼演示:https://github.com/GoogleChrome/puppeteer/blob/v1.20.0/docs/api.md#class-keyboard
實戰10:puppeteer切換瀏覽器tab頁
主要用到api:browser.target();
文檔:https://github.com/GoogleChrome/puppeteer/blob/v1.20.0/docs/api.md#class-browser
實戰11:puppeteer處理彈出的對話框
主要用到的api:Dialog處理彈出的內容
文檔:https://github.com/GoogleChrome/puppeteer/blob/v1.20.0/docs/api.md#class-dialog
實戰12:puppeteer執行JavaScript方法
主要用到的方法:page.evaluate(()=>{ 在這里面可以寫任意JS代碼 })
文檔:https://github.com/GoogleChrome/puppeteer/blob/v1.20.0/docs/api.md#class-page
實戰13:配置typescript環境,並在其中使用puppeteer
待完善
實戰14:獲取全屏截圖
const puppeteer =require('puppeteer');//引入puppeteer (async()=>{//使用自執行函數 const browser = await puppeteer.launch();//生成browser實例 const page = await browser.newPage();//生成一個頁面 await page.goto('https://cn.aliyun.com/');//前往頁面 console.log(await page.content());//打印頁面信息(源碼) await page.screenshot({//截圖 path: 'ali.png', fullPage: true }); await browser.close();//關閉browser實例 })();