中间人爬虫利器

506 阅读5分钟

mitmproxy

是一个命令行下的抓包工具,作用和charles差不多,但可以在终端下工作。使用mitmproxy就可以实现自动化的抓包并从数据包里面得到有用的信息。 安装

pip install mitmproxy

要启动 mitmproxy 用 mitmproxy、mitmdump、mitmweb 这三个命令中的任意一个即可,这三个命令功能一致,且都可以加载自定义脚本,唯一的区别是交互界面的不同。 默认监听端口8080

  • mitmproxy 命令启动后,会提供一个命令行界面,用户可以实时看到发生的请求,并通过命令过滤请求,查看请求数据。
  • mitmweb 命令启动后,会提供一个 web 界面,用户可以实时看到发生的请求,并通过 GUI 交互来过滤请求,查看请求数据。
  • mitmdump 命令启动后——你应该猜到了,没有界面,程序默默运行,所以 mitmdump 无法提供过滤请求、查看数据的功能,只能结合自定义脚本,默默工作。加载 python 脚本

使用

  1. 可以通过上下移动鼠标滚轮的切换请求,选中某一请求后单击可查看请求详情
  2. 然后通过q命令可以返回到主界面,然后通过f命令加上要过滤的参数可以过滤请求,如下是只展示包含mitmproxy的请求
:      Command prompt
E      View event log  查看事件日志
O      View options  视图选项
enter  Select
q      Exit the current view 退出当前视图
tab    Next 
​
Keybindings for this view
;       Add comment to flow   向流程添加注释
A       Resume all intercepted flows  恢复所有被拦截的流
D       Duplicate flow  重复流
F       Set focus follow 设置焦点跟随
L       Load flows from file 从文件加载流
M       Toggle viewing marked flows 切换查看标记流
S       Start server replay 启动服务器重放
U       Un-set all marks 取消所有标记
V       Revert changes to this flow 将更改恢复到此流
X       Kill this flow 杀死这个流
Z       Purge all flows not showing 清除所有未显示的流
a       Resume this intercepted flow 恢复截取的流
b       Save response body to file 保存响应正文到文件
d       Delete flow from view 从视图中删除flow
e       Export this flow to file 导出该流到文件
f       Set view filter 设置视图过滤器
m       Toggle mark on this flow 此流上的切换标记
n       Create a new flow 创建新的流程
o       Set flow list order 设置流-列表按照啥顺序
r       Replay this flow 重新进行请求
v       Reverse flow list order 流列表-倒序排序
w       Save listed flows to file 保存列出的流程到文件
z       Clear flow list 清除流程列表
|       Run a script on this flow 在这个流上运行一个脚本
ctrl l  Send cuts to clipboard 发送剪切到剪贴板
​
Global Keybindings
-           Cycle to next layout 循环到下一个布局
:           Command prompt 命令提示符
?           View help
B           Start an attached browser 启动附加浏览器
C           View commands 查看命令
E           View event log
G           Go to end 到终点
I           Toggle whether the filtering via the intercept option is enabled 切换是否过滤通过拦截选项是启用的
K           View key bindings  Key Bindings界面
O           View options 视图选项
P           View flow details   Flow Details界面
Q           Exit immediately 立即退出
W           Stream to file
enter       Select
g           Go to start
h           Left
i           Set intercept 设置拦截
j           Down
k           Up
l           Right
q           Exit the current view
space       Page down
tab         Next
ctrl b      Page up
ctrl f      Page down
ctrl right  Focus next layout pane 聚焦下一个布局窗格
shift tab   Focus next layout pane
​
​
例子:
i 进入请求拦截  ~u /api/coach_info & ~q    拦截指定url,过滤器~q仅拦截请求,不拦截响应

访问HTTPS

通过手机浏览器访问mitm.it/下载代理

使用python定制mitmproxy

mitmdump命令可以用来运行符合一定规则的python脚本,并在python脚本里面直接操作HTTP和HTTPS的请求,以及返回的数据包。 文档:docs.mitmproxy.org/stable/

请求数据包

创建一个parse_request.py文件

def request(flow):
    print(flow.request.headers)

在命令行执行命令:

mitmdump -s parse_request.py

运行命令之后,打开一个app,可以看到app请求的头部信息已经出现在终端窗口中 也可以查看cookie、body信息等

def request(flow):
    req = flow.request
    print(f'当前请求的URL为:{req.url}')
    print(f'当前请求的请求方式为:{req.method}')
    print(f'当前请求的Cookies为:{req.cookies}')
    print(f'当前请求的body为:{req.text}')

返回数据包

创建一个parse_response.py文件

import json
def response(flow):
    resq = flow.response
    print(f'返回的头部为:{resq.headers}')
    print(f'返回的body为:{json.loads(resq.content)}')
    

针对性处理某个网站返回的数据。此时将请求和返回内容放在一起,且函数名必须为"response"

import json
def response(flow):
    req = flow.request
    resq = flow.response
    if 'kingname.info' in req.url:
        print('这是kingname的网站,也是我的目标网站')
        print(f'请求的headers为:{req.headers}')
        print(f'请求的UA为:{req.headers["User-Agent"]}')
        print(f'返回的内容为:{response.text}')
    

实际案例
mock本地文件
maplocal.py

from mitmproxy import http
import csv
import os
​
base_dir=os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
base_dir = os.path.join(base_dir, "mitmproxy_practice/mock")
mock_filePath=os.path.join(base_dir, "mock.csv")
​
def request(flow: http.HTTPFlow) -> None:
    if flow.request.method == "OPTIONS":
        flow.response = http.HTTPResponse.make(200, b"", {"Access-Control-Allow-Origin": "*",
                                                          "Access-Control-Allow-Methods": "*",
                                                          "Access-Control-Allow-Headers": "Origin,Content-Type,authcode,authrole,Accept,token,X-Requested-With,Authorization,HType,cipherKey,Content-Language",
                                                          "Access-Control-Allow-Credentia": "true",
                                                          "Allow": "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH",
                                                          "Access-Control-Expose-Headers": "cipherKey,Authentication"})
    else:
        with open(mock_filePath, encoding='utf-8') as f:
            reader = [x for x in csv.DictReader(f)]
​
        for r in reader:
            if r['is_mock'] == "1":
                # 发起请求,判断 url 是不是预期值
                if r['url'] in flow.request.pretty_url:
                    # 打开一个保存在本地的文件
                    with open(os.path.join(base_dir, r['file'])) as f:
                    # 创造一个 response
                        flow.response = http.Response.make(
                            200,  # (optional) status code
                            f.read(),  # (optional) content
                            {"Content-Type": "application/json"}  # (optional) headers
                        )

mock.csv

is_mock,url,file,commit
0,https://127.0.0.1/open/student/list/for/coach,student_index.json,平台生源
​

启动代理mitmproxy -p 8089 -s mitmproxy_practice/maplocal.py,这样就能方便mock本地数据了