pytest-pyppeteer
pytest-pyppeteer是我寫的一個 pytest 插件,支持在 pytest 中運行pyppeteer,起因是為了解決作業中的一個測驗需求,現在將其開源并做簡單介紹,
背景
為什么不用 selenium?
最根本的原因是 selenium 的配置比較繁瑣,最常見的問題是需要保持 webdriver 和瀏覽器版本的一致性,
pyppeteer 的簡單介紹
pyppeteer 是 puppeteer的非官方 python 版本,幾乎實作了和其相同的 API,可以非常方便的去操作 Chrome 瀏覽器,
pyppeteer 的局限性
目前最明顯的問題是沒有提供跨瀏覽器的解決方案,最新的 puppeteer 已經提供對 Firefox 的支持,但是 pyppeteer 可能還需要一些時間,
安裝
推薦使用pipenv管理虛擬環境,并替換為國內 pip 源,
$ pipenv install pytest-pyppeteer
僅支持 python >= 3.7
快速開始
用下面這個測驗用例來說明:斷言電影《活著》的豆瓣評分大于 9.0,
from dataclasses import dataclass
from pytest_pyppeteer.models import Browser
@dataclass(init=False)
class Elements:
"""收集所有使用到的頁面元素,可以為 XPath 或者 CSS Selector,"""
# 查詢輸入框
query = "#inp-query"
# 點擊搜索
apply = ".inp-btn > input:nth-child(1)"
# 第一條結果
first_result = (
"#root > div > div > div > div > div:nth-child(1) > div.item-root a.cover-link"
)
# 評分
rating = (
"#interest_sectl > div.rating_wrap.clearbox > div.rating_self.clearfix > strong"
)
async def test_lifetimes(pyppeteer: Browser):
page = await pyppeteer.new_page()
await page.goto('https://movie.douban.com/')
await page.type(Elements.query, "活著")
await page.click(Elements.apply)
await page.waitfor(Elements.first_result)
await page.click(Elements.first_result)
await page.waitfor(Elements.rating)
rating = await page.get_value(Elements.rating)
assert float(rating) >= 9.0
執行測驗用例,看一下效果:

這里我們無需指定瀏覽器的路徑,pytest-pyppeteer 會在對應平臺默認的安裝路徑下搜尋 Chrome 的可執行檔案,
也可以通過 --executable-path命令列選項顯示的指定 Chrome 的路徑,
或者,在你的conftest.py檔案中指定:
@pytest.fixture(scope="session")
def executable_path(executable_path):
if executable_path is None:
return "path/to/Chrome/or/Chromium"
return executable_path
其它支持的命令列選項,包括:
-
--headless:使用瀏覽器的無頭模式; -
--args:為瀏覽器指定其它引數,例如:指定代理服務器:$ pytest --args proxy-server "localhost:5555,direct://" --args proxy-bypass-list "192.0.0.1/8;10.0.0.1/8" -
--window-size:指定瀏覽器的大小,默認是 800*600;--window-size 0 0表示最大化瀏覽器;
同時操作多個瀏覽器
用下面這個測驗用例來說明:斷言書籍《活著》的豆瓣評分高于其電影的評分,
import asyncio
from dataclasses import dataclass
from pytest_pyppeteer.models import Browser, Page
@dataclass(init=False)
class Elements:
"""公共物件庫"""
query = "#inp-query"
apply = ".inp-btn > input:nth-child(1)"
@dataclass(init=False)
class BookElements(Elements):
url = "https://book.douban.com/"
first_result = '(//*[@]/a)[1]'
rating = "#interest_sectl > div > div.rating_self.clearfix > strong"
@dataclass(init=False)
class MovieElements(Elements):
url = "https://movie.douban.com/"
first_result = (
"#root > div > div > div > div > div:nth-child(1) > div.item-root a.cover-link"
)
rating = (
"#interest_sectl > div.rating_wrap.clearbox > div.rating_self.clearfix > strong"
)
async def query_rating(pyppeteer: Browser, name: str, elements: Elements):
"""獲取電影或者書籍的評分,"""
page: Page = await pyppeteer.new_page()
await page.goto(elements.url)
await page.type(elements.query, name)
await page.click(elements.apply)
await page.waitfor(elements.first_result)
await page.click(elements.first_result)
await page.waitfor(elements.rating)
rating = await page.get_value(elements.rating)
return rating
async def test_multiple_pyppeteer(pyppeteer_factory):
pyppeteer1 = await pyppeteer_factory()
pyppeteer2 = await pyppeteer_factory()
movie_rating, book_rating = await asyncio.gather(
query_rating(pyppeteer1, "活著", MovieElements),
query_rating(pyppeteer2, "活著", BookElements)
)
assert book_rating >= movie_rating
通過pyppeteer_factory 可以獲取多個瀏覽器實體,再利用 python 標準庫asyncio可以很方便的執行異步操作,節省時間,
執行測驗用例,看一下效果:

Github 倉庫
更多功能可以訪問:https://github.com/luizyao/pytest-pyppeteer,如果能幫助到你的話,可以給個 star,也歡迎提 issue 和 pr,
pytest 中文檔案(v6.1.1)
之前翻譯過 pytest v5.1.3 的官方檔案并開源,目前計劃更新到 v6.1.1 版本,
專案更多進度可以訪問:https://github.com/luizyao/pytest-chinese-doc/tree/6.1.1
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/187626.html
標籤:Python
