pyppeteer的使用(筆記,未完待續)


1、基本使用

--------------------------------------------

import asyncio
from pyppeteer import launch


async def main():
    browser = await launch(
        {'headless': False, 'userDataDir': r'C:\temp', 'autoClose': False,
         'args': ['--disable-infobars', '--no-sandbox']})
    page = await browser.newPage()
    await page.goto('https://login.taobao.com/member/login.jhtml?redirectURL=https://www.taobao.com/')
    await page.evaluate(
        '''() =>{ Object.defineProperties(navigator,{ webdriver:{ get: () => false } }) }''')
    await page.screenshot(path='example.png')
    await page.pdf(path='example.pdf')
    await asyncio.sleep(100)

asyncio.get_event_loop().run_until_complete(main())

 2、主要操作

browser = await launch();//啟動瀏覽器實例
page = await browser.newPage();//打開一個空白頁
await page.goto('https://example.com');//在地址欄輸入網址並等待加載
await page.screenshot({path: 'example.png'});//截個圖
await page.setUserAgent(
        'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299')
await page.goto('https://www.baidu.com')
await page.type('#kw', keyword, {'delay': 100}) 獲取輸入框焦點並輸入文字{'delay': input_time_random() - 50}
await page.click('#su')
await page.waitForNavigation({
      waitUntil: 'load'});//等待頁面加載出來,等同於window.onload
await browser.close();//關掉瀏覽器
content = await page.content()
cookies = await page.cookies()
await page.evaluate(js1)   //在網頁中執行js代碼
await page.keyboard.press 模擬鍵盤按下某個按鍵,目前mac上組合鍵無效為已知bug
page.waitFor 頁面等待,可以是時間、某個元素、某個函數
page.url 獲得當前訪問的url
await get_cookie(page)
page.frames() 獲取當前頁面所有的 iframe,然后根據 iframe 的名字精確獲取某個想要的 iframe
iframe.$('.srchsongst') 獲取 iframe 中的某個元素
iframe.evaluate() 在瀏覽器中執行函數,相當於在控制台中執行函數,返回一個 Promise
Array.from 將類數組對象轉化為對象
page.click() 點擊一個元素
iframe.$eval() 相當於在 iframe 中運行 document.queryselector 獲取指定元素,並將其作為第一個參數傳遞
iframe.$$eval 相當於在 iframe 中運行 document.querySelectorAll 獲取指定元素數組,並將其作為第一個參數傳遞
#await page.waitFor(10000)
# print(await (await item.getProperty('textContent')).jsonValue()) 獲取元素文本
# print(await (await item.getProperty('href')).jsonValue()) 獲取元素鏈接
View Code
View Code

以下是具體說明,更新中......

(1)打開瀏覽器

pyppeteer.launcher.launch(options: dict = None, **kwargs)

打開瀏覽器是通過pyppeteer.launcher.launch(options: dict = None, **kwargs) 方法,運行該函數后,會得到一個pyppeteer.browser.Browser實例,也就是說瀏覽器對象實例。launch方法是必須使用的方法,所以,詳細學學它的參數,你也直接閱讀官方文檔,因為我也是直接翻譯的:

  • ignoreHTTPSErrors (bool): 是否HTTPS錯誤,某人情況下為False.
  • headless (bool): 是否以無頭模式(無界面模式)執行,默認為True,為True時是不會彈出可視界面的,所以,上面代碼運行時設置headless=False。注意,下面還有個devtools參數,表示是否出現打開調試窗口,如果devtools設置為True,headless就算設置為False也會彈出可視界面。
  • executablePath (str): Chromium或Chrome瀏覽器的可執行文件路徑,如果設置,則使用設置的這個路徑,不使用默認設置.
  • slowMo (int|float): 設置這個參數可以延遲pyppeteer的操作,單位是毫秒.
  • args (List[str]): 要傳遞給瀏覽器進程的一些其他參數.
  • ignoreDefaultArgs (bool): 如果有些參數你不想使用默認值,那么,通過這個參數設置,不過,孩子,最好別用,有危險(電腦會爆炸).
  • handleSIGINT (bool): 是否響應 SIGINT 信號,是否允許通過快捷鍵Ctrl+C來終止瀏覽器進程,默認值為True,也就是允許.
  • handleSIGTERM (bool): 是否響應 SIGTERM 信號,也就是說kill命令關閉瀏覽器,,默認值為True,也就是允許.
  • handleSIGHUP (bool): 是否響應 SIGHUP 信號,即掛起信號,默認值為True,也就是允許.
  • dumpio (bool): 是要將瀏覽器進程的輸出傳遞給process.stdout 和 process.stderr 對象,默認為False不傳遞。
  • userDataDir (str): 用戶數據文件目錄.
  • env (dict): 以字典的形式傳遞給瀏覽器環境變量.
  • devtools (bool): 是否打開調試窗口,上面介紹headless參數是說過,默認值為False不打開.
  • logLevel (int|str): 日志級別,默認和 root logger 對象的級別相同.
  • autoClose (bool): 當所有操作都執行完后,是否自動關閉瀏覽器,默認True,自動關閉.
  • loop (asyncio.AbstractEventLoop): 時間循環。
  • appMode (bool): Deprecated.

打開瀏覽器操作簡單,看參數就行,不多介紹。

(2)調整窗口大小

如果你運行了上面的代碼,你會發現,打開的頁面只在窗口左上角一小塊顯示,看着很別扭,這是因為pyppeteer默認窗口大小是800*600,所以,調整一下吧。調整窗口大小通過方法實現,看下面代碼,最大化窗口:

import asyncio
from pyppeteer import launch
 
def screen_size():
    """使用tkinter獲取屏幕大小"""
    import tkinter
    tk = tkinter.Tk()
    width = tk.winfo_screenwidth()
    height = tk.winfo_screenheight()
    tk.quit()
    return width, height
 
async def main():
    browser = await launch(headless=False)
    page = await browser.newPage()
    width, height = screen_size()
    await page.setViewport({ # 最大化窗口
        "width": width,
        "height": height
    })
await page.goto('http://www.baidu.com/')
await asyncio.sleep(100)
await browser.close()
 
asyncio.get_event_loop().run_until_complete(main())
View Code

(3)設置userAgent,設置cookie,保存cookie

import asyncio
from pyppeteer import launch
 
async def main():
browser = await launch(headless=False)
page = await browser.newPage()
# 設置請求頭userAgent
await page.setUserAgent('Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Mobile Safari/537.36')
await page.goto('http://www.baidu.com/')
await asyncio.sleep(100)
await browser.close()
 
asyncio.get_event_loop().run_until_complete(main())
View Code
cookies = open(r'C:\Users\ho\Downloads\EditThisCookie\cookies.txt').read()
for item in json.loads(cookies):
    await page.setCookie(item)
await page.goto('http://www.xxx.com/')
View Code
# 保存cookie
async def save_cookie(cookie):
    with open("cookie.json", 'w+', encoding="utf-8") as file:
        json.dump(cookie, file, ensure_ascii=False)
View Code

(4)執行js腳本

有時候,為了達成某些目的(例如屏蔽網站原有js),我們不可避免得需要執行一些js腳本。執行js腳本通過evaluate方法。如下所示,我們通過js來修改window.navigator.webdriver屬性的值,由此繞過網站對webdriver的檢測:

import asyncio
from pyppeteer import launch
 
async def main():
js1 = '''() =>{
 
    Object.defineProperties(navigator,{
    webdriver:{
        get: () => false
        }
    })
}'''
 
js2 = '''() => {
    alert (
        window.navigator.webdriver
    )
}'''
browser = await launch({'headless':False, 'args':['--no-sandbox'],})
 
page = await browser.newPage()
await page.goto('https://h5.ele.me/login/')
await page.evaluate(js1)
await page.evaluate(js2)
 
asyncio.get_event_loop().run_until_complete(main())
View Code

在上面代碼中,通過page.evalute方法執行了兩段js腳本,第一段腳本將webdriver的屬性值設為false,第二段代碼在此讀取 webdriver屬性值,輸出為false。

import asyncio
from pyppeteer import launch

async def main():
    browser = await launch(headless=False, args=['--disable-infobars'])
    page = await browser.newPage()
    await page.goto('https://login.taobao.com/member/login.jhtml?redirectURL=https://www.taobao.com/')
    await page.evaluate(
        '''() =>{ Object.defineProperties(navigator,{ webdriver:{ get: () => false } }) }''')
    await asyncio.sleep(100)

asyncio.get_event_loop().run_until_complete(main())
View Code

 (5)模擬操作

pyppeteer提供了Keyboard和Mouse兩個類來實現模擬操作,前者是用來實現鍵盤模擬,后者實現鼠標模擬(還有其他觸屏之類的就不說了)。

主要來說說輸入和點擊:

import os
os.environ['PYPPETEER_HOME'] = 'D:\Program Files'
import asyncio
from pyppeteer import launch
 
async def main():
browser = await launch(headless=False, args=['--disable-infobars'])
page = await browser.newPage()
await page.goto('https://h5.ele.me/login/')
await page.type('form section input', '12345678999') # 模擬鍵盤輸入手機號
await page.click('form section button') # 模擬鼠標點擊獲取驗證碼
await asyncio.sleep(200)
await browser.close()
 
asyncio.get_event_loop().run_until_complete(main())
View Code

上面的模擬操作中,無論是模擬鍵盤輸入還是鼠標點擊定位都是通過css選擇器,似乎pyppeteer的type和click直接模擬操作定位都只能通過css選擇器(或者是我在官方文檔中沒找到方法),當然,要間接通過xpath先定位,然后再模擬操作也是可以的。下一小節中模擬登陸外賣平台就是用這種方法,不過,這種方法要麻煩一些,不推薦。

await page.hover('#alreday-login > a') #移動到元素上

              (參考https://www.jianshu.com/p/ccd4ae892440,模擬人工滑動操作)

(6)dialog點擊彈窗

from pyppeteer.dialog import Dialog

async def handle_dialog(page,dialog: Dialog):
    print(dialog.message)#打印出彈框的信息
    print(dialog.type)#打印出彈框的類型,是alert、confirm、prompt哪種
    # print(dialog.defaultValue())#打印出默認的值只有prompt彈框才有
    await page.waitFor(2000)#特意加兩秒等可以看到彈框出現后取消
    await dialog.dismiss()
   # await dialog.accept(‘000’) #可以給彈窗設置默認值

async def main():
    browser = await launch({'headless': False, 'userDataDir': r'C:\temp', 'autoClose': False, 'args': ['--disable-infobars', '--no-sandbox']})
    page = await browser.newPage()

    page.on('dialog', lambda dialog: asyncio.ensure_future(handle_dialog(page, dialog)))
    await page.goto('https://XXX.com/')
View Code

(7)某電商平台模擬登錄

用selenium + chrome 實現了模擬登陸這個電商平台,但是實在是有些麻煩,繞過對webdriver的檢測不難,但是,通過webdriver對瀏覽器的每一步操作都會留下特殊的痕跡,會被平台識別,這個必須通過重新編譯chrome的webdriver才能實現,麻煩得讓人想哭。不說了,都是淚,下面直接上用pyppeteer實現的代碼:

import os
os.environ['PYPPETEER_HOME'] = 'D:\Program Files'
import asyncio
from pyppeteer import launch
 
def screen_size():
    """使用tkinter獲取屏幕大小"""
    import tkinter
    tk = tkinter.Tk()
    width = tk.winfo_screenwidth()
    height = tk.winfo_screenheight()
    tk.quit()
    return width, height
 
 
async def main():
    js1 = '''() =>{
 
        Object.defineProperties(navigator,{
        webdriver:{
            get: () => false
            }
        })
    }'''
 
    js2 = '''() => {
        alert (
            window.navigator.webdriver
        )
    }'''
    browser = await launch({'headless':False, 'args':['--no-sandbox'],})
 
    page = await browser.newPage()
    width, height = screen_size()
    await page.setViewport({ # 最大化窗口
        "width": width,
        "height": height
    })
    await page.goto('https://h5.ele.me/login/')
    await page.evaluate(js1)
    await page.evaluate(js2)
    input_sjh = await page.xpath('//form/section[1]/input[1]')
    click_yzm = await page.xpath('//form/section[1]/button[1]')
    input_yzm = await page.xpath('//form/section[2]/input[1]')
    but = await page.xpath('//form/section[2]/input[1]')
    print(input_sjh)
    await input_sjh[0].type('*****手機號********')
    await click_yzm[0].click()
    ya = input('請輸入驗證碼:')
    await input_yzm[0].type(str(ya))
    await but[0].click()
    await asyncio.sleep(3)
    await page.goto('https://www.ele.me/home/')
    await asyncio.sleep(100)
    await browser.close()
 
asyncio.get_event_loop().run_until_complete(main())
View Code

登錄時,由於等待時間過長(我猜的)導致出現以下錯誤:

pyppeteer.errors.NetworkError: Protocol Error (Runtime.callFunctionOn): Session closed. Most likely the page has been closed.

在github上找到了解決方法,似乎只能改源碼,找到pyppeteer包下的connection.py模塊,在其43行和44行改為下面這樣:

self._ws = websockets.client.connect(
# self._url, max_size=None, loop=self._loop)
self._url, max_size=None, loop=self._loop, ping_interval=None, ping_timeout=None)

再次運行就沒問題了。可以成功繞過官方對webdriver的檢測,登錄成功,諸位可以自己嘗試一下。

3、總結

當使用selenium+webdriver寫爬蟲被檢測到時,pyppeteer是你得不二選擇,幾乎所有能在人工操作瀏覽器進行的操作通過pyppeteer都能實現,且能完美避開官方對webdriver的檢測。pyppeteer涉及的使用方法還很多,本文只介紹了常用方法的很小很小一部分,需要一說的是,pyppeteer的中文資料真的很少,多看看官方文檔吧。

待續:https://blog.csdn.net/u012206617/article/details/108323037


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM