本文共1451字,閱讀時間約4分鐘
Puppeteer是Chrome團隊出的nodejs庫(無頭瀏覽器),其中一個功能是網頁抓取(可以作為爬蟲使用)
詳細介紹請看gayhub,更新週期大約是一個月,本文是基於 v1.4.0寫的,大致api是通用的。 本文總結了Puppeteer爬蟲的主要用法。我的目標是,有了這篇文章,日常的一般爬蟲使用就不需要去看官方文件了。
一、安裝和使用
1.1安裝
cnpm i -S puppeteer
用cnpm安裝沒有試過報錯,預設會下載puppeteer配套版本的Chromium。
1.2 使用
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({
headless: false, //預設為true(無頭),不顯示瀏覽器介面
slowMo :200, //減速顯示,有時會作為模擬人操作特意減速
devtools: true //顯示開發者工具。頁面寬高預設800*600,把開發者工具顯示再隱藏頁面會佔滿螢幕,有沒有大佬解釋下?
});
//生成Page物件
//const page = await browser.newPage();//官網寫法:一開啟瀏覽器會開啟兩個tab,第二個才是你正在操作的tab
const page = (await browser.pages())[0]; //這是我的寫法,只有一個tab
await page.goto('https://www.juejin.com'); //跳轉到掘金
//請開始你的表演...
await browser.close(); //關閉瀏覽器
})();
複製程式碼
puppeteer基本上每個操作都會返回一個Promise,記得要用await接收下一步的操作。
puppeteer上也提供了一些第三方寫的爬蟲demo,不過感覺封裝得有點多,先不玩。
二、基本用法
2.1 調整頁面
頁面寬高預設800*600,我覺得太小。我一般都會先初始化頁面大小。
和上面說的一樣,這只是初始化的時候的大小,當開啟再隱藏開發者工具後,頁面就會佔滿全屏了,不知道這是不是bug。
await page.setViewport({
width: 1280,
height: 800
});
複製程式碼
2.2 模擬輸入和點選
目測底層是用document.querySelector()
await page.type(selector, 'Hello puppeteer'); //找到對應的選擇器然後填充值。如果之前設定了slowMo會看到像人打字一樣,值是一個一個填進<input/>
await page.click(selector); //模擬點選,這對傳統非同步分頁(url沒有分頁引數)很有用,selector定在下一頁的標籤上
複製程式碼
2.3 iframe處理
如果網頁內有用iframe等標籤,這時page物件是無法讀取<iframe>
裡面的內容的,需要用到page.frames()
。返回一個Frame物件陣列。
通常iframe會有name屬性,判斷name屬性可以快速獲取單個Frame物件的內容。
let iframe = await page.frames();
iframe.find(f => f.name() === 'name')
複製程式碼
2.4 waitFor函式
waitFor函式是簡寫,Page和Frame物件都有。我只會用以下兩種方式,剩下了請大佬指點一下。
為了簡化,Page和Frame物件都有的api,我不會再特意說明,會在程式碼中直接體現。
await iframe.waitFor('.contain .item') //在<iframe>中等待'.contain .item'的節點出現,阻塞結束(ps:優先使用,有時200ms我是等不起的)
await page.waitFor(200)//頁面等待200ms
複製程式碼
2.5 selector和emulate
為什麼要合在一點寫呢?因為確實有一個組合的api叫eval
先分開說說吧。
2.5.1 selector
目測底層是用document.querySelector()和document.querySelectorAll()。熟悉這兩個api的人應該很容易上手。
//ps:較少用
page.$(selector) // document.querySelector()
iframe.$$(selector) // document.querySelectorAll(), $$是All的意思
複製程式碼
2.5.2 emulate
這裡首先要有個概念,puppeteer爬蟲解析dom在瀏覽器,這個api的實參在瀏覽器中。所以可以在這個函式內進行dom操作,同時本地的node api是無法在這裡執行的,執行console.log(global)
會報錯。
舉個栗子:在函式內有console.log('按f12,我出現在瀏覽器的console中,並不在node命令列')
你會發現node命令列看不到這句話,而在Chromium的console中看見。因此你應該理解他的執行環境是當前網站,而不是你本地的node。
//ps:更少用
await page.evaluate(el => {
//喜聞樂見的dom操作
})
await iframe.evaluate(el => {
//請開始你的表演
console.log('按f12,我出現在瀏覽器的console中,並不在node命令列')
})
複製程式碼
2.5.3 真正的主角 $eval
和 $$eval
上面的兩個api一起用就變成了eval,我最常用的api之一。一個api頂上面兩個,集中一起寫,舒服。
const result = await page.$eval(selector, el => {
//如果需要賦值要返回Promise
return new Promise(resolve => {
//...一波騷操作
//可以用Dom api啦
reslove(obj)
})
});
await iframe.$$eval(selector, el => {...});
複製程式碼
2.6 監聽事件
上文說過在page.evaluate
中用console
是不能在node命令列列印出來的,不過有了監聽事件就可以改變這個規則了。也可以在監聽事件裡面做容錯處理。
page.on('console', msg => {
console.log(msg);
});
複製程式碼
個人覺得如果列印dom的話,還是看瀏覽器的console比較好,直觀。
//監聽瀏覽器報錯
page.on('pageerror', pageErr => {
console.log(pageErr);
});
//監聽node報錯
page.on('error', err => {
console.log(err);
});
複製程式碼
三、偽裝移動端
const devices = require("puppeteer/DeviceDescriptors");
const iPhone = devices["iPhone 6"];
...
await page.emulate(iPhone);
複製程式碼
更多裝置可以檢視這裡
以上就是我要介紹的puppeteer爬蟲api。
安利兩本書,一本是老姚的正規表示式pdf版說得很詳細,確實很有用,雖然我已經忘了一大半了(╯﹏╰);另一本是 Web 前端面試指南與高頻考題解析小冊子,內容基礎又豐富,希望我可以找個機會實踐一下。
下面我要說說正事。
小弟不才,17年軟體工程畢業生,熟悉vue寫過兩個公司專案。目前已離職,座標廣州,求大佬們收留。