国产秋霞理论久久久电影-婷婷色九月综合激情丁香-欧美在线观看乱妇视频-精品国avA久久久久久久-国产乱码精品一区二区三区亚洲人-欧美熟妇一区二区三区蜜桃视频

強(qiáng)大易用!新一代爬蟲利器 Playwright

共 19250字,需瀏覽 39分鐘

 ·

2021-12-24 18:33

大家好,歡迎來到 Crossin的編程教室 !

Playwright 是微軟在 2020 年初開源的新一代自動(dòng)化測(cè)試工具,它的功能類似于 Selenium、Pyppeteer 等,都可以驅(qū)動(dòng)瀏覽器進(jìn)行各種自動(dòng)化操作。它的功能也非常強(qiáng)大,對(duì)市面上的主流瀏覽器都提供了支持,API 功能簡(jiǎn)潔又強(qiáng)大。雖然誕生比較晚,但是現(xiàn)在發(fā)展得非?;馃?。

因?yàn)?Playwright 是一個(gè)類似 Selenium 一樣可以支持網(wǎng)頁(yè)頁(yè)面渲染的工具,再加上其強(qiáng)大又簡(jiǎn)潔的 API,Playwright 同時(shí)也可以作為網(wǎng)絡(luò)爬蟲的一個(gè)爬取利器。

1. Playwright 的特點(diǎn)

  • Playwright 支持當(dāng)前所有主流瀏覽器,包括 Chrome 和 Edge(基于 Chromium)、Firefox、Safari(基于 WebKit) ,提供完善的自動(dòng)化控制的 API。
  • Playwright 支持移動(dòng)端頁(yè)面測(cè)試,使用設(shè)備模擬技術(shù)可以使我們?cè)谝苿?dòng) Web 瀏覽器中測(cè)試響應(yīng)式 Web 應(yīng)用程序。
  • Playwright 支持所有瀏覽器的 Headless 模式和非 Headless 模式的測(cè)試。
  • Playwright 的安裝和配置非常簡(jiǎn)單,安裝過程中會(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 編寫復(fù)雜度。

下面我們就來了解下 Playwright 的使用方法。

2. 安裝

Playwright 目前提供了 Python 和 Node.js 的 API,下面我們針對(duì) Python 版的 Playwright 進(jìn)行介紹。

要使用 Playwright,需要 Python 3.7 版本及以上,請(qǐng)確保 Python 的版本符合要求。

要安裝 Playwright,可以直接使用 pip3,命令如下:

pip3?install?playwright

安裝完成之后需要進(jìn)行一些初始化操作:

playwright?install

這時(shí)候 Playwrigth 會(huì)安裝 Chromium, Firefox and WebKit 瀏覽器并配置一些驅(qū)動(dòng),我們不必關(guān)心中間配置的過程,Playwright 會(huì)為我們配置好。

具體的安裝說明可以參考:https://setup.scrape.center/playwright

安裝完成之后,我們便可以使用 Playwright 啟動(dòng) Chromium 或 Firefox 或 WebKit 瀏覽器來進(jìn)行自動(dòng)化操作了。

3. 基本使用

Playwright 支持兩種編寫模式,一種是類似 Pyppetter 一樣的異步模式,另一種是像 Selenium 一樣的同步模式,我們可以根據(jù)實(shí)際需要選擇使用不同的模式。

我們先來看一個(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ì)象,可以理解是一個(gè)瀏覽器上下文管理器,我們將其賦值為變量 p。

接著我們調(diào)用了 PlaywrightContextManager 對(duì)象的 chromium、firefox、webkit 屬性依次創(chuàng)建了一個(gè) Chromium、Firefox 以及 Webkit 瀏覽器實(shí)例,接著用一個(gè) for 循環(huán)依次執(zhí)行了它們的 launch 方法,同時(shí)設(shè)置了 headless 參數(shù)為 False。

注意:如果不設(shè)置為 False,默認(rèn)是無頭模式啟動(dòng)瀏覽器,我們看不到任何窗口。

launch 方法返回的是一個(gè) Browser 對(duì)象,我們將其賦值為 browser 變量。然后調(diào)用 browser 的 new_page 方法,相當(dāng)于新建了一個(gè)選項(xiàng)卡,返回的是一個(gè) Page 對(duì)象,將其賦值為 page,這整個(gè)過程其實(shí)和 Pyppeteer 非常類似。接著我們就可以調(diào)用 page 的一系列 API 來進(jìn)行各種自動(dòng)化操作了,比如調(diào)用 goto,就是加載某個(gè)頁(yè)面,這里我們?cè)L問的是百度的首頁(yè)。接著我們調(diào)用了 page 的 screenshot 方法,參數(shù)傳一個(gè)文件名稱,這樣截圖就會(huì)自動(dòng)保存為該圖片名稱,這里名稱中我們加入了 browser_type 的 name 屬性,代表瀏覽器的類型,結(jié)果分別就是 chromium, firefox, webkit。另外我們還調(diào)用了 title 方法,該方法會(huì)返回頁(yè)面的標(biāo)題,即 HTML 中 ?title 節(jié)點(diǎn)中的文字,也就是選項(xiàng)卡上的文字,我們將該結(jié)果打印輸出到控制臺(tái)。最后操作完畢,調(diào)用 browser 的 close 方法關(guān)閉整個(gè)瀏覽器,運(yùn)行結(jié)束。

運(yùn)行一下,這時(shí)候我們可以看到有三個(gè)瀏覽器依次啟動(dòng)并加載了百度這個(gè)頁(yè)面,分別是 Chromium、Firefox 和 Webkit 三個(gè)瀏覽器,頁(yè)面加載完成之后,生成截圖、控制臺(tái)打印結(jié)果就退出了。

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

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

百度一下,你就知道
百度一下,你就知道
百度一下,你就知道

通過運(yùn)行結(jié)果我們可以發(fā)現(xiàn),我們非常方便地啟動(dòng)了三種瀏覽器并完成了自動(dòng)化操作,并通過幾個(gè) API 就完成了截圖和數(shù)據(jù)的獲取,整個(gè)運(yùn)行速度是非??斓模呔褪?Playwright 最最基本的用法。

當(dāng)然除了同步模式,Playwright 還提供異步的 API,如果我們項(xiàng)目里面使用了 asyncio,那就應(yīng)該使用異步模式,寫法如下:

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è)寫法和同步模式基本類似,導(dǎo)入的時(shí)候使用的是 async_playwright 方法,而不再是 sync_playwright 方法。寫法上添加了 async/await 關(guān)鍵字的使用,最后的運(yùn)行效果是一樣的。

另外我們注意到,這例子中使用了 with as 語(yǔ)句,with 用于上下文對(duì)象的管理,它可以返回一個(gè)上下文管理器,也就對(duì)應(yīng)一個(gè) PlaywrightContextManager 對(duì)象,無論運(yùn)行期間是否拋出異常,它能夠幫助我們自動(dòng)分配并且釋放 Playwright 的資源。

4. 代碼生成

Playwright 還有一個(gè)強(qiáng)大的功能,那就是可以錄制我們?cè)跒g覽器中的操作并將代碼自動(dòng)生成出來,有了這個(gè)功能,我們甚至都不用寫任何一行代碼,這個(gè)功能可以通過 playwright 命令行調(diào)用 codegen 來實(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??????saves?the?generated?script?to?a?file
??--target???????????language?to?use,?one?of?javascript,?python,?python-async,?csharp?(default:?"python")
??-b,?--browser???browser?to?use,?one?of?cr,?chromium,?ff,?firefox,?wk,?webkit?(default:?"chromium")
??--channel???????????Chromium?distribution?channel,?"chrome",?"chrome-beta",?"msedge-dev",?etc
??--color-scheme???????emulate?preferred?color?scheme,?"light"?or?"dark"
??--device?????????emulate?device,?for?example??"iPhone?11"
??--geolocation???specify?geolocation?coordinates,?for?example?"37.819722,-122.478611"
??--load-storage?????load?context?storage?state?from?the?file,?previously?saved?with?--save-storage
??--lang?????????????specify?language?/?locale,?for?example?"en-GB"
??--proxy-server????????specify?proxy?server,?for?example?"http://myproxy:3128"?or?"socks5://myproxy:8080"
??--save-storage?????save?context?storage?state?at?the?end,?for?later?use?with?--load-storage
??--timezone????????time?zone?to?emulate,?for?example?"Europe/Rome"
??--timeout???????????timeout?for?Playwright?actions?in?milliseconds?(default:?"10000")
??--user-agent??????specify?user?agent?string
??--viewport-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)是 Chromium,其他還有很多設(shè)置,比如 --device 可以模擬使用手機(jī)瀏覽器,比如 iPhone 11,--lang 代表設(shè)置瀏覽器的語(yǔ)言,--timeout 可以設(shè)置頁(yè)面加載超時(shí)時(shí)間。

好,了解了這些用法,那我們就來嘗試啟動(dòng)一個(gè) Firefox 瀏覽器,然后將操作結(jié)果輸出到 script.py 文件,命令如下:

playwright?codegen?-o?script.py?-b?firefox

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

我們可以在瀏覽器中做任何操作,比如打開百度,然后點(diǎn)擊輸入框并輸入 nba,然后再點(diǎn)擊搜索按鈕,瀏覽器窗口如下:

可以看見瀏覽器中還會(huì)高亮顯示我們正在操作的頁(yè)面節(jié)點(diǎn),同時(shí)還顯示了對(duì)應(yīng)的選擇器字符串 input[name="wd"],右側(cè)的窗口如圖所示:

在操作過程中,該窗口中的代碼就實(shí)時(shí)變化,可以看到這里生成了我們一系列操作的對(duì)應(yīng)代碼,比如在搜索框中輸入 nba,就對(duì)應(yīng)如下代碼:

page.fill("input[name=\"wd\"]",?"nba")

操作完畢之后,關(guān)閉瀏覽器,Playwright 會(huì)生成一個(gè) script.py 文件,內(nèi)容如下:

from?playwright.sync_api?import?sync_playwright

def?run(playwright):
????browser?=?playwright.firefox.launch(headless=False)
????context?=?browser.new_context()

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

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

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

????#?Fill?input[name="wd"]
????page.fill("input[name=\"wd\"]",?"nba")

????#?Click?text=百度一下
????with?page.expect_navigation():
????????page.click("text=百度一下")

????context.close()
????browser.close()

with?sync_playwright()?as?playwright:
????run(playwright)

可以看到這里生成的代碼和我們之前寫的示例代碼幾乎差不多,而且也是完全可以運(yùn)行的,運(yùn)行之后就可以看到它又可以復(fù)現(xiàn)我們剛才所做的操作了。

所以,有了這個(gè)功能,我們甚至都不用編寫任何代碼,只通過簡(jiǎn)單的可視化點(diǎn)擊就能把代碼生成出來,可謂是非常方便了!

另外這里有一個(gè)值得注意的點(diǎn),仔細(xì)觀察下生成的代碼,和前面的例子不同的是,這里 new_page 方法并不是直接通過 browser 調(diào)用的,而是通過 context 變量調(diào)用的,這個(gè) context 又是由 browser 通過調(diào)用 new_context 方法生成的。有讀者可能就會(huì)問了,這個(gè) context 究竟是做什么的呢?

其實(shí)這個(gè) context 變量對(duì)應(yīng)的是一個(gè) BrowserContext 對(duì)象,BrowserContext 是一個(gè)類似隱身模式的獨(dú)立上下文環(huán)境,其運(yùn)行資源是單獨(dú)隔離的,在做一些自動(dòng)化測(cè)試過程中,每個(gè)測(cè)試用例我們都可以單獨(dú)創(chuàng)建一個(gè) BrowserContext 對(duì)象,這樣可以保證每個(gè)測(cè)試用例之間互不干擾,具體的 API 可以參考 https://playwright.dev/python/docs/api/class-browsercontext

5. 移動(dòng)端瀏覽器支持

Playwright 另外一個(gè)特色功能就是可以支持移動(dòng)端瀏覽器的模擬,比如模擬打開 iPhone 12 Pro Max 上的 Safari 瀏覽器,然后手動(dòng)設(shè)置定位,并打開百度地圖并截圖。首先我們可以選定一個(gè)經(jīng)緯度,比如故宮的經(jīng)緯度是 39.913904, 116.39014,我們可以通過 geolocation 參數(shù)傳遞給 Webkit 瀏覽器并初始化。

示例代碼如下:

from?playwright.sync_api?import?sync_playwright

with?sync_playwright()?as?p:
????iphone_12_pro_max?=?p.devices['iPhone?12?Pro?Max']
????browser?=?p.webkit.launch(headless=False)
????context?=?browser.new_context(
????????**iphone_12_pro_max,
????????locale='zh-CN',
????????geolocation={'longitude':?116.39014,?'latitude':?39.913904},
????????permissions=['geolocation']
????)
????page?=?context.new_page()
????page.goto('https://amap.com')
????page.wait_for_load_state(state='networkidle')
????page.screenshot(path='location-iphone.png')
????browser.close()

這里我們先用 PlaywrightContextManager 對(duì)象的 devices 屬性指定了一臺(tái)移動(dòng)設(shè)備,這里傳入的是手機(jī)的型號(hào),比如 iPhone 12 Pro Max,當(dāng)然也可以傳其他名稱,比如 iPhone 8,Pixel 2 等。

前面我們已經(jīng)了解了 BrowserContext 對(duì)象,BrowserContext 對(duì)象也可以用來模擬移動(dòng)端瀏覽器,初始化一些移動(dòng)設(shè)備信息、語(yǔ)言、權(quán)限、位置等信息,這里我們就用它來創(chuàng)建了一個(gè)移動(dòng)端 BrowserContext 對(duì)象,通過 geolocation 參數(shù)傳入了經(jīng)緯度信息,通過 permissions 參數(shù)傳入了賦予的權(quán)限信息,最后將得到的 BrowserContext 對(duì)象賦值為 context 變量。

接著我們就可以用 BrowserContext 對(duì)象來新建一個(gè)頁(yè)面,還是調(diào)用 new_page 方法創(chuàng)建一個(gè)新的選項(xiàng)卡,然后跳轉(zhuǎn)到高德地圖,并調(diào)用了 wait_for_load_state 方法等待頁(yè)面某個(gè)狀態(tài)完成,這里我們傳入的 state 是 networkidle,也就是網(wǎng)絡(luò)空閑狀態(tài)。因?yàn)樵陧?yè)面初始化和加載過程中,肯定是伴隨有網(wǎng)絡(luò)請(qǐng)求的,所以加載過程中肯定不算 networkidle 狀態(tài),所以這里我們傳入 networkidle 就可以標(biāo)識(shí)當(dāng)前頁(yè)面和數(shù)據(jù)加載完成的狀態(tài)。加載完成之后,我們?cè)僬{(diào)用 screenshot 方法獲取當(dāng)前頁(yè)面截圖,最后關(guān)閉瀏覽器。

運(yùn)行下代碼,可以發(fā)現(xiàn)這里就彈出了一個(gè)移動(dòng)版瀏覽器,然后加載了高德地圖,并定位到了故宮的位置,如圖所示:

輸出的截圖也是瀏覽器中顯示的結(jié)果。

所以這樣我們就成功實(shí)現(xiàn)了移動(dòng)端瀏覽器的模擬和一些設(shè)置,其操作 API 和 PC 版瀏覽器是完全一樣的。

6. 選擇器

前面我們注意到 click 和 fill 等方法都傳入了一個(gè)字符串,這些字符串有的符合 CSS 選擇器的語(yǔ)法,有的又是 text= 開頭的,感覺似乎沒太有規(guī)律的樣子,它到底支持怎樣的匹配規(guī)則呢?下面我們來了解下。

傳入的這個(gè)字符串,我們可以稱之為 Element Selector,它不僅僅支持 CSS 選擇器、XPath,Playwright 還擴(kuò)展了一些方便好用的規(guī)則,比如直接根據(jù)文本內(nèi)容篩選,根據(jù)節(jié)點(diǎn)層級(jí)結(jié)構(gòu)篩選等等。

文本選擇

文本選擇支持直接使用 text= 這樣的語(yǔ)法進(jìn)行篩選,示例如下:

page.click("text=Log?in")

這就代表選擇文本是 Log in 的節(jié)點(diǎn),并點(diǎn)擊。

CSS 選擇器

CSS 選擇器之前也介紹過了,比如根據(jù) id 或者 class 篩選:

page.click("button")
page.click("#nav-bar?.contact-us-item")

根據(jù)特定的節(jié)點(diǎn)屬性篩選:

page.click("[data-test=login-button]")
page.click("[aria-label='Sign?in']")

CSS 選擇器 + 文本

我們還可以使用 CSS 選擇器結(jié)合文本值進(jìn)行海選,比較常用的就是 has-text 和 text,前者代表包含指定的字符串,后者代表字符串完全匹配,示例如下:

page.click("article:has-text('Playwright')")
page.click("#nav-bar?:text('Contact?us')")

第一個(gè)就是選擇文本中包含 Playwright 的 article 節(jié)點(diǎn),第二個(gè)就是選擇 id 為 nav-bar 節(jié)點(diǎn)中文本值等于 Contact us 的節(jié)點(diǎn)。

CSS 選擇器 + 節(jié)點(diǎn)關(guān)系

還可以結(jié)合節(jié)點(diǎn)關(guān)系來篩選節(jié)點(diǎn),比如使用 has 來指定另外一個(gè)選擇器,示例如下:

page.click(".item-description:has(.item-promo-banner)")

比如這里選擇的就是選擇 class 為 item-description 的節(jié)點(diǎn),且該節(jié)點(diǎn)還要包含 class 為 item-promo-banner 的子節(jié)點(diǎn)。

另外還有一些相對(duì)位置關(guān)系,比如 right-of 可以指定位于某個(gè)節(jié)點(diǎn)右側(cè)的節(jié)點(diǎn),示例如下:

page.click("input:right-of(:text('Username'))")

這里選擇的就是一個(gè) input 節(jié)點(diǎn),并且該 input 節(jié)點(diǎn)要位于文本值為 Username 的節(jié)點(diǎn)的右側(cè)。

XPath

當(dāng)然 XPath 也是支持的,不過 xpath 這個(gè)關(guān)鍵字需要我們自行制定,示例如下:

page.click("xpath=//button")

這里需要在開頭指定 xpath= 字符串,代表后面是一個(gè) XPath 表達(dá)式。

關(guān)于更多選擇器的用法和最佳實(shí)踐,可以參考官方文檔:https://playwright.dev/python/docs/selectors。

7. 常用操作方法

上面我們了解了瀏覽器的一些初始化設(shè)置和基本的操作實(shí)例,下面我們?cè)賹?duì)一些常用的操作 API 進(jìn)行說明。

常見的一些 API 如點(diǎn)擊 click,輸入 fill 等操作,這些方法都是屬于 Page 對(duì)象的,所以所有的方法都從 Page 對(duì)象的 API 文檔查找就好了,文檔地址:https://playwright.dev/python/docs/api/class-page

下面介紹幾個(gè)常見的 API 用法。

事件監(jiān)聽

Page 對(duì)象提供了一個(gè) on 方法,它可以用來監(jiān)聽頁(yè)面中發(fā)生的各個(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://spa6.scrape.center/')
????page.wait_for_load_state('networkidle')
????browser.close()

這里我們?cè)趧?chuàng)建 Page 對(duì)象之后,就開始監(jiān)聽 response 事件,同時(shí)將回調(diào)方法設(shè)置為 on_response,on_response 對(duì)象接收一個(gè)參數(shù),然后把 Response 的狀態(tài)碼和鏈接都輸出出來了。

運(yùn)行之后,可以看到控制臺(tái)輸出結(jié)果如下:

Statue?200:?https://spa6.scrape.center/
Statue?200:?https://spa6.scrape.center/css/app.ea9d802a.css
Statue?200:?https://spa6.scrape.center/js/app.5ef0d454.js
Statue?200:?https://spa6.scrape.center/js/chunk-vendors.77daf991.js
Statue?200:?https://spa6.scrape.center/css/chunk-19c920f8.2a6496e0.css
...
Statue?200:?https://spa6.scrape.center/css/chunk-19c920f8.2a6496e0.css
Statue?200:?https://spa6.scrape.center/js/chunk-19c920f8.c3a1129d.js
Statue?200:?https://spa6.scrape.center/img/logo.a508a8f0.png
Statue?200:?https://spa6.scrape.center/fonts/element-icons.535877f5.woff
Statue?301:?https://spa6.scrape.center/api/movie?limit=10&offset=0&token=NGMwMzFhNGEzMTFiMzJkOGE0ZTQ1YjUzMTc2OWNiYTI1Yzk0ZDM3MSwxNjIyOTE4NTE5
Statue?200:?https://spa6.scrape.center/api/movie/?limit=10&offset=0&token=NGMwMzFhNGEzMTFiMzJkOGE0ZTQ1YjUzMTc2OWNiYTI1Yzk0ZDM3MSwxNjIyOTE4NTE5
Statue?200:?https://p0.meituan.net/movie/da64660f82b98cdc1b8a3804e69609e041108.jpg@464w_644h_1e_1c
Statue?200:?https://p0.meituan.net/movie/283292171619cdfd5b240c8fd093f1eb255670.jpg@464w_644h_1e_1c
....
Statue?200:?https://p1.meituan.net/movie/b607fba7513e7f15eab170aac1e1400d878112.jpg@464w_644h_1e_1c

注意:這里省略了部分重復(fù)的內(nèi)容。

可以看到,這里的輸出結(jié)果其實(shí)正好對(duì)應(yīng)瀏覽器 Network 面板中所有的請(qǐng)求和響應(yīng)內(nèi)容,和下圖是一一對(duì)應(yīng)的:

這個(gè)網(wǎng)站我們之前分析過,其真實(shí)的數(shù)據(jù)都是 Ajax 加載的,同時(shí) Ajax 請(qǐng)求中還帶有加密參數(shù),不好輕易獲取。

但有了這個(gè)方法,這里如果我們想要截獲 Ajax 請(qǐng)求,豈不是就非常容易了?

改寫一下判定條件,輸出對(duì)應(yīng)的 JSON 結(jié)果,改寫如下:

from?playwright.sync_api?import?sync_playwright

def?on_response(response):
????if?'/api/movie/'?in?response.url?and?response.status?==?200:
????????print(response.json())

with?sync_playwright()?as?p:
????browser?=?p.chromium.launch(headless=False)
????page?=?browser.new_page()
????page.on('response',?on_response)
????page.goto('https://spa6.scrape.center/')
????page.wait_for_load_state('networkidle')
????browser.close()

控制臺(tái)輸入如下:

{'count':?100,?'results':?[{'id':?1,?'name':?'霸王別姬',?'alias':?'Farewell?My?Concubine',?'cover':?'https://p0.meituan.net/movie/ce4da3e03e655b5b88ed31b5cd7896cf62472.jpg@464w_644h_1e_1c',?'categories':?['劇情',?'愛情'],?'published_at':?'1993-07-26',?'minute':?171,?'score':?9.5,?'regions':?['中國(guó)大陸',?'中國(guó)香港']},?
...
'published_at':?None,?'minute':?103,?'score':?9.0,?'regions':?['美國(guó)']},?{'id':?10,?'name':?'獅子王',?'alias':?'The?Lion?King',?'cover':?'https://p0.meituan.net/movie/27b76fe6cf3903f3d74963f70786001e1438406.jpg@464w_644h_1e_1c',?'categories':?['動(dòng)畫',?'歌舞',?'冒險(xiǎn)'],?'published_at':?'1995-07-15',?'minute':?89,?'score':?9.0,?'regions':?['美國(guó)']}]}

簡(jiǎn)直是得來全不費(fèi)工夫,我們直接通過這個(gè)方法攔截了 Ajax 請(qǐng)求,直接把響應(yīng)結(jié)果拿到了,即使這個(gè) Ajax 請(qǐng)求有加密參數(shù),我們也不用關(guān)心,因?yàn)槲覀冎苯咏孬@了 Ajax 最后響應(yīng)的結(jié)果,這對(duì)數(shù)據(jù)爬取來說實(shí)在是太方便了。

另外還有很多其他的事件監(jiān)聽,這里不再一一介紹了,可以查閱官方文檔,參考類似的寫法實(shí)現(xiàn)。

獲取頁(yè)面源碼

要獲取頁(yè)面的 HTML 代碼其實(shí)很簡(jiǎn)單,我們直接通過 content 方法獲取即可,用法如下:

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://spa6.scrape.center/')
????page.wait_for_load_state('networkidle')
????html?=?page.content()
????print(html)
????browser.close()

運(yùn)行結(jié)果就是頁(yè)面的 HTML 代碼。獲取了 HTML 代碼之后,我們通過一些解析工具就可以提取想要的信息了。

頁(yè)面點(diǎn)擊

剛才我們通過示例也了解了頁(yè)面點(diǎn)擊的方法,那就是 click,這里詳細(xì)說一下其使用方法。

頁(yè)面點(diǎn)擊的 API 定義如下:

page.click(selector,?**kwargs)

這里可以看到必傳的參數(shù)是 selector,其他的參數(shù)都是可選的。第一個(gè) selector 就代表選擇器,可以用來匹配想要點(diǎn)擊的節(jié)點(diǎn),如果傳入的選擇器匹配了多個(gè)節(jié)點(diǎn),那么只會(huì)用第一個(gè)節(jié)點(diǎn)。

這個(gè)方法的內(nèi)部執(zhí)行邏輯如下:

  • 根據(jù) selector 找到匹配的節(jié)點(diǎn),如果沒有找到,那就一直等待直到超時(shí),超時(shí)時(shí)間可以由額外的 timeout 參數(shù)設(shè)置,默認(rèn)是 30 秒。
  • 等待對(duì)該節(jié)點(diǎn)的可操作性檢查的結(jié)果,比如說如果某個(gè)按鈕設(shè)置了不可點(diǎn)擊,那它會(huì)等待該按鈕變成了可點(diǎn)擊的時(shí)候才去點(diǎn)擊,除非通過 force 參數(shù)設(shè)置跳過可操作性檢查步驟強(qiáng)制點(diǎn)擊。
  • 如果需要的話,就滾動(dòng)下頁(yè)面,將需要被點(diǎn)擊的節(jié)點(diǎn)呈現(xiàn)出來。
  • 調(diào)用 page 對(duì)象的 mouse 方法,點(diǎn)擊節(jié)點(diǎn)中心的位置,如果指定了 position 參數(shù),那就點(diǎn)擊指定的位置。

click 方法的一些比較重要的參數(shù)如下:

  • click_count:點(diǎn)擊次數(shù),默認(rèn)為 1。
  • timeout:等待要點(diǎn)擊的節(jié)點(diǎn)的超時(shí)時(shí)間,默認(rèn)是 30 秒。
  • position:需要傳入一個(gè)字典,帶有 x 和 y 屬性,代表點(diǎn)擊位置相對(duì)節(jié)點(diǎn)左上角的偏移位置。
  • force:即使不可點(diǎn)擊,那也強(qiáng)制點(diǎn)擊。默認(rèn)是 False。

具體的 API 設(shè)置參數(shù)可以參考官方文檔:https://playwright.dev/python/docs/api/class-page/#pageclickselector-kwargs。

文本輸入

文本輸入對(duì)應(yīng)的方法是 fill,API 定義如下:

page.fill(selector,?value,?**kwargs)

這個(gè)方法有兩個(gè)必傳參數(shù),第一個(gè)參數(shù)也是 selector,第二個(gè)參數(shù)是 value,代表輸入的內(nèi)容,另外還可以通過 timeout 參數(shù)指定對(duì)應(yīng)節(jié)點(diǎn)的最長(zhǎng)等待時(shí)間。

獲取節(jié)點(diǎn)屬性

除了對(duì)節(jié)點(diǎn)進(jìn)行操作,我們還可以獲取節(jié)點(diǎn)的屬性,方法就是 get_attribute,API 定義如下:

page.get_attribute(selector,?name,?**kwargs)

這個(gè)方法有兩個(gè)必傳參數(shù),第一個(gè)參數(shù)也是 selector,第二個(gè)參數(shù)是 name,代表要獲取的屬性名稱,另外還可以通過 timeout 參數(shù)指定對(duì)應(yīng)節(jié)點(diǎn)的最長(zhǎng)等待時(shí)間。

示例如下:

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://spa6.scrape.center/')
????page.wait_for_load_state('networkidle')
????href?=?page.get_attribute('a.name',?'href')
????print(href)
????browser.close()

這里我們調(diào)用了 get_attribute 方法,傳入的 selector 是 a.name,選定了 class 為 name 的 a 節(jié)點(diǎn),然后第二個(gè)參數(shù)傳入了 href,獲取超鏈接的內(nèi)容,輸出結(jié)果如下:

/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWIx

可以看到對(duì)應(yīng) href 屬性就獲取出來了,但這里只有一條結(jié)果,因?yàn)檫@里有個(gè)條件,那就是如果傳入的選擇器匹配了多個(gè)節(jié)點(diǎn),那么只會(huì)用第一個(gè)節(jié)點(diǎn)。

那怎么獲取所有的節(jié)點(diǎn)呢?

獲取多個(gè)節(jié)點(diǎn)

獲取所有節(jié)點(diǎn)可以使用 query_selector_all 方法,它可以返回節(jié)點(diǎn)列表,通過遍歷獲取到單個(gè)節(jié)點(diǎn)之后,我們可以接著調(diào)用單個(gè)節(jié)點(diǎn)的方法來進(jìn)行一些操作和屬性獲取,示例如下:

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://spa6.scrape.center/')
????page.wait_for_load_state('networkidle')
????elements?=?page.query_selector_all('a.name')
????for?element?in?elements:
????????print(element.get_attribute('href'))
????????print(element.text_content())
????browser.close()

這里我們通過 query_selector_all 方法獲取了所有匹配到的節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)對(duì)應(yīng)的是一個(gè) ElementHandle 對(duì)象,然后 ElementHandle 對(duì)象也有 get_attribute 方法來獲取節(jié)點(diǎn)屬性,另外還可以通過 text_content 方法獲取節(jié)點(diǎn)文本。

運(yùn)行結(jié)果如下:

/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWIx
霸王別姬?-?Farewell?My?Concubine
/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWIy
這個(gè)殺手不太冷?-?Léon
/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWIz
肖申克的救贖?-?The?Shawshank?Redemption
/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWI0
泰坦尼克號(hào)?-?Titanic
/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWI1
羅馬假日?-?Roman?Holiday
/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWI2
唐伯虎點(diǎn)秋香?-?Flirting?Scholar
/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWI3
亂世佳人?-?Gone?with?the?Wind
/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWI4
喜劇之王?-?The?King?of?Comedy
/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWI5
楚門的世界?-?The?Truman?Show
/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWIxMA==
獅子王?-?The?Lion?King

獲取單個(gè)節(jié)點(diǎn)

獲取單個(gè)節(jié)點(diǎn)也有特定的方法,就是 query_selector,如果傳入的選擇器匹配到多個(gè)節(jié)點(diǎn),那它只會(huì)返回第一個(gè)節(jié)點(diǎn),示例如下:

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://spa6.scrape.center/')
????page.wait_for_load_state('networkidle')
????element?=?page.query_selector('a.name')
????print(element.get_attribute('href'))
????print(element.text_content())
????browser.close()

運(yùn)行結(jié)果如下:

/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWIx
霸王別姬?-?Farewell?My?Concubine

可以看到這里只輸出了第一個(gè)匹配節(jié)點(diǎn)的信息。

網(wǎng)絡(luò)劫持

最后再介紹一個(gè)實(shí)用的方法 route,利用 route 方法,我們可以實(shí)現(xiàn)一些網(wǎng)絡(luò)劫持和修改操作,比如修改 request 的屬性,修改 response 響應(yīng)結(jié)果等。

看一個(gè)實(shí)例:

from?playwright.sync_api?import?sync_playwright
import?re

with?sync_playwright()?as?p:
????browser?=?p.chromium.launch(headless=False)
????page?=?browser.new_page()

????def?cancel_request(route,?request):
????????route.abort()

????page.route(re.compile(r"(\.png)|(\.jpg)"),?cancel_request)
????page.goto("https://spa6.scrape.center/")
????page.wait_for_load_state('networkidle')
????page.screenshot(path='no_picture.png')
????browser.close()

這里我們調(diào)用了 route 方法,第一個(gè)參數(shù)通過正則表達(dá)式傳入了匹配的 URL 路徑,這里代表的是任何包含 .png.jpg ?的鏈接,遇到這樣的請(qǐng)求,會(huì)回調(diào) cancel_request 方法處理,cancel_request 方法可以接收兩個(gè)參數(shù),一個(gè)是 route,代表一個(gè) CallableRoute 對(duì)象,另外一個(gè)是 request,代表 Request 對(duì)象。這里我們直接調(diào)用了 route 的 abort 方法,取消了這次請(qǐng)求,所以最終導(dǎo)致的結(jié)果就是圖片的加載全部取消了。

觀察下運(yùn)行結(jié)果,如圖所示:

可以看到圖片全都加載失敗了。

這個(gè)設(shè)置有什么用呢?其實(shí)是有用的,因?yàn)閳D片資源都是二進(jìn)制文件,而我們?cè)谧雠廊∵^程中可能并不想關(guān)心其具體的二進(jìn)制文件的內(nèi)容,可能只關(guān)心圖片的 URL 是什么,所以在瀏覽器中是否把圖片加載出來就不重要了。所以如此設(shè)置之后,我們可以提高整個(gè)頁(yè)面的加載速度,提高爬取效率。

另外,利用這個(gè)功能,我們還可以將一些響應(yīng)內(nèi)容進(jìn)行修改,比如直接修改 Response 的結(jié)果為自定義的文本文件內(nèi)容。

首先這里定義一個(gè) HTML 文本文件,命名為 custom_response.html,內(nèi)容如下:

html>
<html>
??<head>
????<title>Hack?Responsetitle>
??head>
??<body>
????<h1>Hack?Responseh1>
??body>
html>

代碼編寫如下:

from?playwright.sync_api?import?sync_playwright

with?sync_playwright()?as?p:
????browser?=?p.chromium.launch(headless=False)
????page?=?browser.new_page()

????def?modify_response(route,?request):
????????route.fulfill(path="./custom_response.html")

????page.route('/',?modify_response)
????page.goto("https://spa6.scrape.center/")
????browser.close()

這里我們使用 route 的 fulfill 方法指定了一個(gè)本地文件,就是剛才我們定義的 HTML 文件,運(yùn)行結(jié)果如下:

可以看到,Response 的運(yùn)行結(jié)果就被我們修改了,URL 還是不變的,但是結(jié)果已經(jīng)成了我們修改的 HTML 代碼。

所以通過 route 方法,我們可以靈活地控制請(qǐng)求和響應(yīng)的內(nèi)容,從而在某些場(chǎng)景下達(dá)成某些目的。

8. 總結(jié)

本文介紹了 Playwright 的基本用法。它是一款自動(dòng)化測(cè)試工具,其 API 強(qiáng)大又易于使用,同時(shí)具備很多 Selenium、Pyppeteer 不具備的更好用的 API,所以可以用來抓取復(fù)雜的?JavaScript 渲染頁(yè)面,可謂是新一代的爬取利器。

本文相關(guān)代碼下載:https://github.com/Python3WebSpider/PlaywrightTest

如果文章對(duì)你有幫助,歡迎轉(zhuǎn)發(fā)/點(diǎn)贊/收藏~

作者:崔慶才

來源:進(jìn)擊的Coder


_往期文章推薦_

為了讓大家更好地學(xué)習(xí)python爬蟲,我們做了一個(gè)“靶子”




如需了解付費(fèi)精品課程教學(xué)答疑服務(wù)
請(qǐng)?jiān)?strong style="max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;">Crossin的編程教室內(nèi)回復(fù): 666

瀏覽 54
點(diǎn)贊
評(píng)論
收藏
分享

手機(jī)掃一掃分享

分享
舉報(bào)
評(píng)論
圖片
表情
推薦
點(diǎn)贊
評(píng)論
收藏
分享

手機(jī)掃一掃分享

分享
舉報(bào)

感谢您访问我们的网站,您可能还对以下资源感兴趣:

国产秋霞理论久久久电影-婷婷色九月综合激情丁香-欧美在线观看乱妇视频-精品国avA久久久久久久-国产乱码精品一区二区三区亚洲人-欧美熟妇一区二区三区蜜桃视频 91人人妻人人做人人爽| 成年人在线观看视频网站| 蜜臀久久99精品久久久久久宅男| 日本高清一区二区高清免费视频| 水蜜桃网址| 91久久综合| 在线观看三级| 最新在线中文字幕| 欧美日韩国产性爱| 久久久久久久AV| 欧美日韩操逼片| 亚洲AV无码专区一级婬片毛片 | 欧美三级欧美一级| 欧美伦妇AAAAAA片| 中文字幕第23页| 日本色五月| 高清欧美日韩第一摸| 插综合网| 亚洲欧洲AV| 青青草在线免费视频| 欧美性爱AAA| 日韩精品成人AV| 大香蕉国产视频| 无码高清免费| 国产a毛片| 精品乱子伦一区二区三区在线播放 | 久久99精品久久久水蜜桃| 无码一级二级| 乱伦内射视频| 天天色人人| 亚洲V在线观看| 天天干夜夜爽| 久久97| 国产成人无码一区二区| 丁香社区五月天| 五月天婷婷网站| 淫色AV| 日韩一及| 久操视频一区二区三区| 天堂中文字幕在线观看| 国产精品午夜成人免费| 亚洲成人大香蕉| 无码入口| 欧美成人手机在线看片| A色片| 中文无码熟妇一区二区| 日本AI高清无码在线观看网址| 91在线精品无码秘入口苹果| 今天成全在线观看高清| 日韩成人在线观看视频| 激情人妻AV| 无码人妻在线播放| 成人在线激情| 国产黄在线| 色九月婷婷| 一区二区Av| 中文字幕激情精品| 国产精品一区在线观看| 99精品视频在线播放免费| 69国产精品| 日韩精品人妻中文字幕第4区| 西西人体44www大胆无码| 青青草原在线视频免费观看| 黄色视频在线观看| 国产又粗又大又黄视频| 伊人日韩| 仙踪林777777野大粗| 日本成人视频在线免费播放| 欧美九九| 国产人人操| 一级免费黄色电影| 男人的天堂2019| 午夜无码精品一区二区三区99午| av网站免费观看| www.亚洲| 国产精品成人在线观看| 可以在线观看的AV| 欧美黄色性爱| 欧美人妻无码| 69国产精品无码免费| 女生自慰网站免费| 亚洲日逼网站| 浮力影院av| 黄色视频大全免费看| 国产精品一卡二卡三卡| 人人人人干| 无码人妻精品一区二区50| 免费无码A片在线观看全| 青草娱乐| 日本高清视频网站网wwwwww| 欧美日韩视频| 亚洲三级片在线观看| 日本不卡一区| 五月丁香综合网| 一级片在线观看视频| 91国产爽黄在线| 东京热一区二区三区| 国内老熟妇对白HDXXXX| 爱爱无码视频| 国产理论电影在线观看| 无码一区三区| 欧美成人性爱视频| 99视频在线观看免费| av中文字幕网| www.第四色| 日韩中文字幕有码| 欧美操操| 色哟哟精品| 操毛| 一级a片免费看| 国产熟妇| 日日干夜夜撸| 日韩A片一级无码免费蜜桃| 日韩综合在线| 久久婷婷五月| 69久久久久久久久久| 手机在线小视频| 天天影视综合网免费观看电视剧国产 | 安徽妇搡BBBB搡BBBB按摩| 国外成人性视频免费| 少妇搡BBBB搡BBB搡造水多/| 人人妻人人澡人人爽人人爽| 婷婷俺也去| 天天操天天射天天日| 亚洲欧美成人在线观看| 一区成人| 18av在线观看| 日韩熟妇无码中文字幕| 污污污www精品国产网站| 翔田千里无码XXXXXX| 日韩无码播放| 日韩无码久久久| 久久一级片| 亚洲天堂在线观看视频| 亚洲一区欧美二区gay| 少妇无码中文| 在线免费亚洲视频| 蝌蚪窝在线视频观看| 怡红院一区二区| 成人福利电影| 精品乱子伦| 欧美在线免费视频| 日本国产在线观看| 人妻少妇无码精品| 骚逼av| 一起操在线| 91蜜桃视频| 成人黄色大片| 亚洲免费精品视频| 国产人妻精品一区二区三区不卡| 国产AV综合网| 探花一区二区| 久久婷婷国产综合| AV小说在线观看| 日韩a级片| 无码视频在线观看免费| 精品国产国产没封| 亚洲在线免费观看| 久久久久国产一区二区三区四区| 天天干在线观看视频| 色99在线| 国产91白丝在线播放| 天堂网久久| 色色热热| 黄色福利在线观看| 影音av| 亚洲色图15p| 国产AV一区二区三区四区五区| YOUjiZZ欧美大全| 日本黄色片在线播放| 天堂网av2014| 成年人视频免费看| 久久午夜影院| 大香蕉69| 国产欧美一区在线看| 无码不卡视频在线| 99视频+国产日韩欧美| 亚洲狠狠撸| 日本精品人妻| 无码一区二区视频| 国产精品一区二区视频| 最近中文字幕高清2019中文字幕 | 日韩欧美小视频| 婷婷五月天av| 在线免费观看黄片| 欧美视频A| 婷婷五月伊人| 成人做爰黄A片免费看| 国产三级AV在线| 黄色一级片网站| 无码国产精品一区二区免费式直播| A黄色绿像| 少妇熟女视频一区二区三区| 日韩欧美高清在线| 久久熟女嫩草成人片免费| 91成人在线免费视频| 黄片免费观看视频| 色青草影院久久综合| 粉嫩护士小泬18p| 一区二区三区免费在线| www.黄色在线观看| 少妇无码| 久草大香蕉在线视频| 少婦揉BBBB揉BBBB揉| 人妻AV一区| av在线资源网| 成人做爰A片一区二区| 午夜无码在线观看视频| 国产黄色电影在线| 91麻豆精品无码人妻| 中文字幕无码日韩| 亚洲色综合| 日韩人妻无码一区二区三区中文| 婷婷五月天成人社区| 国产aaaaaa| 欧美黄色免费网站| 国产一区二区在线视频| 最新AV在线播放| 免费的黄色视频网站| 久久这里只有精品9| 大香蕉看片| 91操操| 成人二区三区| 国产成人精品无码片子的价格| 中文字幕第10页| 午夜激情AV| 懂色av| 黄色高清视频在线观看| 国产麻豆精品成人免费视频| 一本一道无码免费看视频| 大香蕉福利视频| 日本肏逼视频| 欧美三级无码| 婷婷丁香五月综合| 欧美成人精品一区二区| 懂色一区二区二区在线播放视频| 337P粉嫩大胆噜噜噜55569| 亚洲秘无码一区二区三区蜜桃中文 | 不卡无码中文字幕| 草草视频在线观看| 日韩二区三区| 天天插在线视频| 中文人妻无码| 亚洲无码视频一区二区| 九九在线视频| 五月婷婷黄色| 91天天爽| 91久久久久久| 日皮做爱视频网站| 久一在线| 中文字幕久热| 中文字幕无码av| 欧美成人精品A片免费一区99| 97精品人妻一区二区三区香蕉 | 91嫩草欧美久久久九九九| 99A片| 在线天堂999| 黄色小视频在线免费观看| 伊人网站| 免费在线观看内射| 亚洲美女视频在线观看| 国产在线小视频| 午夜一区二区三区免费| 日本精品人妻| 婷婷五月在线视频| 欧一美一伦一A片| 日本白浆| 大荫蒂HD大荫蒂视频| 人妻无码中文久久久久专区| 荫蒂添到高潮免费视频| 懂色av粉嫩av蜜臀av| 日批视频| 国产伦精品一级A片视频夜夜| AV日韩无码| 思思热在线| 欧美一区二区精品| 麻豆三级片在线观看| 一区二区不卡视频| 黄色不卡视频| 国产毛片在线视频| 久草中文在线| 亚洲av资源在线观看| 东北老女人操逼视频| 无码熟妇| 欧美色图1| 99xav| 欧美一区二区三区在线| 男人天堂网av| 18禁网站禁片免费观看| 自慰喷水流白浆中文字幕| 亚洲无码av网站| 久久精品一区二区三区蜜芽的特点 | 天堂网久久| 亚洲一级黄色| 婷婷丁香五月花| 日韩亚洲中文字幕| 亚洲欧美性爱| 欧美精品一级| 国产免费AV网站| 2025精品精品视频| 日韩欧美群交| 黃色一级A一片人与| 欧美aaa| jizz无码| 亚洲国产成人精品女人| 中文字幕婷婷五月天| 在线观看污网站| 国产熟妇码视频户外直播| av一区在线观看| 亚洲中文字幕视频在线观看| 日韩无码高清免费视频| 国产免费无码视频| 一夲道无码专区av无码A片| 亚洲无码AV免费观看| 亚洲性爱一区二区| 最近中文字幕在线视频| 在线免费观看黄色视频网站| 91大片| 中文资源在线√8| 亚洲视频a| 麻豆传媒视频观看| 蜜桃亚洲AV无码一区二区三区 | 综合夜夜| 91黄色在线视频| 精品国产久| 69AV视频| 91美女被操| 黄页网站在线免费观看| sm视频网站| 亚洲综合色色| 情趣视频网站| 精品人妻一区二区三区在线视频不卡 | 国产91无码| 91视频久久| 韩国一级AV| 免费a片视频| 天天干天天日蜜臀色欲av| 欧美色国| 欧美日本成人网站入口| 日韩av小电影| 国产成人精品AV| 女生自慰网站免费| 五月激情丁香| 清清草在线视频| 欧美视频免费在线观看| 亚洲日韩成人AV| 少妇熟女一区| 欧美性爱高清| 囯产精品久久久久久久久久辛辛 | 日本特黄AA片免费视频| 成人AV婷婷| 亚洲视频在线免费看| 97人妻| 亚洲永久免费精品| 先锋AV资源| 可以免费看av的网站| 精品欧美一区二区三区| 蜜桃视频app| 亚洲日本在线观看| 丁香婷婷五月基地| 日本A级视频| 精品无码免费视频| 婷婷成人电影| 一本之道DVD不卡视频| 亚洲免费在线视频观看| 热久久久久久| 制服丝袜强奸乱伦| 爱爱日韩| 国产黃色AAA片| 欧美三级视频在线| 成人三级AV| 梁祝艳谭A级毛片| 狠狠躁日日躁夜夜躁A片无码| 亚洲激情欧美激情| 豆花视频成人精品视频| 日韩美女性爱| 你懂的在线播放| 怡红院一区二区| 中文字幕人妻日韩在线| 免费日批网站| 亚洲综合中文| 1插菊花网| 亚洲成人无码在线| 久久精品偷拍视频| 日本大胆中出| 伊人色播| 婷婷国产成人精品| 国产精品成人在线| 日本在线www| 亚洲欧洲成人在线| 国产熟妇搡BBBB搡BBBB搡| 日韩中出| AV天堂偷拍亂伦| 在线第一页| av手机在线| 黄色片免费| 久久偷看各类wc女厕嘘嘘偷窃| 日韩无码高清视频| 久久99精品久久久久久水蜜桃| 久久无码黄片| 久久永久视频| 九九伊人大香蕉| 黄网在线免费观看| 狠狠ri| 在线观看亚洲视频| 色噜噜人妻丝袜无码影院| 色999网址| 亚洲无码手机在线观看| 亚洲午夜精品久久久久久APP| 各种妇女撒尿mm毛免费网站| 成人免费高清| 肏屄免费视频| 狠狠色噜噜狠狠狠888米奇视频| 免费无码高清| 成年人在线播放| 91精品国产成人www| 大香蕉久热| 91在线无码精品入口电车| 国产成人精品三级麻豆| 黄色电影av| 日韩成人精品| 亚洲无码一二区| 久久久综合网| 在线视频日韩| 免费在线看A| 影音先锋人妻限定| 一道本一区二区三区| 色噜噜一区二区| 中文字幕日韩在线观看| 麻豆一二三区| 色色欧美视频| 视频在线观看一区| 久婷婷| 欧一美一婬一伦一区| 午夜天堂精品久久久久9| 中文字幕高清无码免费视频| 色婷婷亚洲婷婷| 中文字幕无码Av在线| 国产精品9| 老司机视频在线视频18| 99亚洲欲妇| 黄色福利在线观看| 九九热视频99| 欧美一二三区黄色免费视屏| 大香蕉伊人网站| 日韩一区二区视频在线观看| 韩国无码精品| 亚洲免费毛片| 欧美特黄AAA| 女人的天堂av| aaaaaa在线观看免费高清| 亚洲成人69| 国产欧美一区二区三区四区| 国产精品色综合| 日韩中文字幕| 狠狠操狠狠操狠狠操| 亚洲免费观看在线观看| 91中文字幕在线观看| 黄色视频在线观看免费网站| 黄片视频在线免费播放| 操逼网站免费| 婷色五月天| 午夜理论在线| 午夜天堂| 中文一区| 北条麻妃成人视频| 日韩成人无码一区二区视频| 久久久无码视频| 天天夜夜久久| 亚洲欧美在线观看| 亚洲国产精品成人久久蜜臀| 大香蕉熟女| 性感91影院| 色777| 中国丰满妇BBwBBwHD| 久久欧洲成人精品无码区| 激情综合五月| 四川少妇搡bbw搡bbbb| 性爱AV在线观看| 一区二区三区高清| 加勒比综合网| www.bbbb| 99在线国产| 波多野结衣av一区| 无码操逼| 黄a在线观看| 色欲熟妇| 91人妻无码视频| 免费视频a| 欧美亚洲自拍偷拍| aⅴ免费观看| 日韩在线不卡| 久久成人综合| 性福利导航| 欧美成人中文字幕| 透逼视频| 一级黄色录像带| 美女91小视频| 久久99影院| 一区二区三区四区久久| 综合久久亚洲| 91蝌蚪在线视频| 精品国产va久久久久久| 97国产超碰| 日韩免费黄色视频| 国产伦精品一区二区三区色大师| 中文字幕av久久波多野结| 久久久久久久网站| 黄色视频日本免费| 德国肥妇熟妇BBwBBw| www.av在线| AV无码在线播放| 国产乱╳╳AⅤ毛片| 日韩精品影视| 亚洲vs无码秘蜜桃少妇| 国产—a毛—a毛A免费看图| 黄片网站免费在线观看| 欧美黄色网视频| 人妻无码免费视频| 伊人成年网| 天天干天天操天天爽| 欧美偷拍一区二区| 91在线精品无码秘入口苹果| 色综合一区二区| 91欧美亚洲| 最新日韩中文字幕| 黄网站在线观看| 亚洲AV观看| 无码人妻A片一区二区青苹果| 国产在线接入| 三级片青青草| 四虎国产| 欧美性夜黄A片爽爽免费视频| 亚洲欧洲无码视频| 2025天天操夜夜操| 日韩在线一区二区| 黄片高清无码| 日韩91在线| 激情五月天综合网| 人人操人人超碰| 国产成人无码A片V99| 青娱乐久久| 国产操b视频| 91成人A片| 91人妻无码视频| 99热综合| 亚洲AV无码一区| 99热在线观看免费精品| 日韩精品一区二区亚洲AV观看| 成人无码欧美大片免费看| 大香蕉啪啪| 亚洲AV无码成人精品区欧洲| www.黄色电影| 天堂中文在线播放| av日韩在线播放| 免费黄色网址啊不卡| 亚洲无码AV电影| 2025av天堂网| 少妇搡BBBB搡BBB搡HD(| 揉BBB搡BBB搡BBB| 久久久久久无码视频| 无码一区二区三区四区五区| 国精品伦一区一区三区有限公司| 熟女人妻视频| 蜜桃视频日韩| 国产字幕在线观看| 俺来也俺去也www色| 丁香六月| AAA免费视频| 热的无码| 刘玥一区二区| 国产成人激情| 3D动漫精品啪啪一区二区| 中文字幕无码视频| 久久黄网| 国产精品国产精品国产专区| 国产香蕉视频在线观看| 亚洲乱伦图| 特级西西444www| 国产一级特黄aaa大片| 狠狠狠狠狠| 黄色动态视频| 91精品视频网站| 国产精品久久久久久久久久久久久| 九色麻豆| 九九热99视频| 亚州精品成人片| 北条麻妃99精彩视频| 午夜国产视频| 蜜桃网站| 欧美日韩性爱| 在线观看免费A片| 北条麻妃性爱视频| 免费无码毛片一区二区A片| 久久久WWW成人免费无遮挡大片| 成人在线18禁| 在线观看免费完整版中文字幕视频| 成人免费无遮挡无码黄漫视频| 91久久久久久| 无码偷拍| www.99国产| 国內精品久久久久久久| 动漫无码视频| 高清在线无码视频| 亚洲无码免费视频在线观看| 婷婷免费| 天天射天天干| a在线视频| 欧美一页| 四虎一区| 日韩av毛片| 一级国产欧美成人A片| 无码成人精品| 3D动漫精品一区二区在线播放免费 | 一区二区成人免费视频| 88海外华人免费一区| A片免费在线观看| 四川BBBB擦BBBB| 欧美日在线| 国产传媒在线| 91精品国产偷窥一区二区| 高清无码波多野结衣| 国产视频不卡| 欧美色视频一区二区三区在线观看| 成人黄A片免费| 国产成人激情| 日本免费在线黄色视频| 欧美色图视频在线观看| 开心色播五月天| 国产精品成人国产乱| 国产欧美在线不卡| 婷婷五月天青草| 人人摸人人| 青娱乐精品| 国产黄色免费| 免费看无码一级A片放24小时| 欧美日韩国产成人| 亚洲AV无码成人精品国产五月天 | aaa精品| 亚洲无码另类| 大香蕉88| 亚洲国产成人无码| 大香蕉视频国产| 大鸡巴影院| 怡春院熟女精品AV| 免费精品黄色网页| 大香蕉最新国产2025| 在线免费观看黄色视频| 欧美一级片| 夜夜骚精品人妻av一区| 免费黄片网站| 大香蕉啪啪| 99在线精品视频| 欧美成人黄色电影| 国产免费无码| 国内久久| 99这里只有精品| www.操逼| 成人网站在线观看免费| 大香蕉电影网| 一级操逼视频| 91在线观看| 三洞齐开Av在线免费观看| 国产AV一区二区三区| 日韩欧美中文| 淫秽视频免费看| 短发妹子双人啪啪秀| 国产成人AV免费观看| 草比网| footjobvk| 国色天香一区二区| 欧美成人网站视频| 亚洲一二区| 一级成人片在线观看| 欧美九九九九| 日韩欧美一级A片| 日逼无码视频| 六月丁香综合| 2024男人天堂| 国精品无码人妻一区二区三区| 美女人人操| 日韩第五页| 成人无码91| 97人人干人人| 亚洲无码图片| 日韩偷拍网| 亚洲不卡在线观看| 先锋影音中文字幕| caopor在线| 欧美一级黄色A片| 成人午夜视频在线观看| 婷婷五月av| 九色91| 99爱视频| 久久久久久久人妻丝袜| 丰满人妻一区二区三区视频在线不卡 | 欧美成人精品AAA| 亚洲AV成人片无码网站| 毛片毛片毛片| 欧美日本成人网站入口| 国色天香一区二区| 久久国产精品在线| 久久久久久免费一级A片| 欧美wwwww| 国产成人无码精免费视频| 蜜桃传媒在线播放| 久久天堂AV综合合色蜜桃网| 影音先锋国产av| 亚洲国产精品成人综合| 琪琪色在线视频| 天天干一干| 成人精品免费| 综合网伊人| 久久午夜无码鲁丝片午夜精品偷窥| 狠狠色AV| 香蕉av在线| 日韩在线观看免| 色综合色综合色综合| 自拍超碰在线| 东京热视频免费观看| 拍真实国产伦偷精品| 中国老熟女重囗味HDXX| 日本黄色免费| 欧美日韩中文字幕无码| 国产在线欧美在线| 日本免费福利视频| 欧美va亚洲va| wwwwww黄| 成人午夜在线观看| 亚洲国产天堂| 欧美久久网| 黄色成人在线| 男女拍拍视频| 亚洲无码三级片在线观看| 亚洲第一a| 最近最火中文字幕mv歌词| 欧美AAA大片| 三级片亚洲无码| 高清无码黄| 91精品大屁股白浆自慰久久久| 另类罕见稀奇videos| 五月激情视频| 久久久精品| 成人无码视频在线| 在线不卡无码| 国产小黄片在线| 免费黄色视频在线| 国产AV在| 91色伦| 欧美日韩国产在线观看| 大香蕉伊人在线手机网| 在线观看无码AV| 欧美在线视频一区二区| 午夜福利视频网站| 成人亚洲A片V一区二区三区蜜月| 欧美一级片在线| 怡春院免费视频| 精品AV无码一区二区三区| 五月婷婷中文版| 日本黄色免费在线观看| 国产成人精品一区二| 亚洲精品成人av无码| 国产精品你懂的| 亚洲高清无码视频| 成年人毛片视频| 久久一级A片| 久热视频在线| 强开小嫩苞一区二区电影| 人人妻人人爽人人操| 日韩免费AV| 女同一区二区三区| 中文字幕一二三四| 国产黄色视频免费在线观看| 午夜性爱AV| 军人妓女院BD高清片在线播放| 国产精品电影| 日韩AV无码免费| 东京热av一区二区| 91在线不卡| 国产精品成人影视| 日韩一级免费视频| 欧美性爱精品一区| 毛片性爱视屏| 97人妻一区二区精品视频| 内射欧美| 一本一道无码| 欧美成人在线观看| 嫖中国站街老熟女HD| 亚洲成人资源| 偷拍亚洲天堂| 中文字幕在线不卡| 玖玖视频| 欧美大鸡吧视频| 色哟哟无码精品一区二区三区| 天天操天天操天天操天天操 | 中国12一13毛片| 国外成人性视频免费| 一级特黄大片色| 啪啪免费视频| 久久er视频| 超碰碰97| 日韩一级二级三级| 中文字幕性爱| 亚洲丝袜不卡| 国产超级无码高清在线视频观看| 欧美热热| 久久噜噜噜精品国产亚洲综合| 午夜国产| 亚洲高清视频无码| 97视频精品| 91色综合| 亚洲影音先锋| 免费看一级高潮毛片| 国产色婷婷精品综合在线播放| 91av免费在线观看| 97碰碰碰| 亚洲日本三级片| 免费在线观看黄色网址| 久久久久麻豆V国产精华液好用吗 色噜噜狠狠一区二区三区牛牛影视 | 五月婷婷综合在线| 成人性生活免费视频| 无套免费视频欧美| 成年女人毛片| 日韩亚洲欧美在线| 伊人网在线视频观看| 毛片自拍| 国产成人一区二区无码| 日韩有码一区| 91探花足浴店少妇在线| 91香蕉在线观看视频在线播放| 99熟女| 欧美少妇视频| 精品视频一区二区三区| 欧美成人精品A片免费一区99 | 1204手机看片| 欧美日韩成人在线观看| 国产成人精品三级麻豆| 久久青青婷婷| 色综合色综合色综合| 国产高清色| www.蜜桃| 久碰人妻人妻人妻| 综合偷拍| 臭小子啊轻点灬太粗太长了的视频 | 亚洲操操| 日韩中文在线观看| 女女女女女女BBBBBB手| 大香蕉老师| 欧美日韩性| 99久久爱re热6在播放| 一区二区三区四区av| 久久精品夜色噜噜亚洲A∨| 久久久久久亚洲| 日本一区二区三区四区在线观看| 欧美婬乱片A片AAA毛片地址| 日韩精品久久久久久久| 综合成人在线| 国产精品久久久久久婷婷天堂| 91精品大屁股白浆自慰久久久| 亚洲精品无码在线观看| 老女人AV| 91在线无码精品秘入口国战| 国产乱子伦-区二区三区| 亚洲欧洲久久| 一道本无码在线视频| 亭亭五月天| 青青操原| 人人干97| 国产精品久久久久野外| 波多野结衣99| 成人日皮视频| 日韩欧美黄色| 亚洲色男人天堂| 裸体美女视频欧美18| 超碰c| 天堂成人网站| 欧美第二页| 福利视频一区| 国产夫妻露脸| 午夜福利影视| 午夜成人福利| 成人A片免费在线观看| 一区二区三区免费在线| 黄色日本视频| 狠狠狠狠狠狠狠狠狠狠| 久久精品一区二区三区蜜芽的特点 | 91视频你懂的| 欧美精品黄片| 天天日综合网| 欧美一区二区三区成人片在线| 亚洲成人性爱| 高潮91PORN蝌蚪九色| 亚洲va欧洲va国产va不卡| 欧美不卡视频| 最近最火中文字幕mv歌词| 一级特黄AA片| 美女性爱3P视频| 国产人体视频| 日本色色色| 午夜成人一区二区|