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