pyppeteer——簡單使用示例


 原文:https://mp.weixin.qq.com/s/Iz-DY1UrSfVFRFh5CyHl3Q

一.簡介

  Puppeteer 是 Google 基於 Node.js 開發的一個工具,有了它我們可以通過 JavaScript 來控制 Chrome 瀏覽器的一些操作,當然也可以用作網絡爬蟲上,其 API 極其完善,功能非常強大。 而 Pyppeteer 又是什么呢?它實際上是 Puppeteer 的 Python 版本的實現,但他不是 Google 開發的,是一位來自於日本的工程師依據 Puppeteer 的一些功能開發出來的非官方版本。

  在 Pyppetter 中,實際上它背后也是有一個類似 Chrome 瀏覽器的 Chromium 瀏覽器在執行一些動作進行網頁渲染,首先說下 Chrome 瀏覽器和 Chromium 瀏覽器的淵源。

Chromium 是谷歌為了研發 Chrome 而啟動的項目,是完全開源的。二者基於相同的源代碼構建,Chrome 所有的新功能都會先在 Chromium 上實現,待驗證穩定后才會移植,
因此 Chromium 的版本更新頻率更高,也會包含很多新的功能,但作為一款獨立的瀏覽器,Chromium 的用戶群體要小眾得多。兩款瀏覽器“同根同源”,它們有着同樣的 Logo,
但配色不同,Chrome 由藍紅綠黃四種顏色組成,而 Chromium 由不同深度的藍色構成。

  Pyppeteer 就是依賴於 Chromium 這個瀏覽器來運行的。那么有了 Pyppeteer 之后,我們就可以免去那些繁瑣的環境配置等問題。如果第一次運行的時候,Chromium 瀏覽器沒有安裝,那么程序會幫我們自動安裝和配置,就免去了繁瑣的環境配置等工作。另外 Pyppeteer 是基於 Python 的新特性 async 實現的,所以它的一些執行也支持異步操作,效率相對於 Selenium 來說也提高了。

  安裝:

pip3 install pyppeteer

 

二.抓取js

  而Pyppeteer 模擬jsvascript渲染,抓取信息。

 import asyncio
from pyppeteer import launch from pyquery import PyQuery as pq async def main(): browser = await launch() page = await browser.newPage() await page.goto('http://quotes.toscrape.com/js/') doc = pq(await page.content()) print('Quotes:', doc('.quote').length) await browser.close() asyncio.get_event_loop().run_until_complete(main())

  運行結果:

10

  那么這里面的過程發生了什么?

  實際上,Pyppeteer 整個流程就完成了瀏覽器的開啟、新建頁面、頁面加載等操作。另外 Pyppeteer 里面進行了異步操作,所以需要配合 async/await 關鍵詞來實現。

  首先, launch 方法會新建一個 Browser 對象,然后賦值給 browser,然后調用 newPage  方法相當於瀏覽器中新建了一個選項卡,同時新建了一個 Page 對象。然   后 Page 對象調用了 goto 方法就相當於在瀏覽器中輸入了這個 URL,瀏覽器跳轉到了對應的頁面進行加載,加載完成之后再調用 content 方法,返回當前瀏覽器頁面的源代碼。然后進一步地,我們用 pyquery 進行同樣地解析,就可以得到 JavaScript 渲染的結果了。

另外其他的一些方法如調用 asyncio 的 get_event_loop 等方法的相關操作則屬於 Python 異步 async 相關的內容了,大家如果不熟悉可以了解下 Python 的 async/await 的相關知識。

  好,通過上面的代碼,我們就可以完成 JavaScript 渲染頁面的爬取了。

  在這個過程中,我們沒有配置 Chrome 瀏覽器,沒有配置瀏覽器驅動,免去了一些繁瑣的步驟,同樣達到了 Selenium 的效果,還實現了異步抓取,爽歪歪!

  接下來我們再看看另外一個例子,這個例子可以模擬網頁截圖,保存 PDF,另外還可以執行自定義的 JavaScript 獲得特定的內容,代碼如下

import asyncio from pyppeteer import launch 
async def main():
    browser = await launch()
    page = await browser.newPage()
    await page.goto('http://quotes.toscrape.com/js/')
    await page.screenshot(path='example.png')
    await page.pdf(path='example.pdf')
    dimensions = await page.evaluate('''() => {
        return {
            width: document.documentElement.clientWidth,
            height: document.documentElement.clientHeight,
            deviceScaleFactor: window.devicePixelRatio,
        }
    }''')

    print(dimensions)
    # >>> {'width': 800, 'height': 600, 'deviceScaleFactor': 1}
    await browser.close()

asyncio.get_event_loop().run_until_complete(main())

  

  這里我們又用到了幾個新的 API,完成了網頁截圖保存、網頁導出 PDF 保存、執行 JavaScript 並返回對應數據。

  首先 screenshot 方法可以傳入保存的圖片路徑,另外還可以指定保存格式 type、清晰度 quality、是否全屏 fullPage、裁切 clip 等各個參數實現截圖。

  

  可見其內容也是 JavaScript 渲染后的內容,另外這個方法還可以指定放縮大小 scale、頁碼范圍 pageRanges、寬高 width 和 height、方向 landscape 等等參數,導出定制化的 pdf 用這個方法就十分方便。

最后我們又調用了 evaluate 方法執行了一些 JavaScript,JavaScript 傳入的是一個函數,使用 return 方法返回了網頁的寬高、像素大小比率三個值,最后得到的是一個 JSON 格式的對象,內容如下:

{'width': 800, 'height': 600, 'deviceScaleFactor': 1}

  OK,實例就先感受到這里,還有太多太多的功能還沒提及。

  總之利用 Pyppeteer 我們可以控制瀏覽器執行幾乎所有動作,想要的操作和功能基本都可以實現,用它來自由地控制爬蟲當然就不在話下了。

 

二.詳細用法

  https://miyakogi.github.io/pyppeteer/reference.html

 

  開啟瀏覽器

  使用 Pyppeteer 的第一步便是啟動瀏覽器,首先我們看下怎樣啟動一個瀏覽器,其實就相當於我們點擊桌面上的瀏覽器圖標一樣,把它開起來。用 Pyppeteer 完成同樣的操作,只需要調用 launch 方法即可。

  我們先看下 launch 方法的 API,鏈接為:https://miyakogi.github.io/pyppeteer/reference.html#pyppeteer.launcher.launch,其方法定義如下:

pyppeteer.launcher.launch(options: dict = None, **kwargs) → pyppeteer.browser.Browser

  可以看到它處於 launcher 模塊中,參數沒有在聲明中特別指定,返回類型是 browser 模塊中的 Browser 對象,另外觀察源碼發現這是一個 async 修飾的方法,所以調用它的時候需要使用 await。

  

接下來看看它的參數:

  • ignoreHTTPSErrors (bool): 是否要忽略 HTTPS 的錯誤,默認是 False。

  • headless (bool): 是否啟用 Headless 模式,即無界面模式,如果 devtools 這個參數是 True 的話,那么該參數就會被設置為 False,否則為 True,即默認是開啟無界面模式的。

  • executablePath (str): 可執行文件的路徑,如果指定之后就不需要使用默認的 Chromium 了,可以指定為已有的 Chrome 或 Chromium。

  • slowMo (int|float): 通過傳入指定的時間,可以減緩 Pyppeteer 的一些模擬操作。

  • args (List[str]): 在執行過程中可以傳入的額外參數。

  • ignoreDefaultArgs (bool): 不使用 Pyppeteer 的默認參數,如果使用了這個參數,那么最好通過 args 參數來設定一些參數,否則可能會出現一些意想不到的問題。這個參數相對比較危險,慎用。

  • handleSIGINT (bool): 是否響應 SIGINT 信號,也就是可以使用 Ctrl + C 來終止瀏覽器程序,默認是 True。

  • handleSIGTERM (bool): 是否響應 SIGTERM 信號,一般是 kill 命令,默認是 True。

  • handleSIGHUP (bool): 是否響應 SIGHUP 信號,即掛起信號,比如終端退出操作,默認是 True。

  • dumpio (bool): 是否將 Pyppeteer 的輸出內容傳給 process.stdout 和 process.stderr 對象,默認是 False。

  • userDataDir (str): 即用戶數據文件夾,即可以保留一些個性化配置和操作記錄。

  • env (dict): 環境變量,可以通過字典形式傳入。

  • devtools (bool): 是否為每一個頁面自動開啟調試工具,默認是 False。如果這個參數設置為 True,那么 headless 參數就會無效,會被強制設置為 False。

  • logLevel  (int|str): 日志級別,默認和 root logger 對象的級別相同。

  • autoClose (bool): 當一些命令執行完之后,是否自動關閉瀏覽器,默認是 True。

  • loop (asyncio.AbstractEventLoop): 時間循環對象。

好了,知道這些參數之后,我們可以先試試看。

首先可以試用下最常用的參數 headless,如果我們將它設置為 True 或者默認不設置它,在啟動的時候我們是看不到任何界面的,如果把它設置為 False,那么在啟動的時候就可以看到界面了,一般我們在調試的時候會把它設置為 False,在生產環境上就可以設置為 True,我們先嘗試一下關閉 headless 模式:

  

import asyncio
from pyppeteer import launch

async def main():
    await launch(headless=False)
    await asyncio.sleep(100)

asyncio.get_event_loop().run_until_complete(main())

  運行之后看不到任何控制台輸出,但是這時候就會出現一個空白的 Chromium 界面了:

  

   但是可以看到這就是一個光禿禿的瀏覽器而已,看一下相關信息

    

  

  看到了,這就是 Chromium,上面還寫了開發者內部版本,可以認為是開發版的 Chrome 瀏覽器就好。

  另外我們還可以開啟調試模式,比如在寫爬蟲的時候會經常需要分析網頁結構還有網絡請求,所以開啟調試工具還是很有必要的,我們可以將 devtools 參數設置為 True,  這樣每開啟一個界面就會彈出一個調試窗口,非常方便,示例如下:

import asyncio
from pyppeteer import launch

async def main():
    browser = await launch(devtools=True)
    page = await browser.newPage()
    await page.goto('https://www.baidu.com')
    await asyncio.sleep(100)

asyncio.get_event_loop().run_until_complete(main())
 

  剛才說過 devtools 這個參數如果設置為了 True,那么 headless 就會被關閉了,界面始終會顯現出來。在這里我們新建了一個頁面,打開了百度,界面運行效果如下:

  

 

  

這時候我們可以看到上面的一條提示:"Chrome 正受到自動測試軟件的控制",這個提示條有點煩,那咋關閉呢?這時候就需要用到 args 參數了,禁用操作如下:

browser = await launch(headless=False, args=['--disable-infobars'])

這里就不再寫完整代碼了,就是在 launch 方法中,args 參數通過 list 形式傳入即可,這里使用的是 --disable-infobars 的參數。

另外有人就說了,這里你只是把提示關閉了,有些網站還是會檢測到是 webdriver 吧,比如淘寶檢測到是 webdriver 就會禁止登錄了,我們可以試試:

import asyncio
from pyppeteer import launch

async def main():
    browser = await launch(headless=False)
    page = await browser.newPage()
    await page.goto('https://www.taobao.com')
    await asyncio.sleep(100)

asyncio.get_event_loop().run_until_complete(main())

運行時候進行一下登錄,然后就會彈出滑塊,自己手動拖動一下,然后就報錯了,界面如下:

  

  

爬蟲的時候看到這界面是很讓人崩潰的吧,而且這時候我們還發現了頁面的 bug,整個瀏覽器窗口比顯示的內容窗口要大,這個是某些頁面會出現的情況,讓人看起來很不爽。

我們可以先解決一下這個顯示的 bug,需要設置下 window-size 還有 viewport,代碼如下:

import asyncio
from pyppeteer import launch

width, height = 1366, 768

async def main():
    browser = await launch(headless=False,
                           args=[f'--window-size={width},{height}'])
    page = await browser.newPage()
    await page.setViewport({'width': width, 'height': height})
    await page.goto('https://www.taobao.com')
    await asyncio.sleep(100)

asyncio.get_event_loop().run_until_complete(main())

這樣整個界面就正常了:

  

 

  

OK,那剛才所說的 webdriver 檢測問題怎樣來解決呢?其實淘寶主要通過 window.navigator.webdriver 來對 webdriver 進行檢測,所以我們只需要使用 JavaScript 將它設置為 false 即可,代碼如下:

import asyncio
from pyppeteer import launch


async def main():
    browser = await launch(headless=False, args=['--disable-infobars'])
    page = await browser.newPage()
    await page.goto('https://login.taobao.com/member/login.jhtml?redirectURL=https://www.taobao.com/')
    await page.evaluate(
        '''() =>{ Object.defineProperties(navigator,{ webdriver:{ get: () => false } }) }''')
    await asyncio.sleep(100)

asyncio.get_event_loop().run_until_complete(main())

這里沒加輸入用戶名密碼的代碼,當然后面可以自行添加,下面打開之后,我們點擊輸入用戶名密碼,然后這時候會出現一個滑動條,這里滑動的話,就可以通過了,如圖所示:

  

  

OK,這樣的話我們就成功規避了 webdriver 的檢測,使用鼠標拖動模擬就可以完成淘寶的登錄了。

還有另一種方法可以進一步免去淘寶登錄的煩惱,那就是設置用戶目錄。平時我們已經注意到,當我們登錄淘寶之后,如果下次再次打開瀏覽器發現還是登錄的狀態。這是因為淘寶的一些關鍵 Cookies 已經保存到本地了,下次登錄的時候可以直接讀取並保持登錄狀態。

那么這些信息保存在哪里了呢?其實就是保存在用戶目錄下了,里面不僅包含了瀏覽器的基本配置信息,還有一些 Cache、Cookies 等各種信息都在里面,如果我們能在瀏覽器啟動的時候讀取這些信息,那么啟動的時候就可以恢復一些歷史記錄甚至一些登錄狀態信息了。

這也就解決了一個問題:很多朋友在每次啟動 Selenium 或 Pyppeteer 的時候總是是一個全新的瀏覽器,那就是沒有設置用戶目錄,如果設置了它,每次打開就不再是一個全新的瀏覽器了,它可以恢復之前的歷史記錄,也可以恢復很多網站的登錄信息。

那么這個怎么來做呢?很簡單,在啟動的時候設置 userDataDir 就好了,示例如下:

import asyncio
from pyppeteer import launch

async def main():
    browser = await launch(headless=False, userDataDir='./userdata', args=['--disable-infobars'])
    page = await browser.newPage()
    await page.goto('https://www.taobao.com')
    await asyncio.sleep(100)

asyncio.get_event_loop().run_until_complete(main())

好,這里就是加了一個 userDataDir 的屬性,值為 userdata,即當前目錄的 userdata 文件夾。我們可以首先運行一下,然后登錄一次淘寶,這時候我們同時可以觀察到在當前運行目錄下又多了一個 userdata 的文件夾,里面的結構是這樣子的:

  

  

具體的介紹可以看官方的一些說明,如:https://chromium.googlesource.com/chromium/src/+/master/docs/user_data_dir.md,這里面介紹了 userdatadir 的相關內容。

再次運行上面的代碼,這時候可以發現現在就已經是登錄狀態了,不需要再次登錄了,這樣就成功跳過了登錄的流程。當然可能時間太久了,Cookies 都過期了,那還是需要登錄的。

好了,本想把 Pyppeteer 的用法詳細介紹完的,結果只 launch 的方法就介紹這么多了,后面的內容放到其他文章來介紹了,其他的內容后續文章會陸續放出,謝謝。

小彩蛋:以上文章摘自即將完稿的《Python3網絡爬蟲開發實戰(第二版)》,敬請期待,謝謝。


免責聲明!

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



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