前言
前段時間因為有任務(wù)焕数,需要四個電商(京東、淘寶刨啸、天貓堡赔、拼多多)的數(shù)據(jù)。而其中京東的沒什么反爬设联,基本是隨便抓善已。拼多多的加密參數(shù)有點復(fù)雜,而且變化也挺頻繁的离例,用的是 selenium换团,也沒什么可提的。抓淘寶和天貓因為用 selenium 滑塊過不了宫蛆,于是就改成了 pyppeteer∷野現(xiàn)在我說一下使用的心得。有些細(xì)節(jié)因為當(dāng)時沒有記錄耀盗,現(xiàn)在也記不起來了想虎。
首先 pip install pyppeteer
, 這時候我們先看一下 websockets 這個庫的版本,因為必須保證這個庫是 7.0 的版本叛拷。8.0 和 6.0 雖然可以使用舌厨,但是在訪問多個網(wǎng)頁會出現(xiàn)一些無法解決的異常》揶保現(xiàn)在安裝 pyppeteer裙椭,websockets 的版本默認(rèn)是 8.0,我們需要先pip uninstall websockets
卸載 8.0署浩,然后pip install websockets==7.0
揉燃。然后我們按照 https://github.com/miyakogi/pyppeteer/pull/160/files 這個網(wǎng)頁修改 pyppeteer 的源碼(如果是 anaconda,則路徑是 anaconda 安裝路徑\Lib\site-packages\pyppeteer\connection.py 這個文件)筋栋。這樣準(zhǔn)備工作就完成了你雌,這樣操作之后就可以避免很多異常。
需要這么費勁的折騰二汛,是因為 pyppeteer 這個庫已經(jīng)很久沒有做大的更新了,雖然有點小的改動拨拓,但是基本的 bug 還是沒有解決肴颊。所以如果有 js 基礎(chǔ),最好還是使用 JavaScript 的 puppeteer 這個工具渣磷,這個是谷歌出品的婿着,一直在更新維護(hù),基本沒有 bug。
補充:有時候會出現(xiàn)明明網(wǎng)頁加載完成了竟宋,但是還是會出現(xiàn)超時的情況提完。不知道是什么 bug,解決方法也很簡單丘侠,只要捕獲這個異常徒欣,然后該做啥做啥。
以下有的方法前面帶 coroutine 這個關(guān)鍵字蜗字,有點沒有打肝,這是因為帶這個參數(shù)的方法都是異步方法,這種方法必須被 async 關(guān)鍵字修飾挪捕,調(diào)用的時候也必須 await 關(guān)鍵字修飾粗梭。不過我們既然使用瀏覽器爬蟲了,肯定已經(jīng)不在乎效率了级零,異步等于在等網(wǎng)站封断医,所以只需要遵守某些規(guī)則即可(不懂的請百度 asyncio 的使用),實際上還是同步運行奏纪。另外鉴嗤,雖然 page.on()這個方法是存在的,但是官方文檔中并未給出詳細(xì)的說明亥贸,甚至我查看 pyppeteer 的源碼也未找到這個函數(shù)躬窜,不知道是怎么回事。但是參考 puppeteer 的文檔也是可以用的炕置,不過報錯居多荣挨,我也就沒有深究了。
API 參考
啟動器
- pyppeteer.launcher.launch()
啟動 Chrome 進(jìn)程并返回瀏覽器實例
參數(shù):
-
ignoreHTTPSErrors
(bool):是否忽略 HTTPS 錯誤朴摊。默認(rèn)為False
-
headless
(bool):是否在無頭模式下運行瀏覽器默垄。默認(rèn)為True
除非appMode
或devtools
選項True
-
executablePath
(str):運行 Chromium 或 Chrome 可執(zhí)行文件的路徑,而不是默認(rèn)捆綁的 Chromium -
slowMo
(int | float):按指定的毫秒數(shù)減慢 pyppeteer 操作甚纲。 -
args
(List [str]):傳遞給瀏覽器進(jìn)程的附加參數(shù)(標(biāo)志)口锭。 -
dumpio
(bool):是否管道瀏覽器進(jìn)程 stdout 和 stderr 進(jìn)入process.stdout
和process.stderr
。默認(rèn)為False
介杆。 -
userDataDir
(str):用戶數(shù)據(jù)目錄的路徑鹃操。 -
env
(dict):指定瀏覽器可見的環(huán)境變量。默認(rèn)與 python 進(jìn)程相同春哨。 -
devtools
(bool):是否為每個選項卡自動打開 DevTools 面板荆隘。如果是此選項True
,headless
則將設(shè)置該選項False
赴背。 -
logLevel
(int | str):用于打印日志的日志級別椰拒。默認(rèn)值與根記錄器相同晶渠。 -
autoClose
(bool):腳本完成時自動關(guān)閉瀏覽器進(jìn)程。默認(rèn)為True
燃观。 -
loop
(asyncio.AbstractEventLoop):事件循環(huán)(實驗)褒脯。
- ignoreHTTPSErrors:意思很明顯,不解釋
- headless:不解釋
- executablePath:這個一般是默認(rèn)的路徑就行
- slowMo:我一般會加這個參數(shù)缆毁,至于效果嗎番川,好像有點。
- args:常用的有['--no-sandbox','--disable-gpu', '--disable-setuid-sandbox','--window-size=1440x900']
- dumpio: 不知道為什么积锅,如果不加 dumpio=True 有時會出現(xiàn)瀏覽器卡頓
- userDataDir:selenium 的 userdata 可以保留 cookie爽彤,下次啟動可以達(dá)到免登錄,而這個參數(shù)沒什么用
- env:看需求
- devtools:用的不深缚陷,沒用過
- logLevel:沒什么用适篙,在 Linux 下還是打印大量的日志
- autoClose:默認(rèn)就好,不過如果你需要保持瀏覽器狀態(tài)箫爷,可以不關(guān)閉嚷节,下次直接連接這個已存在的瀏覽器
- loop:暫時不知道有什么用
- pyppeteer.launcher.connect()
連接到現(xiàn)有的 Chrome
參數(shù):
-
browserWSEndpoint
(str):要連接的瀏覽器 websocket 端點。(必填) -
ignoreHTTPSErrors
(bool):是否忽略 HTTPS 錯誤虎锚。默認(rèn)為False
硫痰。 -
slowMo
(int | float):按指定的毫秒數(shù)減慢 pyppeteer 的速度。 -
logLevel
(int | str):用于打印日志的日志級別窜护。默認(rèn)值與根記錄器相同效斑。 -
loop
(asyncio.AbstractEventLoop):事件循環(huán)(實驗)。
browserWSEndpoint:格式是ws://${host}:${port}/devtools/browser/<id>
柱徙。以前瀏覽器的 wsEndpoint 這個值缓屠,可以通過brower = pyppeteer.launcher.launch()
dev = brower. wsEndpoint
保存這個值就可以下次啟動了
- pyppeteer.launcher.executablePath()
獲取默認(rèn) Chrome 的可執(zhí)行路徑
瀏覽器類
pyppeteer.browser.Browser()
這個類是由 launch()返回的實例
- browserContexts: 返回所有打開的瀏覽器上下文的列表,在新創(chuàng)建的瀏覽器中护侮,這將返回單個實例
- coroutine close(): 關(guān)閉連接并終止瀏覽器進(jìn)程
- coroutine createIncognitoBrowserContext(): 創(chuàng)建一個新的隱身瀏覽器上下文敌完。這不會與其他瀏覽器上下文共享 cookie /緩存
- coroutine disconnect(): 斷開瀏覽器
- coroutine newPage(): 在此瀏覽器上創(chuàng)建新頁面并返回其對象
- coroutine pages(): 獲取此瀏覽器的所有頁面。返回格式為列表羊初,包含所有頁面
- process:返回此瀏覽器的進(jìn)程
- target(): 獲取瀏覽器中所有活動目標(biāo)的列表
- coroutine userAgent():返回瀏覽器的原始 UA
- coroutine version(): 獲取瀏覽器的版本
- wsEndpoint: 返回 websocket 端點 url
頁面類
pyppeteer.page.Page()
由 brower.newPage()或者 brower.pages()得到
coroutine J():別名 querySelector(),看名字就知道通過 CSS 選擇器來選出元素
coroutine JJ(): 別名 querySelectorAll()
coroutine Jeval(): 功能比 page.J()功能多一點滨溉,可以選出網(wǎng)頁文本或者屬性指
coroutine JJeval(): querySelectorAllEval()
coroutine Jx(): 別名 xpath()
-
coroutine addScriptTag(): 將腳本標(biāo)記添加到此頁面, 返回 ElementHandle
其中一個 url长赞,path 或 content 選擇是必要的晦攒。-
url
(字符串):要添加的腳本的 URL。 -
path
(字符串):要添加的本地 JavaScript 文件的路徑得哆。 -
content
(字符串):要添加的 JavaScript 字符串坦袍。 -
type
(字符串):腳本類型吼句。使用module
以加載一個 JavaScript ES6 模塊抒巢。
-
-
coroutine addStyleTag(): 將樣式或鏈接標(biāo)記添加到此頁面狸捕, 返回 ElementHandle
其中一個url
,path
或content
選擇是必要的乐设。-
url
(字符串):要添加的鏈接標(biāo)記的 URL讼庇。 -
path
(字符串):要添加的本地 CSS 文件的路徑。 -
content
(字符串):要添加的 CSS 字符串近尚。
-
coroutine authenticate(): 提供 http 身份驗證的憑據(jù)
coroutine bringToFront(): 將頁面置于前面
browser: 獲取該頁面所屬的瀏覽器
-
coroutine click(): 相當(dāng)于鼠標(biāo)左鍵單擊匹配的元素蠕啄,參數(shù)是 CSS 選擇器的字符串。如果沒有匹配到元素戈锻,則會引發(fā) PageError
可選參數(shù):-
button
(str): 歼跟,left,right 或 middle格遭,默認(rèn)為 left哈街。 -
clickCount
(int):默認(rèn)為 1。 -
delay
(int | float):等待時間 mousedown 和 mouseup 以毫秒為單位的時間拒迅。默認(rèn)為 0骚秦。
-
注意
如果此方法觸發(fā)導(dǎo)航事件并且存在單獨的事件,則 waitForNavigation()最終可能會出現(xiàn)產(chǎn)生意外結(jié)果的競爭條件璧微。單擊并等待導(dǎo)航的正確模式如下:
<textarea style="margin: 0px; padding: 0px;"></textarea>
``` await asyncio.gather( page.waitForNavigation(waitOptions), page.click(selector, clickOptions), ) ```
大概意思是 click()觸發(fā)如果會跳轉(zhuǎn)網(wǎng)頁作箍,則需要 page.waitForNavigation()這個函數(shù)來等待。但點擊事件和觸發(fā)事件是同時的前硫,所以需要將這兩個事件綁定胞得,代碼如上。
coroutine close(): 關(guān)閉此頁面
coroutine content(): 獲取頁面的完整 HTML 內(nèi)容
coroutine cookies(): 獲取 cookie屹电。參數(shù)為 URL阶剑,如果未指定 URL,則此方法返回當(dāng)前頁面 URL 的 cookie嗤详。如果指定了 URL个扰,則僅返回這些 URL 的 cookie
coverage: 返回 coverage
coroutine deleteCookie(): 刪除 cookie,參數(shù)為 cookie 字段參數(shù)葱色,比如 name递宅、url、domain苍狰、path 等
coroutine emulate(): 模擬給定的設(shè)備指標(biāo)和用戶代理办龄。相當(dāng)于同時設(shè)置了 setUserAgent()、setViewport()
coroutine emulateMedia(): 模擬頁面的 CSS 媒體類型淋昭。參數(shù)為:screen俐填、print、None翔忽。
coroutine evaluate(): 在瀏覽器上執(zhí)行 js 并獲取結(jié)果
coroutine evaluateHandle(): 同上英融,只是會返回一個值盏檐。至于是什么,沒用過
coroutine evaluateOnNewDocument(): 也是執(zhí)行 js驶悟,至于區(qū)別胡野。好像是在頁面跳轉(zhuǎn)時執(zhí)行
coroutine exposeFunction(): 將 python 函數(shù)添加到瀏覽器的 window 對象中 name。不知道有什么用
coroutine focus(): 聚焦匹配的元素痕鳍。如果不存在硫豆,拋出 PageError
frames:獲取此頁面的所有 frame
coroutine goBack():返回上一個網(wǎng)頁。如果不存在笼呆,則返回 None
coroutine goForward(): 跳轉(zhuǎn)到下一頁熊响。如果不存在,則返回 None
-
coroutine goto(): 訪問某個 URL诗赌。
參數(shù):- url:汗茄。。境肾。
- timeout:剔难。。奥喻。
- waitUntil:什么情況下算成功訪問偶宫。沒看懂參數(shù)的幾個值有什么用
coroutine hover(): 鼠標(biāo)懸停匹配的元素
isClosed(): 判斷頁面是否關(guān)閉
keyboard: 獲取 keyboard 對象
mainFrame: 獲取 frame 頁面的主要內(nèi)容
coroutine metrics(): 好像是獲取頁面中的信息
mouse: 獲取 mouse 對象
coroutine reload(): 刷新網(wǎng)頁
-
coroutine screenshot(): 截圖
參數(shù):-
path
(str):保存圖像的文件路徑。屏幕截圖類型將從文件擴展名中推斷出來环鲤。 -
type
(str):指定屏幕截圖類型纯趋,可以是jpeg
或png
。默認(rèn)為png
冷离。 -
quality
(int):圖像的質(zhì)量吵冒,在 0-100 之間。不適用于png
圖像西剥。 -
fullPage
(bool):如果為 true痹栖,請截取完整的可滾動頁面。默認(rèn)為False
瞭空。 -
clip
(字典):指定頁面剪切區(qū)域的對象揪阿。此選項應(yīng)包含以下字段:-
x
(int):剪輯區(qū)域左上角的 x 坐標(biāo)。 -
y
(int):剪輯區(qū)域左上角的 y 坐標(biāo)咆畏。 -
width
(int):剪切區(qū)域的寬度南捂。 -
height
(int):剪切區(qū)域的高度。
-
-
omitBackground
(bool):隱藏默認(rèn)的白色背景并允許捕獲具有透明度的屏幕截圖旧找。 -
encoding
(str):圖像的編碼可以是'base64'
或'binary'
溺健。默認(rèn)為'binary'
。
-
coroutine select(): 選擇選項并返回所選值钮蛛。如果未找到元素鞭缭,拋出 ElementHandleError剖膳。
coroutine setCacheEnabled(): 為每個請求啟用/禁用緩存。默認(rèn)啟用
coroutine setContent(): 將 HTML 加到網(wǎng)頁
coroutine setCookie(): 設(shè)置 cookie
setDefaultNavigationTimeout(): 更改默認(rèn)的最大導(dǎo)航超時岭辣。默認(rèn) 30 秒
coroutine setJavaScriptEnabled(): 設(shè)置 JavaScript 啟用/禁用
coroutine setExtraHTTPHeaders(): 設(shè)置默認(rèn) headers 頭潮秘,值為一個字典
coroutine setRequestInterception(): 啟用/禁用請求攔截。配合 page.on()
coroutine setUserAgent(): 設(shè)置要在此頁面中使用的 UA
-
coroutine setViewport(): 設(shè)置窗口大小易结。
參數(shù):-
width
(int):以像素為單位的頁面寬度。 -
height
(int):以像素為單位的頁面高度柜候。 -
deviceScaleFactor
(float):默認(rèn)為 1.0搞动。 -
isMobile
(bool):默認(rèn)為False
。 -
hasTouch
(bool):默認(rèn)為False
渣刷。 -
isLandscape
(bool):默認(rèn)為False
鹦肿。
-
coroutine tap(): 點擊與之匹配的元素
coroutine title(): 獲取頁面標(biāo)簽
tracing:獲取 tracing 對象
coroutine type(): 往輸入框中輸入內(nèi)容,第一個參數(shù)為 CSS 選擇器辅柴,第二個為文本內(nèi)容
url:獲取此頁面的 url
waitFor(): 等待頁面上匹配的函數(shù)箩溃,超時或元素。參數(shù)可以是 int 或者 float碌嘀,單位毫秒涣旨。也可以是 CSS 選擇器
waitForFunction():
coroutine waitForNavigation(): 等到網(wǎng)頁跳轉(zhuǎn)
coroutine waitForRequest(): 等待請求
coroutine waitForResponse(): 等待回應(yīng)
waitForSelector(): 等到頁面上出現(xiàn)匹配的元素。其實 waitFor()也有同樣功能股冗。
waitForFunction(): 等到函數(shù)完成并返回一個值
coroutine waitForXPath(): 等到 xpath 頁面上出現(xiàn)匹配的元素
workers: 獲取頁面的所有 worker霹陡。至于是什么,我不知道
coroutine xpath(): ..
worker 類
page.on('workercreated', 函數(shù)) 這個函數(shù)傳入的參數(shù)就是 worker 類
- coroutine evaluate(): 同上
- coroutine evaluateHandle():同上
- coroutine executionContext():同上
- url: 同上
鍵盤類
- coroutine down(): 如果沒有參數(shù)止状,則是按下鼠標(biāo)左鍵烹棉。如果是鍵盤的某個值比如 shift、A 等鍵怯疤,則是相當(dāng)于按下這些鍵浆洗。
- coroutine press(): 同 down(),但是上面是不會釋放鼠標(biāo)或者鍵盤集峦,需要調(diào)用 up 方法釋放鼠標(biāo)伏社。
- coroutine sendCharacter:將字符發(fā)送到頁面。沒用過
- coroutine type(): 同上
- coroutine up(): 釋放由 down 按下的鍵或者鼠標(biāo)
鼠標(biāo)類
-
coroutine click(): 按下(x, y)處的按鈕
參數(shù):-
button
(STR): 少梁,left(左鍵)洛口、right(右鍵)或 middle(中鍵),默認(rèn)為left
凯沪。 -
clickCount
(int):默認(rèn)為 1第焰。 -
delay
(int | float):等待時間mousedown
和mouseup
以毫秒為單位的時間。默認(rèn)為 0妨马。
-
coroutine down(): 同上
coroutine move(): 移動鼠標(biāo)光標(biāo)挺举。
coroutine up(): 同上
tracing 類
創(chuàng)建可在 Chrome DevTools 或時間線查看器打開的跟蹤文件 杀赢,使用如下
await page.tracing.start({'path': 'trace.json'}) await page.goto('https://www.google.com')
await page.tracing.stop()
- coroutine start(): 開始跟蹤
- coroutine stop(): 停止跟蹤
不好用,可能是我不知道用
Dialog 類
page.on( 'dialog', 函數(shù))
湘纵,函數(shù)的參數(shù)就是這個類
- coroutine accept(): 接受對話框
- defaultValue: 如果對話框提示脂崔,則獲取默認(rèn)提示值
- coroutine dismiss(): 關(guān)閉對話框
- message: 獲取對話框消息
- type: 獲取對話框類型。類型有:
alert
梧喷,beforeunload
砌左,confirm
,或prompt
frame 類
- coroutine J():同上
- coroutine JJ():同上
- coroutine JJeval(): 同上
- coroutine Jeval(): 同上
- coroutine Jx(): 同上
- coroutine addScriptTag(): 同上
- coroutine addStyleTag(): 同上
- childFrames: 獲取子框架
- coroutine click(): 同上
- coroutine content(): 同上
- coroutine evaluate(): 同上
- coroutine evaluateHandle(): 同上
- coroutine executionContext(): 同上
- coroutine focus(): 同上
- coroutine hover(): 同上
- isDetached(): 如果此框架已分離铺敌,則返回 True
- name:獲取 frame 的名稱汇歹,如果沒有則返回 ID
- parentFrame:獲取父框架
后面這些屬性和 page 類一模一樣
ElementHandle 類
- coroutine J()
- coroutine JJ()
- coroutine JJeval()
- coroutine Jeval()
- asElement
- coroutine boundingBox(): 返回此元素的邊界框,如果元素不可見偿凭,則返回 None
- coroutine boxModel():返回元素框
- coroutine click()
- coroutine contentFrame(): 返回元素句柄的 frame
- coroutine focus()
- coroutine hover()
- coroutine isIntersectingViewport(): 如果元素在視口中可見产弹,則返回 True
- coroutine press()
- coroutine screenshot()
- coroutine tap()
- coroutine type()
- coroutine uploadFile(): 上傳文件
request 類
page.on('request', 函數(shù)) 這個函數(shù)傳入的參數(shù)就是 request 類
- coroutine abort(): 中斷請求
- coroutine continue_(): 使用可選的請求覆蓋繼續(xù)請求
參數(shù):-
url
(str):如果設(shè)置,請求 URL 將被更改弯囊。 -
method
(str):如果設(shè)置痰哨,則更改請求方法(例如GET
)。 -
postData
(str):如果設(shè)置匾嘱,則更改發(fā)布數(shù)據(jù)或請求斤斧。 -
headers
(dict):如果設(shè)置,則更改請求 HTTP 標(biāo)頭
-
- failure(): 返回錯誤文本
- frame : 返回匹配的 frame 對象
- headers: 返回此請求的 HTTP 標(biāo)頭字典
- isNavigationRequest(): 奄毡?折欠?
- method:返回此請求的方法
- postData: 返回此請求的帖子正文
- redirectChain: request 類重定向的所有請求
- resourceType:渲染引擎感知的此請求的資源類型
- coroutine respond(): 通過給定的參數(shù)修改請求
參數(shù):-
status
(int):響應(yīng)狀態(tài)代碼,默認(rèn)為 200吼过。 -
headers
(dict):可選的響應(yīng)頭锐秦。 -
contentType
(str):如果設(shè)置,則等于設(shè)置Content-Type
響應(yīng)頭盗忱。 -
body
(str | bytes):可選的響應(yīng)主體酱床。
-
- response(): 返回匹配的 response 對象
- url: 此請求的 URL
response 類
- buffer(): 返回相應(yīng)的字節(jié)內(nèi)容
- fromCache: 如果響應(yīng)是從緩存提供的,則返回 True趟佃。緩存可能是瀏覽器的磁盤緩存或者內(nèi)存扇谣,而不是服務(wù)器響應(yīng)的
- fromServiceWorker: 如果響應(yīng)由服務(wù)器提供,則返回 True
- headers: 返回此響應(yīng)的 HTTP 標(biāo)頭字典
- coroutine json(): 獲取響應(yīng)正文的 JSON
- ok: 返回 bool 此請求是否成功
- request: 獲取匹配的 request 對象
- securityDetails: 返回與此響應(yīng)關(guān)聯(lián)的安全詳細(xì)信息
- status: 響應(yīng)的狀態(tài)代碼
- coroutine text(): 獲取響應(yīng)正文的文本
- url : 響應(yīng)的 URL
target 類
我到現(xiàn)在還沒明白這是干什么的
- browser: 獲取目標(biāo)所屬的瀏覽器
- browserContext: 返回目標(biāo)所屬的瀏覽器上下文
- coroutine createCDPSession(): 創(chuàng)建附加到目標(biāo)的 Chrome Devtools 協(xié)議會話
- opener: 獲取打開此目標(biāo)的目標(biāo)
- coroutine page(): 獲取此目標(biāo)的頁面
- type: 獲取此目標(biāo)的類型
- url: 獲取此目標(biāo)的網(wǎng)址
CDPSession 類
- coroutine detach(): 從目標(biāo)分離會話
- send() :
Debugging
對于調(diào)試闲昭,您可以設(shè)置 for 和 功能logLevel
選項罐寨。但是,此選項會打印太多日志序矩,包括 pyppeteer 的 SEND / RECV 消息鸯绿。為了只顯示被抑制的錯誤消息,您應(yīng)該設(shè)置 logging.DEBUG 為 True
](javascript:void(0); "復(fù)制代碼")
<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">import asyncio import pyppeteer from pyppeteer import launch
pyppeteer.DEBUG = True # print suppressed errors as error log
async def main():
browser = await launch()
... # do something
asyncio.get_event_loop().run_until_complete(main()) </pre>
[](javascript:void(0); "復(fù)制代碼")