简易实现一个APP录制 自动保存所触发接口信息的小脚本

古城微笑少年丶 2023-07-17 15:41 29阅读 0赞

应用场景:比如你操作一个APP,从登录,添加商品到购物车,然后点击去结算,支付,最后成功支付,最后到达订单详情,而这个脚本,就是将所这些操作触发的接口全部保存起来

原理:实际上就是利用MitmProxy做中间人代理,后台通过一系列规则,然后获取到每个flow(也可以叫做一个请求上下文,也就是我们常说的,请求+响应一个完整的会话),然后将这些flow的数据全部存起来,最后写到excel中去

下面来开始讲实现过程:

一:搭建MitmProxy环境

mac的用户参考文章:https://blog.csdn.net/Tester_xjp/article/details/104933501

二:编写代理脚本,这里命令成 one.py

依赖模块 pandas,xlsxwriter(这个直接pip安装即可)

  1. # @project_name :person
  2. # @file_name :one
  3. # @auth :xiejiangpeng
  4. # @time :2020-02-29
  5. # @software :PyCharm
  6. # @message
  7. import mitmproxy.http
  8. import pandas as pd
  9. from mitmproxy import ctx
  10. from urllib.parse import unquote
  11. # 过滤
  12. fittler_suffix = (".jpg", ".png", ".gz")
  13. # 白名单域名
  14. whitelist_host = ["mall.xsyxsc.com", "trade.xsyxsc.com", "mall-store.xsyxsc.com", "user.xsyxsc.com", "supertest"]
  15. # 生成的api_info_excel地址
  16. excel_filepath = "/Users/xiejiangpeng/python/mygithub/mypython/person/mitmproxj_api/api_info.xlsx"
  17. # 没有在过滤规则中,同时在白名单域名中的host,当请求数达到下方设置值时,生成excel,同时断开代理
  18. flow_max = 50
  19. def fittler(flow=None):
  20. """ 过滤
  21. :param flow:
  22. :return: 满足过滤条件返回True 不满足返回False
  23. """
  24. if fittler_suffix and flow.request.url.endswith(fittler_suffix):
  25. return True
  26. return False
  27. def whitelist(flow=None):
  28. """白名单域名
  29. :param flow:
  30. :return: 在白名单中的域名返回True 没有在白名单中的域名返回False
  31. """
  32. if not whitelist_host:
  33. return True
  34. request_url = flow.request.url
  35. sizer_url_list = whitelist_host
  36. for sizer_url in sizer_url_list:
  37. if sizer_url in request_url:
  38. return True
  39. return False
  40. def convert(data):
  41. """byte类型->str类型
  42. :param data:
  43. :return:
  44. """
  45. if isinstance(data, dict):
  46. curr_data = {}
  47. for key, value in data.items():
  48. if isinstance(key, bytes):
  49. key = convert(key)
  50. if isinstance(value, bytes):
  51. value = convert(value)
  52. curr_data.update({key: value})
  53. return curr_data
  54. if isinstance(data, bytes):
  55. return data.decode("utf-8")
  56. return data
  57. def url_decode(data=None):
  58. return unquote(data, 'utf-8')
  59. class FlowsData(object):
  60. num = 1
  61. flow_id = []
  62. flow_url = []
  63. flow_request_headers = []
  64. flow_request_cookies = []
  65. flow_request_data = []
  66. flow_method = []
  67. flow_response_data = []
  68. flow_response_headers = []
  69. flow_response_cookies = []
  70. flow_http_version = []
  71. __instance = None
  72. def __new__(cls, *args, **kwargs):
  73. if not cls.__instance:
  74. cls.__instance = super().__new__(cls)
  75. return cls.__instance
  76. def __init__(self, flow: mitmproxy.http.HTTPFlow):
  77. self.flow = flow
  78. self.append_flowdata()
  79. def append_flowdata(self):
  80. self.flow_id.append(self.num)
  81. self.num += 1
  82. self.flow_url.append(self.flow.request.url)
  83. self.flow_request_data.append(url_decode(self.flow.request.text))
  84. self.flow_request_headers.append(convert(dict(self.flow.request.headers.get_state())))
  85. self.flow_request_cookies.append(self.flow.request.cookies)
  86. self.flow_method.append(self.flow.request.method)
  87. self.flow_response_data.append(self.flow.response.text)
  88. self.flow_response_headers.append(convert(dict(self.flow.response.headers.get_state())))
  89. self.flow_response_cookies.append(self.flow.response.cookies)
  90. self.flow_http_version.append(self.flow.request.http_version)
  91. if self.num == flow_max + 1:
  92. save_flow_to_excel(self,
  93. filepath=excel_filepath)
  94. exit()
  95. def save_flow_to_excel(flowsdata: FlowsData = None, filepath: str = None) -> None:
  96. flow_excel_dict = {
  97. "请求ID": flowsdata.flow_id,
  98. "请求地址": flowsdata.flow_url,
  99. "请求参数": flowsdata.flow_request_data,
  100. "请求头": flowsdata.flow_request_headers,
  101. "请求cookie": flowsdata.flow_request_cookies,
  102. "请求方法": flowsdata.flow_method,
  103. "请求响应": flowsdata.flow_response_data,
  104. "响应头": flowsdata.flow_response_headers,
  105. "响应cookie": flowsdata.flow_response_cookies,
  106. "http协议版本": flowsdata.flow_http_version,
  107. }
  108. if not filepath:
  109. filepath = f'api_info.xlsx'
  110. writer = pd.ExcelWriter(filepath)
  111. df = pd.DataFrame(flow_excel_dict)
  112. df.to_excel(writer, columns=flow_excel_dict.keys(), index=False, encoding='unicode-escape',
  113. sheet_name='api_info', engine="xlsxwriter") # 其中engine=xlsxwriter是用来替换excel非法字符
  114. writer.save()
  115. class Counter:
  116. def __init__(self):
  117. self.num = 0
  118. def response(self, flow: mitmproxy.http.HTTPFlow):
  119. """如果过滤了or 不在域名白名单里面,则直接跳过"""
  120. if fittler(flow) or not whitelist(flow):
  121. return None
  122. self.num += 1
  123. ctx.log.info(f"{flow.request.url[-100:]}这是我们过滤后接受到的{self.num}个请求上下文")
  124. ctx.log.info(f"{flow.response.text[-100:]}这是我们过滤后接受到的{self.num}个响应数据")
  125. FlowsData(flow)
  126. addons = [
  127. Counter()
  128. ]

三:运行脚本:

前提是你安装好了MitmProxy,同时安装好了证书,也就是说你的MitmProxy必须保证可以正常抓包

终端运行脚本

mitmdump -s /Users/xiejiangpeng/python/mygithub/mypython/person/mitmproxj_api/one.py -p 9999

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1Rlc3Rlcl94anA_size_16_color_FFFFFF_t_70

ps:如果端口占用,则修改下端口即可

当然如果没有太多问题的话,你就可以跟我看到一样的输出结果了,这时候,你手机滑动你的目标软件,终端就会输出当前获取到到接口信息是多少条,当达到你设置当最大条数当时候,就会停止保存

ps:(这里暂时小编使用的是根据请求数来进行停止运行,后续可以优化成在终端捕获ctrl+c用户输入来进行触发退出)

如果没有什么问题,在五十个请求之后,你的代理就会自动断开

20200322223647637.png

最后打开我们生成的excel,就可以看到操作触发的接口信息了

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1Rlc3Rlcl94anA_size_16_color_FFFFFF_t_70 1

四:关于参数设置:

根据自己的需求设置即可,如果不想过滤任何东西,就都设置成None就行了

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1Rlc3Rlcl94anA_size_16_color_FFFFFF_t_70 2

后续:有时候可能会遇到pandas.to_excel写入的时候,会因为一些非法字符报错,这个后续在解决

发表评论

表情:
评论列表 (有 0 条评论,29人围观)

还没有评论,来说两句吧...

相关阅读