我們通常使用的抓包工具就是Fiddler和Charles這種圖形化的,Charles的優點是跨平臺,Windows和Mac都可以使用,Fiddler的優點是功能“極其”強大,不僅擁有抓包功能,還擁有中間人攻擊的功能,但是使用成本太高了,我們做爬蟲開發,使用到Fiddler的功能不過十之二三罷了。今天我們主要講的是mitmproxy這款工具,這是一款專業的中間人攻擊工具,mitmproxy 不僅可以截獲請求幫助開發者檢視、分析,最最重要的是支援Python進行定製化二次開發。例如:截獲瀏覽器的請求內容,並將資料處理後儲存到資料庫,再將內容交給瀏覽器;如果出現異常時,發出郵件通知,並返回給瀏覽器一個空的頁面。mitmproxy有以下幾個特點:
像正常代理一樣轉發請求,保證伺服器和客戶端之間的通訊可以攔截請求/返回,並可以修改請求/返回可以載入Python指令碼執行安裝mitmproxypip install mitmproxy
在Python環境中安裝使用pip最為簡潔。mitmproxy安裝完成以後會包含三個工具:mitmproxy、mitmdump、mitmweb。安裝完成以後直接在控制檯輸入mitmproxy --version就可以檢視版本資訊。
檢視版本資訊
注意如果是在Windows系統中安裝,需要先安裝Microsoft Visual C++ V14.0以上版本,並且mitmproxy是不能在Windows系統中進行抓包的,在執行mitmproxy --version命令的時候會得到一個錯誤提示。
Error: mitmproxy's console interface is not supported on Windows. You can run mitmdump or mitmweb instead.
在Windows系統中我們主要使用的是安裝完以後的另外兩個工具mitmdump和mitmweb。
安裝瀏覽器代理外掛SwitchyOmega為什麼要先安裝瀏覽器代理外掛呢?因為我們在使用抓包工具的時候,必須要通過代理訪問網路,才能抓到包,可以通過設定系統代理的方式來實現,但是直接設定瀏覽器代理會更加方便,而且使用代理外掛我們可以配置多種代理模式。Chrome瀏覽器安裝外掛需要科學上網,只要在度娘搜尋谷歌上網助手,安裝以後重啟瀏覽器,就可以訪問谷歌商店來安裝外掛了,外掛我們這裡推薦SwitchyOmega。安裝完以後要進行設定。
開啟選項開啟設定項新建情景模式
然後在瀏覽器中訪問地址前,先選擇代理方式,再進行訪問
安裝證書正常情況下,mitmproxy啟動後,只能抓取到HTTP請求的資訊,我們要抓取HTTPS請求資訊需要安裝證書。證書安裝有兩種方式:
第一種首先開啟mitmproxy進行抓包,即執行: mitmproxy或者另外兩個命令訪問http://mitm.it/如果你沒有開啟mitmproxy進行抓包的話,在這一步你會得到如下錯誤
上面這種方法我一直訪問不到mitm.it這個頁面,可以採用以下方式進行安裝
.cer是Mac或Linux下的證書,.p12是Windows下的證書,.pem是安卓下的證書。
通過上述兩種方式得到證書檔案後,證書按照步驟在網上找,非常多,這裡就不再敖述了。
使用mitmproxy要啟動 mitmproxy 用 mitmproxy、mitmdump、mitmweb 這三個命令中的任意一個即可,這三個命令功能一致,且都可以載入自定義指令碼,唯一的區別是互動介面的不同。但是他們各有特點,mitmproxy是進行抓包除錯使用的,mitmweb是mitmproxy的可視版本,mitmdump主要是載入指令碼執行的,因為mitmdump抓取的資訊是不主動顯示的,由我們在指令碼中使用特定列印方式,輸出到介面,方便我們除錯,當然也可以直接使用print列印。
在控制檯中輸入mitmdump -h,可以檢視命令列幫助,我們主要使用的是-s和-p引數,-p指定監聽埠,預設埠為8080,如果和其他軟體有衝突,可以通過此引數修改;-s指定執行指令碼,這個就是我們用mitmproxy的主要作用,通過載入指令碼,執行請求過程的中間處理,修改請求資料或者儲存返回資料。目前有兩種使用方式:
from mitmproxy import httpfrom mitmproxy import ctxdef response(flow: http.HTTPFlow): """ flow為引數,後面跟http.HTTPFlow表示宣告其型別, 這樣在IDE中就可以自動提示其屬性和方法,這是Python為我們提供的一種 便攜的方式,尤其是對外提供介面時,可以告知引數型別,這種方式是可選 的,當然你也可以使用常用方式,即不知道引數型別,只寫引數名即可 """ ctx.log.info(flow.request.url) ctx.log.warn(flow.request.headers)
mitmproxy.ctx.log為mitmproxy為我們提供的日誌列印方式。
from mitmproxy import httpclass Counter: def __init__(self): self.num = 0 def request(self, flow: http.HTTPFlow): self.num += 1 print("We've seen %d flows" % self.num) print(flow.request.url) print(flow.request.query)addons = [ Counter()]
官方推薦使用類的方式,上面的程式碼可能讓你有點迷茫,無論是使用類方式還是函式方式def reqeust函式都是在mitmdump內部回撥時會呼叫的,mitmdump就是使用這種事件回撥的方式,為我們提供了資料流的操作方式,那首先我們要了解mitmproxy為我們提供的事件(我們只關注HTTP相關的事件)。
class Events: def request(self, flow: http.HTTPFlow): """ The full HTTP request has been read. """ def response(self, flow: http.HTTPFlow): """ The full HTTP response has been read. """
request為請求傳送至伺服器前的回撥函式,如果我們想對傳送給伺服器的請求進行修改,可以在這裡進行處理。response為伺服器將請求資料返回給我們時的回撥函式,這裡就是我們爬取到的資料,在這裡我們可以對資料進行處理,做入庫處理。
我們在爬蟲中使用mitmproxy,主要就是對Request和Response物件進行操作,下面我在原始碼中把對應的屬性和方法都找出來,作為參考,就當作是字典一樣來查詢即可。原始碼在GitHub上下載,路徑為:mitmproxy/net/http/request.py和mitmproxy/net/http/response.py。
Requestflow.request.cookies #獲取請求的cookiesflow.request.headers # 獲取所有頭資訊,包含Host、User-Agent、Content-type等欄位flow.request.url # 完整的請求地址,包含域名及請求引數,但是不包含放在body裡面的請求引數flow.request.host # 域名flow.request.method # 請求方式。POST、GET等flow.request.scheme # 請求型別 ,如 http、httpsflow.request.path # 請求的路徑,url除域名之外的內容flow.request.text # 請求中body內容,可以獲取某些請求的引數,返回字典型別flow.request.replace() # 使用正則替換content中的內容flow.request.query # 返回MultiDictView型別的資料,url直接帶的鍵值引數,一般是GET請求的引數flow.request.content # bytes,結果如flow.request.textflow.request.raw_content # bytes,結果如flow.request.get_content()flow.request.urlencoded_form # MultiDictView,content-type:application/x-www-form-urlencoded 時的請求引數,不包含url直接帶的鍵值引數flow.request.multipart_form # MultiDictView,content-type:multipart/form-data 時的請求引數,不包含url直接帶的鍵值引數
Responseflow.response.status_code # 狀態碼flow.response.text # 返回內容,已解碼flow.response.content # 返回內容,二進位制flow.response.cookies # 返回的cookiesflow.response.headers # 返回的請求頭flow.response.replace() # 使用正則替換content中的內容
要特別注意,返回值為字典的型別的,不能直接在控制檯列印,可以使用str修飾,或者按照字典方式進行輸出。
以下為測試示例:
示例中使用兩個類Demo1、Demo2,主要是為大家展示類方式的好處,即可以使用多個類,每個類處理進行獨立的邏輯處理,每個類當中都可以同時使用request、response函式,希望不要因為例子裡面而誤導了大家。下面再說一點進階用法,每一個處理類,都可以單獨寫一個py檔案,再統一定義一個py檔案,匯入處理類,定義一個列表變數addons,變數中儲存所有處理類的例項,示例如下:demo1.py
from mitmproxy import httpclass Demo1: def request(self, flow: http.HTTPFlow): print('request url', flow.request.url) print('request name', flow.request.query.get('name')) print('request age', flow.request.query.get('age')) flow.request.query['name'] = 'yuehan'
demo2.py
from mitmproxy import httpclass Demo2: def response(self, flow: http.HTTPFlow): print('response name', flow.request.query.get('name'))
spider.py
import demo1import demo2addons = [ demo1.Demo1(), demo2.Demo2()]
抓包命令mitmdump -p 8888 -s spider.py
參考文章:
1.使用 mitmproxy + python 做攔截代理 https://blog.wolfogre.com/posts/usage-of-mitmproxy/
2.如何突破網站對selenium的遮蔽 https://blog.csdn.net/qq_26877377/article/details/83307208