Python爬虫之pyppeteer的使用(爬虫、获取cookie、截屏插件、防爬绕过)
官方幫助:
- https://pyppeteer.github.io/pyppeteer/reference.html
?
下載文本中的網頁源碼,由于需要向下拉動滾動條所以使用pyppeteer渲染網頁,并執行js代碼,可是發現開啟無界面的時候似乎執行不了js代碼,還有異步的時候好像也執行不了js代碼
環境部署
pip install
pip install pyppeteer -i https://pypi.douban.com/simplechromium下載
chromium下載地址:https://npm.taobao.org/mirrors/chromium-browser-snapshots/
下載之后解壓之后,通過executablePath屬性指定運行瀏覽器了
啟動參數:
- ignoreHTTPSErrors (bool): 是否要忽略 HTTPS 的錯誤,默認是 False。
- headless (bool): 是否啟用 Headless 模式,即無界面模式,如果 devtools 這個參數是 True 的話,那么該參數就會被設置為 False,否則為 True,即默認是開啟無界面模式的。
- executablePath (str): 可執行文件的路徑,如果指定之后就不需要使用默認的 Chromium 了,可以指定為已有的 Chrome 或 Chromium。
- slowMo (int|float): 通過傳入指定的時間,可以減緩 Pyppeteer 的一些模擬操作。
- args (List[str]): 在執行過程中可以傳入的額外參數。
- ignoreDefaultArgs (bool): 不使用 Pyppeteer 的默認參數,如果使用了這個參數,那么最好通過 args 參數來設定一些參數,否則可能會出現一些意想不到的問題。這個參數相對比較危險,慎用。
- handleSIGINT (bool): 是否響應 SIGINT 信號,也就是可以使用 Ctrl + C 來終止瀏覽器程序,默認是 True。
- handleSIGTERM (bool): 是否響應 SIGTERM 信號,一般是 kill 命令,默認是 True。
- handleSIGHUP (bool): 是否響應 SIGHUP 信號,即掛起信號,比如終端退出操作,默認是 True。
- dumpio (bool): 是否將 Pyppeteer 的輸出內容傳給 process.stdout 和 process.stderr 對象,默認是 False。
- userDataDir (str): 即用戶數據文件夾,即可以保留一些個性化配置和操作記錄。
- env (dict): 環境變量,可以通過字典形式傳入。
- devtools (bool): 是否為每一個頁面自動開啟調試工具,默認是 False。如果這個參數設置為 True,那么 headless 參數就會無效,會被強制設置為 False。
- logLevel (int|str): 日志級別,默認和 root logger 對象的級別相同。
- autoClose (bool): 當一些命令執行完之后,是否自動關閉瀏覽器,默認是 True。
- loop (asyncio.AbstractEventLoop): 時間循環對象。
-
Python爬蟲 Pyppeteer 清空input輸入框的值
-
await page.evaluate('document.querySelector("#txt_account").value=""')
-
常見參數
| executablePath | str | chrome.exe運行的路徑 |
| ignorehttpserrrors | bool | 忽略https錯誤,默認false |
| headless | bool | True 開始無頭瀏覽器 False關閉無頭 |
| dumpio | bool | 設置True 解決瀏覽器多開卡死 |
args的參數設置:
| –disable-infobars | - | 關閉自動化提示框 |
| –window-size=1920,1080 | str | 設置瀏覽器大小嗎,1920是寬,1080是寬 |
| –log-level=30 | str | 日志保存等級 |
| –start-maximized | - | 窗口最大化模式 |
| –proxy-server=http://localhost:1080 | str | 設置代理 |
| userDataDir=D:\userData\ | str | 用戶文件保存地址 |
使用pyppeteer時有個bug會報錯,將源碼改動下就ok
鏈接:?這里.
設置viewport 自動獲取當前屏幕大小并設置viewport
# coding:utf8 import asyncio from pyppeteer import launchdef screen_size():"""使用tkinter獲取屏幕大小"""import tkintertk = tkinter.Tk()width = tk.winfo_screenwidth()height = tk.winfo_screenheight()tk.quit()return width, heightasync def main():launch_kwargs = {"headless": False}# 啟動瀏覽器browser = await launch(launch_kwargs)# 打開標簽頁page = await browser.newPage()# 默認 800 * 600 一般是不夠的print(page.viewport)#width, height = screen_size()# 設置網頁可視區域大小await page.setViewport({"width": width,"height": height})await browser.close()returnasyncio.get_event_loop().run_until_complete(main())導出或加載cookie
# 取出cookiecookies = await page.cookies()# 這里可以做些什么 :)pass# 然后導入cookieawait page.setCookie(*cookies)?
完整的一個實例
#!/usr/bin/python # -*- coding: UTF-8 -*- """ @time:2020/04/04 """import asyncio import logging import tkinterfrom pyppeteer import launch, launcher from lxml import etreeasync def main():# 瀏覽器 啟動參數start_parm = {# 啟動chrome的路徑"executablePath": r"C:\Users\yq\AppData\Local\pyppeteer\pyppeteer\local-chromium\722234\chrome-win\chrome.exe",# 關閉無頭瀏覽器"headless": False,"args": ['--disable-infobars', # 關閉自動化提示框# '--window-size=1920,1080', # 窗口大小'--log-level=30', # 日志保存等級, 建議設置越好越好,要不然生成的日志占用的空間會很大 30為warning級別'--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36', # UA'--no-sandbox', # 關閉沙盒模式'--start-maximized', # 窗口最大化模式# '--proxy-server=http://localhost:1080' # 代理r'userDataDir=D:\project_demo\python_demo\spider_demo\JavaScript 逆向系列課\userdata' # 用戶文件地址],}await page.goto('https://www.httpbin.org/headers')page_text = await page.content()input('----------------')await browser.close()asyncio.get_event_loop().run_until_complete(main())窗口/可視區最大化
但窗口設置最大化(–start-maximized)或窗口大小(–window-size=1920,1080)時,發現自己頁面可視區域沒有變化。成下面圖片顯示效果
設置可視化參數,代碼如下
# !/usr/bin/python # -*- coding: UTF-8 -*- """ @time:2020/04/04 """ import asyncio import tkinterfrom pyppeteer import launcher# 注意 在導入launch之前先把默認參數改了 # 去除自動化 啟動參數 launcher.AUTOMATION_ARGS.remove("--enable-automation") from pyppeteer import launchasync def main():# 瀏覽器 啟動參數start_parm = {# 啟動chrome的路徑"executablePath": r"C:\Users\yq\AppData\Local\pyppeteer\pyppeteer\local-chromium\722234\chrome-win\chrome.exe",# 關閉無頭瀏覽器"headless": False,"args": ['--disable-infobars', # 關閉自動化提示框'--no-sandbox', # 關閉沙盒模式'--start-maximized', # 窗口最大化模式],}browser = await launch(**start_parm)page = await browser.newPage()# 查看當前 桌面視圖大小tk = tkinter.Tk()width = tk.winfo_screenwidth()height = tk.winfo_screenheight()tk.quit()print(f'設置窗口為:width:{width} height:{height}')# 設置網頁 視圖大小await page.setViewport(viewport={'width': width, 'height': height})await page.goto('https://www.baidu.com')input('----------------')await browser.close()asyncio.get_event_loop().run_until_complete(main())隱藏瀏覽器特征
pyppeteer跟selenium一樣會有瀏覽器特征,所以需要修改,隱藏特征防止被識別。
主要有下面兩點:
攔截請求
可以對出現的請求,進行攔截 類似mitmproxy。
#!/usr/bin/python # -*- coding: UTF-8 -*- """ @time:2020/04/04 """import asyncio import jsonfrom jsonpath import jsonpath from pyppeteer import launcherlauncher.AUTOMATION_ARGS.remove("--enable-automation")from pyppeteer import launchfrom pyppeteer.network_manager import Request, Responseasync def intercept_request(req:Request):await req.continue_() # 請求,看源碼可以重新編寫請求async def intercept_response(res:Response):if 'ext2020/apub/json/prevent.new' in res.url:print('攔截到請求')json_text = await res.text()title_li = jsonpath(json.loads(json_text), '$..title')for title in title_li:print(title)passasync def main():# 瀏覽器 啟動參數start_parm = {# 啟動chrome的路徑"executablePath": r"C:\Users\yq\AppData\Local\pyppeteer\pyppeteer\local-chromium\722234\chrome-win\chrome.exe",# 關閉無頭瀏覽器 默認是無頭啟動的"headless": False,"args": ['--disable-infobars', # 關閉自動化提示框# '--no-sandbox', # 關閉沙盒模式'--start-maximized', # 窗口最大化模式'--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36',# UA],}# 創建瀏覽器對象,可以傳入 字典形式參數browser = await launch(**start_parm)# 創建一個頁面對象, 頁面操作在該對象上執行page = await browser.newPage()await page.setJavaScriptEnabled(enabled=True)# 啟用攔截器await page.setRequestInterception(True)page.on('request', intercept_request) page.on('response', intercept_response)js_text = """() =>{ Object.defineProperties(navigator,{ webdriver:{ get: () => false } });window.navigator.chrome = { runtime: {}, };Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] });Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5,6], });}"""await page.evaluateOnNewDocument(js_text) # 本頁刷新后值不變,自動執行jsawait page.goto('https://news.qq.com/') # 頁面跳轉await browser.close()asyncio.get_event_loop().run_until_complete(main()) # 創建異步池并執行main函數。按鈕路徑獲取(page.click)
谷歌瀏覽器 -> copy -> copy js path
獲取驗證碼
新建瀏覽器,進行登錄,由于驗證碼的識別準確率不是百分之百,需要多次嘗試。
async def main(self, username, pwd, url): # 定義main協程函數,login_count = 0# 打開瀏覽器browser = await launch({'headless': False, "userDataDir": r"./temp_data", 'args': ['--no-sandbox'], })# 登錄檢測while login_count < 10:# 登錄await self.login(browser, username, pwd, url)# 檢測是否登錄成功if await self.check_login(browser):breakelse:login_count += 1# 嘗試登錄次數大于10就退出if login_count > 10:print("login failed!")await browser.close()returndo_something()await browser.close()可以替換程序中驗證操作函數,實現不同的驗證方式。
其中提交過程采用了xpath定位提交按鈕。
驗證碼識別和輸入
我在這里利用了某網站的驗證碼識別api,通過http方式就能上傳驗證碼圖片,并獲取驗證碼。這個網站每天有固定的1000張圖片免費次數,足夠我們使用。第一個請求鏈接的用戶名和密碼換成我們注冊該網站的用戶名和密碼即可。具體可以看官方的API文檔。
該網站地址:http://fast.95man.com/
?
防檢測的一些方法
1、常用小功能
async def init_pyppeteer(self):self.browser = await pyppeteer.launch({'headless': False,# 'userDataDir': './userdata',# 用戶臨時目錄,保存cookie可以開啟'args': [# '--window-size={1300},{800}','--start-maximized', # 最大化窗口'--proxy-server=http://118.24.51.247:1443',#瀏覽器代理 配合某些中間人代理使用# '--load-extension={}'.format(chrome_extension), # 加載插件# '--disable-extensions-except={}'.format(chrome_extension),# '--disable-extensions','--hide-scrollbars','--disable-bundled-ppapi-flash','--mute-audio','--no-sandbox', # 取消沙盒模式 沙盒模式下權限太小'--no-sandbox', # 不顯示信息欄 比如 chrome正在受到自動測試軟件的控制'--disable-setuid-sandbox','--disable-gpu','--disable-infobars'# log等級設置 在某些不是那么完整的系統里 如果使用默認的日志等級 可能會出現一大堆的warning信息],'dumpio': True, # 減少內存消耗# "slowMo": 25 # 讓執行慢下來})self.page = await self.browser.newPage()width, height = self.screen_size()await self.page.setViewport({"width": width,"height": height})# 設置瀏覽器頭部await self.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 self.page.evaluateOnNewDocument('() =>{ Object.defineProperties(navigator,''{ webdriver:{ get: () => false } }) }') # 本頁刷新后值不變1.1、繞過對方網站監測
import pyppeteer async def page_evaluate(self, page):'''window.navigator.webdriver=false'''await page.evaluate('''() =>{ Object.defineProperties(navigator,{ webdriver:{ get: () => undefined } }) }''') # 以下為插入中間js,將淘寶會為了檢測瀏覽器而調用的js修改其結果。await page.evaluate('''() =>{ window.navigator.chrome = { runtime: {}, }; }''')await page.evaluate('''() =>{ Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] }); }''')await page.evaluate('''() =>{ Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5,6], }); }''')async def main(self):browser = await pyppeteer.launch()page = await browser.newPage()await self.page_evaluate(page)1.2、網絡通信異常處理
await page.goto(h5_detail_url,waitUntil=["networkidle0", "load", "domcontentloaded"],options={'timeout': 30000})1.3、禁止渲染
# # 是否啟用JS,enabled設為False,則無渲染效果 await self.page.setJavaScriptEnabled(enabled=False)1.4、等待元素加載
#waitForSelector 默認為30000(30秒),為0禁用超時 await self.page.waitForSelector('.shop_list .clearfix span.tit_shop',{'timeout': 9000}) #等待元素加載 await asyncio.sleep(2)1.5、滾動瀏覽器
使用js滾動到某個元素
# 使用js滾動到某個元素 await self.page.evaluate('document.querySelector(".page_al").scrollIntoView();')滾動到瀏覽器底部
#滾動到瀏覽器底部 await self.page.evaluate('window.scrollBy(0, document.body.scrollHeight)')滾動多少像素
#瀏覽器向上滾動400個像素 await self.page.evaluate('window.scrollBy(0,-400)')?
總結
以上是生活随笔為你收集整理的Python爬虫之pyppeteer的使用(爬虫、获取cookie、截屏插件、防爬绕过)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python3单例模式
- 下一篇: PyMongo官方文档翻译——VNPY