简易实现一个APP录制 自动保存所触发接口信息的小脚本
应用场景:比如你操作一个APP,从登录,添加商品到购物车,然后点击去结算,支付,最后成功支付,最后到达订单详情,而这个脚本,就是将所这些操作触发的接口全部保存起来
原理:实际上就是利用MitmProxy做中间人代理,后台通过一系列规则,然后获取到每个flow(也可以叫做一个请求上下文,也就是我们常说的,请求+响应一个完整的会话),然后将这些flow的数据全部存起来,最后写到excel中去
下面来开始讲实现过程:
一:搭建MitmProxy环境
mac的用户参考文章:https://blog.csdn.net/Tester_xjp/article/details/104933501
二:编写代理脚本,这里命令成 one.py
依赖模块 pandas,xlsxwriter(这个直接pip安装即可)
# @project_name :person
# @file_name :one
# @auth :xiejiangpeng
# @time :2020-02-29
# @software :PyCharm
# @message
import mitmproxy.http
import pandas as pd
from mitmproxy import ctx
from urllib.parse import unquote
# 过滤
fittler_suffix = (".jpg", ".png", ".gz")
# 白名单域名
whitelist_host = ["mall.xsyxsc.com", "trade.xsyxsc.com", "mall-store.xsyxsc.com", "user.xsyxsc.com", "supertest"]
# 生成的api_info_excel地址
excel_filepath = "/Users/xiejiangpeng/python/mygithub/mypython/person/mitmproxj_api/api_info.xlsx"
# 没有在过滤规则中,同时在白名单域名中的host,当请求数达到下方设置值时,生成excel,同时断开代理
flow_max = 50
def fittler(flow=None):
""" 过滤
:param flow:
:return: 满足过滤条件返回True 不满足返回False
"""
if fittler_suffix and flow.request.url.endswith(fittler_suffix):
return True
return False
def whitelist(flow=None):
"""白名单域名
:param flow:
:return: 在白名单中的域名返回True 没有在白名单中的域名返回False
"""
if not whitelist_host:
return True
request_url = flow.request.url
sizer_url_list = whitelist_host
for sizer_url in sizer_url_list:
if sizer_url in request_url:
return True
return False
def convert(data):
"""byte类型->str类型
:param data:
:return:
"""
if isinstance(data, dict):
curr_data = {}
for key, value in data.items():
if isinstance(key, bytes):
key = convert(key)
if isinstance(value, bytes):
value = convert(value)
curr_data.update({key: value})
return curr_data
if isinstance(data, bytes):
return data.decode("utf-8")
return data
def url_decode(data=None):
return unquote(data, 'utf-8')
class FlowsData(object):
num = 1
flow_id = []
flow_url = []
flow_request_headers = []
flow_request_cookies = []
flow_request_data = []
flow_method = []
flow_response_data = []
flow_response_headers = []
flow_response_cookies = []
flow_http_version = []
__instance = None
def __new__(cls, *args, **kwargs):
if not cls.__instance:
cls.__instance = super().__new__(cls)
return cls.__instance
def __init__(self, flow: mitmproxy.http.HTTPFlow):
self.flow = flow
self.append_flowdata()
def append_flowdata(self):
self.flow_id.append(self.num)
self.num += 1
self.flow_url.append(self.flow.request.url)
self.flow_request_data.append(url_decode(self.flow.request.text))
self.flow_request_headers.append(convert(dict(self.flow.request.headers.get_state())))
self.flow_request_cookies.append(self.flow.request.cookies)
self.flow_method.append(self.flow.request.method)
self.flow_response_data.append(self.flow.response.text)
self.flow_response_headers.append(convert(dict(self.flow.response.headers.get_state())))
self.flow_response_cookies.append(self.flow.response.cookies)
self.flow_http_version.append(self.flow.request.http_version)
if self.num == flow_max + 1:
save_flow_to_excel(self,
filepath=excel_filepath)
exit()
def save_flow_to_excel(flowsdata: FlowsData = None, filepath: str = None) -> None:
flow_excel_dict = {
"请求ID": flowsdata.flow_id,
"请求地址": flowsdata.flow_url,
"请求参数": flowsdata.flow_request_data,
"请求头": flowsdata.flow_request_headers,
"请求cookie": flowsdata.flow_request_cookies,
"请求方法": flowsdata.flow_method,
"请求响应": flowsdata.flow_response_data,
"响应头": flowsdata.flow_response_headers,
"响应cookie": flowsdata.flow_response_cookies,
"http协议版本": flowsdata.flow_http_version,
}
if not filepath:
filepath = f'api_info.xlsx'
writer = pd.ExcelWriter(filepath)
df = pd.DataFrame(flow_excel_dict)
df.to_excel(writer, columns=flow_excel_dict.keys(), index=False, encoding='unicode-escape',
sheet_name='api_info', engine="xlsxwriter") # 其中engine=xlsxwriter是用来替换excel非法字符
writer.save()
class Counter:
def __init__(self):
self.num = 0
def response(self, flow: mitmproxy.http.HTTPFlow):
"""如果过滤了or 不在域名白名单里面,则直接跳过"""
if fittler(flow) or not whitelist(flow):
return None
self.num += 1
ctx.log.info(f"{flow.request.url[-100:]}这是我们过滤后接受到的{self.num}个请求上下文")
ctx.log.info(f"{flow.response.text[-100:]}这是我们过滤后接受到的{self.num}个响应数据")
FlowsData(flow)
addons = [
Counter()
]
三:运行脚本:
前提是你安装好了MitmProxy,同时安装好了证书,也就是说你的MitmProxy必须保证可以正常抓包
终端运行脚本
mitmdump -s /Users/xiejiangpeng/python/mygithub/mypython/person/mitmproxj_api/one.py -p 9999
ps:如果端口占用,则修改下端口即可
当然如果没有太多问题的话,你就可以跟我看到一样的输出结果了,这时候,你手机滑动你的目标软件,终端就会输出当前获取到到接口信息是多少条,当达到你设置当最大条数当时候,就会停止保存
ps:(这里暂时小编使用的是根据请求数来进行停止运行,后续可以优化成在终端捕获ctrl+c用户输入来进行触发退出)
如果没有什么问题,在五十个请求之后,你的代理就会自动断开
最后打开我们生成的excel,就可以看到操作触发的接口信息了
四:关于参数设置:
根据自己的需求设置即可,如果不想过滤任何东西,就都设置成None就行了
后续:有时候可能会遇到pandas.to_excel写入的时候,会因为一些非法字符报错,这个后续在解决
还没有评论,来说两句吧...