爲什麼頂級爬蟲工程師都悄悄換成了 Playwright?趕緊學起來
雜談
如果你也有爬蟲需求,在以往我們需要做一個瀏覽器自動化肯定想到的是 Selenium。作爲老牌的自動化 “選手”,Selenium 網絡上資料多,功能齊全,容易上手。
但是,Selenium 有很多缺陷,特別 web driver 的下載非常頭疼。一個是需要版本要保持一致,就算使用自動下載的代碼,也因爲服務器在國外,速度非常令人崩潰。而且 Selenium 確實存在性能缺陷,有時候無法滿足性能需求。
現在,有一個更加強大的瀏覽器自動化工具可以選擇了,Playwright 是微軟出品的一款自動化測試工具,跨平臺,支持多個瀏覽器,支持自動元素等待,使用上下文管理,一次執行多個瀏覽器頁面隔離。
最可怕的是它還能直接跟蹤我們的操作,錄製操作再執行,不像 Selenium 需要插件才能實現。
一、安裝庫
pip install playwright
安裝完後,我們還需要執行一個命令,它會安裝操控瀏覽器的一些工具,目錄在 C:\Users\xxxxx\AppData\Local\ms-playwright
playwright install
二、使用教程
2.1 打開網址
我們使用谷歌瀏覽器來打開 百度 的網址,其中 input() 是爲了阻止瀏覽器關閉,不然無法看到瀏覽器頁面。
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
# 默認無頭,需要看到瀏覽器,得修改 headless 爲 False
browser = p.chromium.launch(headless=False)
page = browser.new_page()
page.goto('https://www.baidu.com')
# 這裏是爲了阻塞主線程,防止瀏覽器快速關閉
input('')
browser.close()
2.2 截屏
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
page.goto('https://mp.weixin.qq.com/s/ie1MbLsF6_E7V4A0OvyzVQ', wait_until='domcontentloaded')
# 使用 js 絲滑滾動到底部,解決懶加載圖片問題
page.evaluate("""
() => {
window.scrollTo({
transform: translateY( document.body.scrollHeight,
behavior: 'smooth'
});
}
""")
# 等待 1 秒後
page.wait_for_timeout(1000)
print('等待完成')
page.screenshot(path='full_page.png', full_page=True)
print('截屏完成')
browser.close()
在使用截屏時,playwright 是支持長截圖的,但現在很多站點爲了性能優化,使用了 圖片懶加載 的技術,因此爲了能夠截全內容,我們通過模擬滑動來將 懶加載的圖片進行加載展示,然後再截圖。
其中,我們使用 evaluate() 來實現 注入 js 代碼,然後用 wait_for_timeout() 來強制等待,可以讓圖片加載成功率提高。
2.3 等待狀態
在截圖的代碼中,大家應該看到了 wait_until 的參數,它可以等待相應狀態結束後再繼續執行,它有四個狀態值:
-
• commit:等待接收到網絡響應並開始加載文檔
-
• domcontentloaded:等待 DOMContentLoaded 事件觸發
-
• load:等待 load 事件觸發
-
• networkidle:等待網絡空閒,默認在 500ms 內沒有超過 0-2 個網絡請求時認爲完成
當然除了 page.goto() 擁有 wait_until 參數,它還有 page.reload(), page.goBack() 和 page.goForward() 對應刷新、後退和向前操作。
等待元素完成
接下來,咱們要來試一下比較重要的知識點,就是元素的等待,當頁面相應元素完成時才繼續往下運行。
2.4 waitForSelector()
在這之前,我推薦一個比較適合開發 playwright 的寫法,使用異步來開發會更舒服:
import asyncio
from playwright.async_api import async_playwright
async def task():
async with async_playwright() as p:
browser = await p.chromium.launch(headless=False)
page = await browser.new_page()
await page.goto('https://www.baidu.com')
await browser.close()
asyncio.run(task())
這樣我們就可以使用 async 和 await 來比較好的達到我們的需求,且代碼可讀性更高。
在寫代碼前,我想通過判斷 百度 的搜索按鈕出現之後再往下運行,因此我們需要來查看 搜索按鈕 的元素,打開瀏覽器進入 百度,然後按下 F12。
我們通過瀏覽器的控制檯,查看相應按鈕的元素標籤,通過閱讀 html 文檔 來定位元素。
按鈕的 html 內容如下:
可以看到它的 id='su',記住它,將其寫入到代碼中:
import asyncio
from playwright.async_api import async_playwright
async def task():
async with async_playwright() as p:
browser = await p.chromium.launch(headless=False)
page = await browser.new_page()
await page.goto('https://www.baidu.com')
await page.wait_for_selector('#su')
# 這裏是爲了阻塞主線程,防止瀏覽器快速關閉
input('')
await browser.close()
asyncio.run(task())
關鍵代碼是 await page.wait_for_selector('#su'),當然除了支持 id,我們還可以用 class 作爲參照。
2.5 wait_for_function()
除了元素標籤,我們還能注入 js 代碼來判斷,例如 百度首頁 有一個熱門事件,有許多標題鏈接,我希望等待它的個數大於五個以後執行,這裏通過瀏覽器控制檯發現它父標籤的 id 爲 #hotsearch-content-wrapper:
import asyncio
from playwright.async_api import async_playwright
async def task():
async with async_playwright() as p:
browser = await p.chromium.launch(headless=False)
page = await browser.new_page()
await page.goto('https://www.baidu.com')
await page.wait_for_function("document.querySelector('#hotsearch-content-wrapper').children.length > 5")
# 這裏是爲了阻塞主線程,防止瀏覽器快速關閉
input('')
await browser.close()
asyncio.run(task())
常用的就這些,由於篇幅有限不再介紹,其他方式還有 page.wait_for_event()、page.wait_for_timeout()、ele.wait_for_element_state()、ele.wait_for_selector() 等等。
需要說明的是,playwright 是內置等待,當我們使用 click()、fill() 等 行爲操作時,也會進行等待後再調用,無需編寫顯示等待的代碼。
獲取元素並操作
瀏覽器自動化開發最主要的一個內容就是模擬人類操作,因此基本上像點擊、輸入等行爲都可以用代碼來完成。
2.6 fill() 和 click()
現在我們來在百度搜索欄中輸入 “Python 卡皮巴拉” 並點擊搜索按鈕,首先通過瀏覽器控制檯找到元素標籤樣式:分別是 id='kw' 輸入框和 id='su' 搜索按鈕,然後編寫代碼:
import asyncio
from playwright.async_api import async_playwright
async def task():
async with async_playwright() as p:
browser = await p.chromium.launch(headless=False)
page = await browser.new_page()
await page.goto('https://www.baidu.com')
input_ele = await page.query_selector('#kw')
btn_ele = await page.query_selector('#su')
await input_ele.fill('Python卡皮巴拉')
await btn_ele.click()
# 這裏是爲了阻塞主線程,防止瀏覽器快速關閉
input('')
await browser.close()
asyncio.run(task())
除了 fill() 和 click(),還有許多其他操作,例如 dblclick()、hover()、tap()、set_input_files() 等等,就不一一展開了。
三、錄製和執行操作
現在我們來看看 playwright 如何來錄製和執行操作,依舊是之前的 搜索百度 “Python 卡皮巴拉” 的操作流程,我們錄製一份。
在控制檯輸入:
playwright codegen --target python -o script.py https://baidu.com
-
• --target:輸出結果爲 python
-
• -o:將結果輸出到 script.py 中
當我們按下命令回車後,將出現瀏覽器,並且出現如上截圖,總共包含兩部分:
-
- ①部分爲瀏覽器操作部分
-
- ②部分爲操作轉換爲代碼的部分
將瀏覽器關閉後,將會自動保存操作腳本到 script.py 中,想要再次執行,運行腳本即可。
python script.py
四、總結
今天我們初步瞭解了 playwright 的操作,如果你全部閱讀完文章的話,基本就能實現一個簡單的自動化流程。
playwright 十分高效,而且符合現代化開發流程,推薦使用它作爲自動化測試的工具。
安全爬蟲人人有責,文章中只是提供思路和用於學習,請使用爬蟲時遵守法律法規,遵紀守法。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/U7ZZKLTOJC1PKFKVGWMltQ