大資料時代,各行各業對資料採集的需求日益增多,網路爬蟲的運用也更為廣泛,越來越多的人開始學習網路爬蟲這項技術,K哥爬蟲此前已經推出不少爬蟲進階、逆向相關文章,為實現從易到難全方位覆蓋,特設【0基礎學爬蟲】專欄,幫助小白快速入門爬蟲,本期為自動化工具 Pyppeteer 的使用。
概述
前兩期文章中已經介紹到了 Selenium 與 Playwright 的使用方法,它們的功能都非常強大。而本期要講的 Pyppeteer 與 Playwright 一致,都可以作為 Selenium 的替代者來使用。且與 Playwright 相比,Pyppeteer 的使用更加簡單。
Pyppeteer 的使用
介紹
在上上期文章中,我們介紹了 Selenium 隱藏特徵的方法,其中使用到了 stealth.min.js 檔案。在介紹檔案的來源時我們提到了 Puppeteer,Puppeteer是一個基於 Node.js 的自動化工具。而這期要將的 Pyppeteer 就是 Puppeteer 的 Python 版。
Pyppeteer 是一個使用 Python 語言封裝的 Google Chrome 瀏覽器的非官方 API。它可以用來進行自動化測試、網站爬蟲和資料抓取等工作。
Pyppeteer 的底層是透過呼叫 Chrome 瀏覽器的 DevTools Protocol 介面來實現的。DevTools Protocol 是一個基於 WebSocket 協議的遠端除錯介面,可以讓開發者控制和檢查 Chrome 瀏覽器的行為。Pyppeteer 利用這個介面實現了對 Chrome 瀏覽器的完全控制,包括載入頁面、模擬使用者操作、獲取頁面內容等等。
Pyppeteer 支援 Python 3.6 及以上版本,並且可以在 Windows、macOS 和 Linux 等作業系統上執行。它提供了簡單易用的 API,可以方便地模擬使用者在瀏覽器上的操作,例如點選連結、填寫表單、觸發事件等等。同時,它也支援對瀏覽器的除錯、截圖、PDF 匯出等高階功能。
Pyppeteer 的使用方式與其他 Python 庫類似,可以透過 pip 包管理器進行安裝。除了 Pyppeteer 本身外,還需要安裝 asyncio 庫和一個相容的 Chrome 瀏覽器版本。在安裝完成後,可以透過 Python 程式碼來控制瀏覽器的行為,實現各種自動化測試或資料抓取的任務。
安裝
Pyppeteer 的安裝與 Playwright 相似。
Pyppeteer 採用了async機制,所以必須使用Python 3.5及以上版本。
首先使用 pip 安裝 Pyppeteer 包:
pip install pyppeteer
安裝完成後可以選擇執行 pyppeteer-install
下載用於 pyppeteer 的 chromium,這一步可以省略,因為第一次執行 Pyppeteer 時會自動檢測是否安裝了 chromium 瀏覽器,如果沒有安裝程式會自動進行安裝配置。
使用
前兩期文章中介紹到了 Selenium 與 Playwright 庫的使用方法,因為自動化庫的使用大同小異,所以這裡只介紹 Pyppeteer 中比較特殊的方法
Pyppeteer 基於非同步實現,所以它支援非同步操作。
啟動
以百度熱搜榜為例:
import asyncio
from pyppeteer import launch
async def main():
browser = await launch(headless=False)
page = await browser.newPage()
await page.goto('https://top.baidu.com/board?tab=realtime')
await browser.close()
asyncio.get_event_loop().run_until_complete(main())
示例程式碼中使用 launch 方法建立了一個瀏覽器物件 browser ,設定了 headless=False 來關閉無頭模式,這一行程式碼的作用相當於啟動一個瀏覽器,await的作用就是等待瀏覽器啟動完畢。
建立完瀏覽器後,使用到了 newPage 方法,建立了一個 Page 物件,這一步相當於開啟了一個新的標籤頁,透過 await 等待標籤頁建立完畢,然後呼叫 goto 方法開啟目標網址,最後使用 close 方法關閉瀏覽器。
launch詳解
launch 方法用於啟動瀏覽器程式並返回瀏覽器例項,它包含了多個引數:
引數 | 描述 | |
---|---|---|
ignoreHTTPSErrors (bool) | 是否忽略HTTPS錯誤。預設為 False | |
headless (bool) | 是否開啟無頭模式。預設為True | |
executablePath (str) | 可執行檔案的路徑,設定該引數可以指定已有的 Chrome 或 Chromium 瀏覽器。 | |
slowMo (int \ | float) | 傳入指定時間(毫秒),用於延緩 Pyppeteer 的一些模擬操作。 |
args (List [str]) | 傳遞給瀏覽器的額外引數。 | |
dumpio (bool) | 是否將 Pyppeteer 的輸出資訊傳給 process.stdout 和process.stderr 。預設為False 。 | |
userDataDir (str) | 使用者資料資料夾。 | |
env (dict) | 瀏覽器環境。預設與 Python 程式相同。 | |
devtools (bool) | 是否為每個標籤頁開啟 DevTools 皮膚,預設為False ,如果該引數為 True ,則 headless 會被強制設定為 False 。 | |
logLevel (int \ | str) | 日誌級別。預設值與根記錄器相同。 |
autoClose (bool) | 指令碼完成時自動關閉瀏覽器程式。預設為True 。 | |
loop (asyncio.AbstractEventLoop) | 事件迴圈。 |
禁用提示條
與 Selenium 一樣,Pyppeteer 控制瀏覽器時會提示 Chrome 正受到自動測試軟體的控制。可以透過 設定 launch 方法中的 args 引數來關閉提示。
browser = await launch(headless=False, args=['--disable-infobars'])
使用者資料持久化
自動化工具如 Selenium 、Playwright 都有一個特徵,就是每一次執行的時候建立的都是一個全新的瀏覽器,它不會記錄使用者之前的行為。如第一次執行時我登入了某個網站,而第二次執行時再次進入該網站時依舊需要登入。這是因為自動化工具沒有記錄使用者行為資訊。Pyppeteer 中,如果需要記錄使用者的行為資訊,可以透過設定 launch 方法中的 userDataDir 方法來實現。
browser = await launch(headless=False, args=['--disable-infobars'], userDataDir='./userdata')
設定了使用者資料資料夾後執行程式碼,會生成一個 userdata 資料夾,其中就儲存著使用者上次控制瀏覽器時記錄的一些行為資料。
執行 JS 語句
import asyncio
from pyppeteer import launch
async def main():
browser = await launch(headless=False)
page = await browser.newPage()
await page.goto('https://top.baidu.com/board?tab=realtime')
dimensions = await page.evaluate('''() => {
return {
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight,
deviceScaleFactor: window.devicePixelRatio,
}
}''')
print(dimensions)
await browser.close()
# {'width': 783, 'height': 583, 'deviceScaleFactor': 1}
透過呼叫 Page 物件下的 evaluate 方法可以執行一段 JS 語句。
反檢測
Pyppeteer 的反檢測方式與 Selenium 和 Playwright 有些區別,但是思想是一樣的。
首先需要安裝 pyppeteer_stealth 庫,它的作用就是用來隱藏特徵。
pip install pyppeteer_stealth
以無頭模式為例:
import asyncio
from pyppeteer import launch
from pyppeteer_stealth import stealth
async def main():
browser = await launch()
page = await browser.newPage()
# 隱藏特徵
await stealth(page)
await page.goto('https://bot.sannysoft.com/')
await page.screenshot(path='page.png')
await browser.close()
asyncio.get_event_loop().run_until_complete(main())
隱藏特徵前:
[](https://imgse.com/i/p9w2ogH)
隱藏特徵後:
等待
waitForSelector :等待符合條件的節點載入完成
waitForFunction :等待某個 JavaScript 方法執行完畢或返回結果
waitForRequest :等待某個特定的請求發出
waitForResponse :等待某個特定請求對應的響應
waitForNavigation :等待頁面跳轉,如果頁面載入失敗則丟擲異常
waitFor :通用等待
waitForXpath :等待符合 Xpath 的節點載入出來
選擇器
Pyppeteer 提供了一些比較有意思的選擇器方法。
J() :返回匹配到的第一個節點,等同於 querySelector 方法。
JJ() :返回匹配到的所有節點,等同於 querySelectorAll 方法。
JJeval() :執行 JS 指令碼並返回一個 JSON 物件,等同於 querySelectorAllEval 方法。
Jeval() :執行 JS 指令碼並返回執行結果,等同於 querySelectorEval 方法。
Jx() :透過 Xpath 匹配符合條件的內容,等同於 xpath 方法。
import asyncio
from pyppeteer import launch
async def main():
browser = await launch(headless=False)
page = await browser.newPage()
await page.goto('https://top.baidu.com/board?tab=realtime')
# 等待元素載入
await page.waitForXPath('//div[@class="c-single-text-ellipsis"]')
element_j = await page.J('.c-single-text-ellipsis')
element_jj = await page.JJ('.c-single-text-ellipsis')
# 列印元素的文字資訊
print(await (await element_j.getProperty('textContent')).jsonValue())
for element in element_jj:
# 列印元素的文字資訊
print(await (await element.getProperty('textContent')).jsonValue())
await browser.close()
asyncio.get_event_loop().run_until_complete(main())
"""
執行結果:
青年強則國家強
青年強則國家強
烏代表舉自家國旗挑釁暴揍俄代表
英王加冕禮彩排:黃金鑽石馬車亮眼
平凡崗位上的奮鬥故事
俞敏洪建議24節氣都放假
7人吃自助4小時炫300多個螃蟹
.
.
.
"""
總結
Pyppeteer 類似於輕量級的 Playwright ,它使用起來更加簡單,且 Pyppeteer 與 Playwright 一樣都支援非同步,效能方面也比較強。缺點就是它基於 Chromium 核心,資源消耗比較大,不支援其它瀏覽器,而且 Pyppeteer 的作者近年來都沒對該庫進行維護,導致存在一些 bug。