摘要:爬蟲神器,對加密降維打擊是對無頭瀏覽器的封裝。使用等其他無頭瀏覽器的最大優(yōu)勢當然是對加密實行降維打擊,完全無視加密手段,對于一些需要登錄的應(yīng)用,也可以模擬點擊然后保存。請求過濾你的那一段頁面自動下拉腳本
爬蟲神器pyppeteer,對 js 加密降維打擊
pyppeteer?是對無頭瀏覽器?puppeteer的 Python 封裝。無頭瀏覽器廣泛用于自動化測試,同時也是一種很好地爬蟲思路。
使用 puppeteer(等其他無頭瀏覽器)的最大優(yōu)勢當然是對 js 加密實行降維打擊,完全無視 js 加密手段,對于一些需要登錄的應(yīng)用,也可以模擬點擊然后保存 cookie。而很多時候前端的加密是爬蟲最難攻克的一部分。當然puppeteer也有劣勢,最大的劣勢就是相比面向接口爬蟲效率很低,就算是無頭的chromium,那也會占用相當一部分內(nèi)存。另外額外維護一個瀏覽器的啟動、關(guān)閉也是一種負擔。
這篇文章我們來寫一個簡單的 demo,爬取拼多多搜索頁面的數(shù)據(jù),最終的效果如下:
我們把所有 api 請求的原始數(shù)據(jù)保存下來:
示例 json 文件如下:
開發(fā)環(huán)境python3.6+
最好是 python3.7,因為asyncio在 py3.7中加入了很好用的asyncio.run()方法。
安裝pyppeteer
如果安裝有問題請去看官方文檔。
python3 -m pip install pyppeteer
安裝 chromium
你懂的,天朝網(wǎng)絡(luò)環(huán)境很復(fù)雜,如果要用pyppeteer自己綁定的chromium,半天都下載不下來,所以我們要手動安裝,然后在程序里面指定executablePath。
下載地址:www.chromium.org/getting-inv…
hello worldpyppeteer?的 hello world 程序是前往exmaple.com截個圖:
import asyncio from pyppeteer import launch async def main(): browser = await launch({ # Windows 和 Linux 的目錄不一樣,情換成自己對應(yīng)的executable文件地址 "executablePath": "你下載的Chromium.app/Contents/MacOS/Chromium", }) page = await browser.newPage() await page.goto("http://example.com") await page.screenshot({"path": "example.png"}) await browser.close() asyncio.get_event_loop().run_until_complete(main())pyppeteer 重要接口介紹 pyppeteer.launch
launch 瀏覽器,可以傳入一個字典來配置幾個options,比如:
browser = await pyppeteer.launch({ "headless": False, # 關(guān)閉無頭模式 "devtools": True, # 打開 chromium 的 devtools "executablePath": "你下載的Chromium.app/Contents/MacOS/Chromiu", "args": [ "--disable-extensions", "--hide-scrollbars", "--disable-bundled-ppapi-flash", "--mute-audio", "--no-sandbox", "--disable-setuid-sandbox", "--disable-gpu", ], "dumpio": True, })
其中所有可選的args參數(shù)在這里:peter.sh/experiments…
dumpio的作用:把無頭瀏覽器進程的 stderr 核 stdout pip 到主程序,也就是設(shè)置為 True 的話,chromium console 的輸出就會在主程序中被打印出來。
注入 js 腳本可以通過page.evaluate形式,例如:
await page.evaluate(""" () =>{ Object.defineProperties(navigator,{ webdriver:{ get: () => false } }) } """)
我們會看到這一步非常關(guān)鍵,因為puppeteer出于政策考慮(這個詞用的不是很好,就是那個意思)會設(shè)置window.navigator.webdriver為true,告訴網(wǎng)站我是一個 webdriver 驅(qū)動的瀏覽器。有些網(wǎng)站比較聰明(反爬措施做得比較好),就會通過這個來判斷對方是不是爬蟲程序。
這等價于在 devtools 里面輸入那一段 js 代碼。
還可以加載一個 js 文件:
await page.addScriptTag(path=path_to_your_js_file)
通過注入 js 腳本能完成很多很多有用的操作,比如自動下拉頁面等。
截獲 request 和 responseawait page.setRequestInterception(True) page.on("request", intercept_request) page.on("response", intercept_response)
intercept_request和intercept_response相當于是注冊的兩個回調(diào)函數(shù),在瀏覽器發(fā)出請求和獲取到請求之前指向這兩個函數(shù)。
比如可以這樣禁止獲取圖片、多媒體資源和發(fā)起 websocket 請求:
async def intercept_request(req): """請求過濾""" if req.resourceType in ["image", "media", "eventsource", "websocket"]: await req.abort() else: await req.continue_()
然后每次獲取到請求之后將內(nèi)容打印出來(這里只打印了fetch和xhr類型response 的內(nèi)容):
async def intercept_response(res): resourceType = res.request.resourceType if resourceType in ["xhr", "fetch"]: resp = await res.text() print(resp) 大家在學(xué)python的時候肯定會遇到很多難題,以及對于新技術(shù)的追求,這里推薦一下我們的Python學(xué)習(xí)扣qun:784758214,這里是python學(xué)習(xí)者聚集地
一共有哪些resourceType,pyppeteer文檔里面有:
拼多多搜索爬蟲 頁面自動下拉拼多多的搜索界面是一個無限下拉的頁面,我們希望能夠?qū)崿F(xiàn)無限下拉頁面,并且能夠控制程序提前退出,不然一直下拉也不好,我們可能并不需要那么多數(shù)據(jù)。
js 腳本
async () => { await new Promise((resolve, reject) => { // 允許下滑的最大高度,防止那種可以無限下拉的頁面無法結(jié)束 const maxScrollHeight = null; // 控制下拉次數(shù) const maxScrollTimes = null; let currentScrollTimes = 0; // 記錄上一次scrollHeight,便于判斷此次下拉操作有沒有成功,從而提前結(jié)束下拉 let scrollHeight = 0; // maxTries : 有時候無法下拉可能是網(wǎng)速的原因 let maxTries = 5; let tried = 0; const timer = setInterval(() => { // 下拉失敗,提前退出 // BUG : 如果網(wǎng)速慢的話,這一步會成立~ // 所以設(shè)置一個 maxTried 變量 if (document.body.scrollHeight === scrollHeight) { tried += 1; if (tried >= maxTries) { console.log("reached the end, now finished!"); clearInterval(timer); resolve(); } } scrollHeight = document.body.scrollHeight; window.scrollTo(0, scrollHeight); window.scrollBy(0, -10); // 判斷是否設(shè)置了maxScrollTimes if (maxScrollTimes) { if (currentScrollTimes >= maxScrollTimes) { clearInterval(timer); resolve(); } } // 判斷是否設(shè)置了maxScrollHeight if (maxScrollHeight) { if (scrollHeight >= maxScrollHeight) { if (currentScrollTimes >= maxScrollTimes) { clearInterval(timer); resolve(); } } } currentScrollTimes += 1; // 還原 tried tried = 0; }, 1000); }); };
這里面有幾個重要的參數(shù):
interval : 下拉間隔時間,以毫秒為單位
maxScrollHeight : 運行頁面下拉最大高度
maxScrollTimes : 最多下拉多少次(推薦使用,可以更好控制爬取多少數(shù)據(jù))
maxTries : 下拉不成功時最多重試幾次,比如有時候會因為網(wǎng)絡(luò)原因?qū)е聸]能在 interval ms 內(nèi)成功下拉
把這些替換成你需要的。同時你可以打開 chrome 的開發(fā)者工具運行一下這段 js 腳本。
完整代碼這段代碼一共也就只有70多行,比較簡陋,情根據(jù)自己的實際需求更改。
import os import time import json from urllib.parse import urlsplit import asyncio import pyppeteer from scripts import scripts BASE_DIR = os.path.dirname(__file__) async def intercept_request(req): """請求過濾""" if req.resourceType in ["image", "media", "eventsource", "websocket"]: await req.abort() else: await req.continue_() async def intercept_response(res): resourceType = res.request.resourceType if resourceType in ["xhr", "fetch"]: resp = await res.text() url = res.url tokens = urlsplit(url) folder = BASE_DIR + "/" + "data/" + tokens.netloc + tokens.path + "/" if not os.path.exists(folder): os.makedirs(folder, exist_ok=True) filename = os.path.join(folder, str(int(time.time())) + ".json") with open(filename, "w", encoding="utf-8") as f: f.write(resp) async def main(): browser = await pyppeteer.launch({ # "headless": False, # "devtools": True "executablePath": "/Users/changjiang/apps/Chromium.app/Contents/MacOS/Chromium", "args": [ "--disable-extensions", "--hide-scrollbars", "--disable-bundled-ppapi-flash", "--mute-audio", "--no-sandbox", "--disable-setuid-sandbox", "--disable-gpu", ], "dumpio": True, }) page = await browser.newPage() await page.setRequestInterception(True) page.on("request", intercept_request) page.on("response", intercept_response) 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.setViewport({"width": 1080, "height": 960}) await page.goto("http://yangkeduo.com") await page.evaluate(""" () =>{ Object.defineProperties(navigator,{ webdriver:{ get: () => false } }) } """) await page.evaluate("你的那一段頁面自動下拉 js 腳本") await browser.close() if __name__ == "__main__": asyncio.run(main())
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/43958.html
摘要:注意,是叫做,不是。兩款瀏覽器同根同源,它們有著同樣的,但配色不同,由藍紅綠黃四種顏色組成,而由不同深度的藍色構(gòu)成。另外是基于的新特性實現(xiàn)的,所以它的一些執(zhí)行也支持異步操作,效率相對于來說也提高了。是否響應(yīng)信號,一般是命令,默認是。 如果大家對 Python 爬蟲有所了解的話,想必你應(yīng)該聽說過 Selenium 這個庫,這實際上是一個自動化測試工具,現(xiàn)在已經(jīng)被廣泛用于網(wǎng)絡(luò)爬蟲中來應(yīng)對 ...
摘要:時間永遠都過得那么快,一晃從年注冊,到現(xiàn)在已經(jīng)過去了年那些被我藏在收藏夾吃灰的文章,已經(jīng)太多了,是時候把他們整理一下了。那是因為收藏夾太亂,橡皮擦給設(shè)置私密了,不收拾不好看呀。 ...
摘要:接下來我們就來看看學(xué)到什么程度才算是真正學(xué)會可以去一展身手。一確立目標了解需求做什么事情都要先確定好目標,才不至于迷失方向。 大家在學(xué)習(xí)Python的時候,有人會問Python要學(xué)到什么程度才能出去找工作,對于在Python培訓(xùn)機構(gòu)學(xué)習(xí)Python的同學(xué)來說這都不是問題,因為按照Python課程大綱來,一般都不會有什么問題,而對于自學(xué)Python來說,那就比較難掌握,冒然出去找工作非常...
摘要:但是手動復(fù)制粘貼字典里的每一個鍵值對太費事了一個不那么方便的解決方案用正則表達式或者直接字符串替換,把字符串直接轉(zhuǎn)化為字典,封裝成函數(shù)方便以后反復(fù)調(diào)用。有的人喜歡用這種方法,每次復(fù)制信息,然后調(diào)用自己封裝好的函數(shù),但我覺得還是挺麻煩的。 今天介紹個神奇的網(wǎng)站!堪稱爬蟲偷懶的神器! 我們在寫爬蟲,構(gòu)建網(wǎng)絡(luò)請求的時候,不可避免地要添加請求頭( headers ),以 mdn 學(xué)習(xí)區(qū)為例,我...
摘要:獲取音樂播放列表其實,這就是小編要講的重點,因為就是這部分用到了加密。 1.前言 小編在這里講一下,下面的內(nèi)容僅供學(xué)習(xí)參考,切莫用于商業(yè)活動,一經(jīng)被相關(guān)人員發(fā)現(xiàn),本...
閱讀 3044·2023-04-25 20:09
閱讀 3321·2021-11-23 09:51
閱讀 1976·2021-11-22 15:25
閱讀 3353·2021-11-18 10:02
閱讀 2755·2021-09-27 13:56
閱讀 1309·2019-08-30 15:44
閱讀 1153·2019-08-30 13:21
閱讀 3326·2019-08-30 11:05