新一款爬蟲利器的介紹


Playwright是Microsoft在2020年初開源的新一代自動(dòng)化測(cè)試工具恳不,它的功能類似于Selenium怀酷、Pyppeteer等,都可以驅(qū)動(dòng)瀏覽器進(jìn)行各種自動(dòng)化操作剃毒。它的功能也非常強(qiáng)大宝剖,對(duì)市面上主流瀏覽器都提供了支持洁闰,API功能簡(jiǎn)潔又強(qiáng)大。雖然誕生的比較晚万细,但是發(fā)展得非称嗣迹火熱。

在Pyppeteer已經(jīng)不再維護(hù)的年代赖钞,擁有Playwright這個(gè)開源工具是非常棒的選擇腰素,文檔豐富,功能強(qiáng)大仁烹。

安裝方式

conda config --add channels conda-forge
conda config --add channels microsoft
conda install playwright
playwright install

上述命令的具體運(yùn)行過(guò)程是下載Playwright并將其打包為Chromium耸弄、Firefox和Webkit安裝瀏覽器二進(jìn)制文件咧虎。

特點(diǎn)

  • Playwright支持當(dāng)前所有主流瀏覽器卓缰,包括Chrome和Edge(基于Chromium)、Firefox、Safari(基于Webkit)征唬,提供完善的自動(dòng)化控制的API捌显。
  • Playwright支持移動(dòng)端頁(yè)面的測(cè)試,使用設(shè)備模擬技術(shù)可以在移動(dòng)web瀏覽器中測(cè)試響應(yīng)式web應(yīng)用程序总寒。
  • Playwright支持所有瀏覽器的Headless模式和非Headless模式的測(cè)試扶歪。
  • Playwright的安裝配置非常的簡(jiǎn)單,安裝過(guò)程中會(huì)自動(dòng)安裝對(duì)應(yīng)瀏覽器的驅(qū)動(dòng)摄闸,不需要額外的配置WebDriver等善镰。
  • Playwright提供了大量的與自動(dòng)化相關(guān)的API,當(dāng)頁(yè)面加載時(shí)會(huì)自動(dòng)等待對(duì)應(yīng)節(jié)點(diǎn)的加載年枕,大大的簡(jiǎn)化了編寫API的難度炫欺。

使用方式

在python腳本中導(dǎo)入Playwright,并啟動(dòng)3種瀏覽器(Chromium熏兄、Friefox和webkit)的其中一種品洛。Playwright支持兩種編寫模式,一種是Pyppeter一樣的異步模式摩桶,另一種是像Selenium一樣的同步模式桥状,我們可以根據(jù)實(shí)際的需要選擇不同的模式。

下面我們先來(lái)看看一個(gè)基本 同步模式的例子:

from playwright.sync_api import sync_playwright


with sync_playwright() as p:
    for browser_type in [p.chromium, p.firefox, p.webkit]:
        browser = browser_type.launch(headless=False)
        page = browser.new_page()
        page.goto("https://www.baidu.com")
        page.screenshot(path=f"screenshot-{browser_type.name}.png")
        print(page.title())
        browser.close()

首先在這里我們導(dǎo)入了sync_playwright方法硝清,然后調(diào)用這個(gè)方法辅斟,該方法返回的是一個(gè)PlaywrightContextManager對(duì)象,可以將其理解為瀏覽器的上下文管理器芦拿,這里將其賦值給變量p砾肺。接著調(diào)用PlaywrightContextManager對(duì)象的chromium、firefox防嗡、webkit瀏覽器實(shí)例变汪,接著使用for循環(huán)依次去執(zhí)行它們的launch方法,同時(shí)設(shè)置headless為False蚁趁。

這里有一個(gè)注意點(diǎn):如果launch沒(méi)有設(shè)置為Flase裙盾,默認(rèn)是無(wú)頭模式啟動(dòng)瀏覽器,我們看不到任何的窗口他嫡。

launch方法返回的是一個(gè)瀏覽器(Browser)對(duì)象番官,我們將其復(fù)制為browser變量,然后調(diào)用new_page方法钢属,相當(dāng)于是新建一個(gè)選顯卡徘熔,返回page對(duì)象并賦值給變量page,接下來(lái)就是調(diào)用page對(duì)象的一系列自動(dòng)化API進(jìn)行操作淆党。當(dāng)頁(yè)面加載完畢之后生成截圖酷师、控制臺(tái)輸出結(jié)果就退出讶凉,上面的代碼,調(diào)用了page對(duì)象的兩個(gè)方法:

1山孔、screenshot:參數(shù)傳一個(gè)文件的名稱懂讯,這樣截圖就會(huì)自動(dòng)保存為該文件的名稱。

2台颠、title:返回頁(yè)面的標(biāo)題褐望。

這時(shí)當(dāng)前目錄便會(huì)產(chǎn)生三個(gè)截圖文件,都是百度的首頁(yè)串前,文件名中都帶有瀏覽器的名稱瘫里,如圖所示:

image

控制臺(tái)運(yùn)行結(jié)果:

百度一下,你就知道
百度一下荡碾,你就知道
百度一下减宣,你就知道

除了上面所描述的同步模式之外,Playwright還支持異步模式玩荠,如果在項(xiàng)目中使用了asyncio漆腌,那么就應(yīng)該是考慮要采用異步模式,使用異步的API阶冈,寫法如下:

import asyncio
from playwright.async_api import async_playwright


async def main():
    async with async_playwright() as p:
        for browser_type in [p.chromium, p.firefox, p.webkit]:
            browser = await browser_type.launch()
            page = await browser.new_page()
            await page.goto("https://www.baidu.com")
            await page.screenshot(path=f"screenshot-{browser_type.name}.png")
            print(await page.title())

            await browser.close()

asyncio.run(main())

從上面的代碼可以看出闷尿,整個(gè)寫法和同步模式是很相似的。

注意:

1女坑、導(dǎo)入的是async_playwright方法

2填具、在寫法上添加 async/await 關(guān)鍵字。

代碼生成

Playwright還有一個(gè)強(qiáng)大的功能匆骗,那就是可以錄制我們?cè)跒g覽器的操作劳景,并將操作時(shí)的代碼自動(dòng)生成。這個(gè)功能可以通過(guò)Playwright命令調(diào)用codegen來(lái)實(shí)現(xiàn)碉就,我們先看看codegen命令都有什么參數(shù)盟广。

playwright codegen --help

結(jié)果類似如下:

Usage: npx playwright codegen [options] [url]

open page and generate code for user actions

Options:
  -o, --output <file name>     saves the generated script to a file
  --target <language>          language to generate, one of javascript, test, python, python-async, csharp (default:
                               "python")
  -b, --browser <browserType>  browser to use, one of cr, chromium, ff, firefox, wk, webkit (default: "chromium")
  --channel <channel>          Chromium distribution channel, "chrome", "chrome-beta", "msedge-dev", etc
  --color-scheme <scheme>      emulate preferred color scheme, "light" or "dark"
  --device <deviceName>        emulate device, for example  "iPhone 11"
  --geolocation <coordinates>  specify geolocation coordinates, for example "37.819722,-122.478611"
  --ignore-https-errors        ignore https errors
  --load-storage <filename>    load context storage state from the file, previously saved with --save-storage
  --lang <language>            specify language / locale, for example "en-GB"
  --proxy-server <proxy>       specify proxy server, for example "http://myproxy:3128" or "socks5://myproxy:8080"
  --save-storage <filename>    save context storage state at the end, for later use with --load-storage
  --save-trace <filename>      record a trace for the session and save it to a file
  --timezone <time zone>       time zone to emulate, for example "Europe/Rome"
  --timeout <timeout>          timeout for Playwright actions in milliseconds (default: "10000")
  --user-agent <ua string>     specify user agent string
  --viewport-size <size>       specify browser viewport size in pixels, for example "1280, 720"
  -h, --help                   display help for command

Examples:

  $ codegen
  $ codegen --target=python
  $ codegen -b webkit https://example.com

在上面可以看到有幾個(gè)選項(xiàng),比如-o表示輸出代碼文件的名稱瓮钥;--target表示所使用的語(yǔ)言筋量,默認(rèn)是python,即會(huì)生成同步模式的操作代碼碉熄,如果傳入的是python-async則會(huì)生成異步模式的操作代碼桨武;-b表示使用的瀏覽器類型,默認(rèn)是Chrome瀏覽器锈津;--device可以模擬使用手機(jī)瀏覽器呀酸;--lang表示設(shè)置瀏覽器語(yǔ)言,--timeout可以設(shè)置頁(yè)面加載超時(shí)時(shí)間琼梆。

了解這些用法之后性誉,我們就來(lái)嘗試啟動(dòng)Chrome瀏覽器窿吩,然后將操作結(jié)果輸出到test3.py,命令如下:

playwright codegen -o test3.py --target python-async

這時(shí)候就彈出了一個(gè)Chrome瀏覽器艾栋,同時(shí)在右側(cè)會(huì)輸出一個(gè)腳本窗口,實(shí)時(shí)顯示操作對(duì)應(yīng)的代碼蛉顽。

image

可以看到瀏覽器還會(huì)高亮顯示正在操作的節(jié)點(diǎn)蝗砾,同時(shí)還顯示了節(jié)點(diǎn)名稱。

image

在操作的過(guò)程中代碼是實(shí)時(shí)變化的携冤。操作完畢之后即可關(guān)閉瀏覽器悼粮,Playwright會(huì)生成一個(gè)test3.py文件,內(nèi)容如下:

import asyncio

from playwright.async_api import Playwright, async_playwright


async def run(playwright: Playwright) -> None:
    browser = await playwright.chromium.launch(headless=False)
    context = await browser.new_context()

    # Open new page
    page = await context.new_page()

    # Go to https://www.baidu.com/
    await page.goto("https://www.baidu.com/")

    # Click input[name="wd"]
    await page.click("input[name=\"wd\"]")

    # Click input[name="wd"]
    await page.click("input[name=\"wd\"]")

    # Fill input[name="wd"]
    await page.fill("input[name=\"wd\"]", "如何榜上富婆")

    # Click text=百度一下
    # async with page.expect_navigation(url="https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=%E5%A6%82%E4%BD%95%E6%A6%9C%E4%B8%8A%E5%AF%8C%E5%A9%86&fenlei=256&rsv_pq=ca59e3ec000cf6aa&rsv_t=5f82kcndi6iqNSwqOVo5sd%2BHSoqhzQHKLGVs1HFegxx02UtWAA5gHQbWBfw&rqlang=cn&rsv_enter=0&rsv_dl=tb&rsv_sug3=24&rsv_sug1=14&rsv_sug7=100&rsv_btype=i&prefixsug=%25E5%25A6%2582%25E4%25BD%2595%25E6%25A6%259C%25E4%25B8%258A%25E5%25AF%258C%25E5%25A9%2586&rsp=4&inputT=8686&rsv_sug4=68370&rsv_jmp=fail"):
    async with page.expect_navigation():
        await page.click("text=百度一下")
    # assert page.url == "https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=%E5%A6%82%E4%BD%95%E6%A6%9C%E4%B8%8A%E5%AF%8C%E5%A9%86&fenlei=256&rsv_pq=ca59e3ec000cf6aa&rsv_t=5f82kcndi6iqNSwqOVo5sd%2BHSoqhzQHKLGVs1HFegxx02UtWAA5gHQbWBfw&rqlang=cn&rsv_enter=0&rsv_dl=tb&rsv_sug3=24&rsv_sug1=14&rsv_sug7=100&rsv_btype=i&prefixsug=%25E5%25A6%2582%25E4%25BD%2595%25E6%25A6%259C%25E4%25B8%258A%25E5%25AF%258C%25E5%25A9%2586&rsp=4&inputT=8686&rsv_sug4=68370"

    # Close page
    await page.close()

    # ---------------------
    await context.close()
    await browser.close()


async def main() -> None:
    async with async_playwright() as playwright:
        await run(playwright)


asyncio.run(main())

可以看到這里的代碼和我們之前編寫的代碼基本類似曾棕,而且也是完全可以運(yùn)行的扣猫,運(yùn)行之后就可以看到它又復(fù)現(xiàn)了我們剛才的動(dòng)作。

另外這里的new_page并不是通過(guò)browser調(diào)用的翘地,而是通過(guò)context變量調(diào)用的申尤,context又是通過(guò)Browser對(duì)象調(diào)用的。這里的context變量相當(dāng)于一個(gè)BrowserContext對(duì)象衙耕,它是一個(gè)類似于隱身模式的獨(dú)立上下文環(huán)境昧穿,其運(yùn)行資源是隔離的,保證互不干擾橙喘。

選擇器

Playwright的文檔非常的豐富时鸵,可以直接參考https://playwright.dev/python/docs/selectors

事件監(jiān)聽

page對(duì)象提供了一個(gè)on方法,它可以用來(lái)監(jiān)聽頁(yè)面中各個(gè)事件厅瞎,比如close饰潜、console、load和簸、request彭雾、response等等。

比如我們可以監(jiān)聽response事件锁保,response事件可以在每次網(wǎng)絡(luò)請(qǐng)求得到響應(yīng)的時(shí)候觸發(fā)冠跷,我們可以設(shè)置對(duì)應(yīng)的回調(diào)方法獲取對(duì)應(yīng)的Response的全部信息。

from playwright.sync_api import sync_playwright


def on_response(response):
    print(f'Statue {response.status}:{response.url}')

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)
    page = browser.new_page()
    page.on('response', on_response)
    page.goto('https://www.kenshujun.cn/')
    page.wait_for_load_state('networkidle')
    browser.close()

創(chuàng)建page對(duì)象之后身诺,就開始監(jiān)聽response事件蜜托,同時(shí)將回調(diào)方法設(shè)置為on_response撇寞,on_response對(duì)象接受一個(gè)參數(shù)四苇,然后把狀態(tài)碼和連接都輸出來(lái)。

image

看可以看到這里輸出的結(jié)果與瀏覽器Network面板所加載的內(nèi)容是一樣的颗管。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末穴亏,一起剝皮案震驚了整個(gè)濱河市蜂挪,隨后出現(xiàn)的幾起案子重挑,更是在濱河造成了極大的恐慌,老刑警劉巖棠涮,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谬哀,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡严肪,警方通過(guò)查閱死者的電腦和手機(jī)史煎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)驳糯,“玉大人篇梭,你說(shuō)我怎么就攤上這事≡褪啵” “怎么了恬偷?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)帘睦。 經(jīng)常有香客問(wèn)我袍患,道長(zhǎng),這世上最難降的妖魔是什么竣付? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任协怒,我火速辦了婚禮,結(jié)果婚禮上卑笨,老公的妹妹穿的比我還像新娘孕暇。我一直安慰自己,他們只是感情好赤兴,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布妖滔。 她就那樣靜靜地躺著,像睡著了一般桶良。 火紅的嫁衣襯著肌膚如雪座舍。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天陨帆,我揣著相機(jī)與錄音曲秉,去河邊找鬼。 笑死疲牵,一個(gè)胖子當(dāng)著我的面吹牛承二,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播纲爸,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼亥鸠,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起负蚊,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤神妹,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后家妆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鸵荠,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年伤极,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蛹找。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡塑荒,死狀恐怖熄赡,靈堂內(nèi)的尸體忽然破棺而出姜挺,到底是詐尸還是另有隱情齿税,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布炊豪,位于F島的核電站凌箕,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏词渤。R本人自食惡果不足惜牵舱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望缺虐。 院中可真熱鬧芜壁,春花似錦、人聲如沸高氮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)剪芍。三九已至塞淹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間罪裹,已是汗流浹背饱普。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留状共,地道東北人套耕。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像峡继,于是被迫代替她去往敵國(guó)和親箍铲。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • Selenium是一款強(qiáng)大的基于瀏覽器的開源自動(dòng)化測(cè)試工具鬓椭,最初由 Jason Huggins 于 2004 年在...
    FifiZhuang閱讀 7,578評(píng)論 5 71
  • 前言 大家有沒(méi)有發(fā)現(xiàn)之前我們寫的爬蟲都有一個(gè)共性颠猴,就是只能爬取單純的html代碼关划,如果頁(yè)面是JS渲染的該怎么辦呢?...
    追不到的那縷風(fēng)閱讀 2,988評(píng)論 1 5
  • 前言 前段時(shí)間因?yàn)橛腥蝿?wù)翘瓮,需要四個(gè)電商(京東贮折、淘寶、天貓资盅、拼多多)的數(shù)據(jù)调榄。而其中京東的沒(méi)什么反爬,基本是隨便抓呵扛。拼...
    生信師姐閱讀 980評(píng)論 0 2
  • 原文:https://github.com/electron/electron/blob/master/docs/...
    Shmily落墨閱讀 6,093評(píng)論 0 1
  • 大家好每庆,上次我們實(shí)驗(yàn)了爬取了糗事百科的段子,那么這次我們來(lái)嘗試一下爬取百度貼吧的帖子今穿。與上一篇不同的是缤灵,這次我們需...
    追不到的那縷風(fēng)閱讀 549評(píng)論 0 0