利用mitmproxy提高埋点测试效率


该博文是以友盟web端埋点为例,简单讲述了如何用代理工具获取埋点请求、解码并保存数据,这样就不用手工一个一个地去看请求和decodeURI ei参数了。

数据埋点

  1. 友盟统计点击事件埋点
    api介绍(https://open.cnzz.com/a/api/trackevent/)

  2. 纯手工测试做法

    1. 打开要测的网站,打开开发者工具,点击埋点的控件,如果已经做了埋点,应该能看到network页给https://ei.cnzz.com发送了一条get请求

    2. 点开这个请求,能看到有个ei参数

    3. 把ei参数的值拷贝下来,去控制台用chrome自带函数decodeURI解码成中文,再去跟需求文档对比

    可以看到,由于中文和一些特殊字符被转码了,每次都要去控制台手动解码才能看到发送的数据,这样非常枯燥而且效率极低。

    所以想到在页面上点点点的时候用个代理工具获取发送给ei.cnzz.com的所有请求,并自动解码,这样总比一个一个去解效率高吧。当然你也可以进一步把点点点也用自动化取代,但是这个会比较耗时,所以这里就先没做了。

mitmproxy

  1. 什么是mitmproxy
    官网(https://www.mitmproxy.org/),是一个跟ClashX类似的代理工具,但是更灵活,能根据你的需求定制功能。包含mitmdump, mitmproxy, mitmweb等命令行和web端工具。
  2. 如何配置
    mac上直接 brew install mitmproxy, pip install mitmproxy, 按官网给的步骤配置好证书。
  3. 怎样使用
    1. 比如想记录我们发送了多少个请求,可以建一个python文件 'req_counter.py', 写上代码:
      	import mitmproxy.http
      	from mitmproxy import ctx
      
      
      	class Counter:
      		def __init__(self):
      			self.num = 0
      
      		def request(self, flow: mitmproxy.http.HTTPFlow):
      			self.num = self.num + 1
      			ctx.log.info("We've seen %d flows" % self.num)
      
      	addons = [
      		Counter()
      	]
      
    2. 在terminal执行下面脚本,在8080端口启动一个mitmproxy
      PYTHONPATH=. mitmdump -p 8080 -s /Users/xxx/mitm/req_counter.py
    3. 打开另一个terminal, 设置好chrome的代理启动chrome
      /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --proxy-server=127.0.0.1:8080 --ignore-certificate-errors
    4. 此时打开任意网页,应该就能在mitmdump命令控制台看到输出了请求数

编写脚本过滤和处理请求

  1. 直接用flow.request.query.get("ei") 获取 ei的值,比较简洁

    	import mitmproxy.http
    	import urllib
    	import time
    
    	addons = [
    		GetDataFromURL()
    	]
    	class GetDataFromURL:
    		def __init__(self):
    			self.num = 0
    
    		def request(self, flow: mitmproxy.http.HTTPFlow):
    			if flow.request.host != "ei.cnzz.com":  # 忽略非ei.cnzz.com的请求
    				pass
    			else:
    				self.num += 1
    				ei = flow.request.query.get("ei")
    				ei = urllib.parse.unquote(ei).split('|')
    				res = [urllib.parse.unquote(e) for e in ei]  # 再次解码每个子串
    				with open('maidian/maidian.txt', 'a+') as f:
    					f.write(str(self.num) + ',' 
    					+ time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())
    							+ ',' + '-'.join(r for r in res) + '\n')
    
  2. 通过flow.request.path获取到ei(只写了处理res的那段代码)

    paths = flow.request.path[10:].split("&")  # 用&分割查询参数
    			for path in paths:
    				if path.split('=')[0] == 'ei':  # 如果参数是ei
    					p1 = path.split('=')[1]  # 获取ei的值
    					p1 = urllib.parse.unquote(p1).split('|')
    					# urllib.parse.unquote(p1) 解码ei的值
    					# 值里面还有|分隔符,且中文没有被解码掉,用它再次分割字符串
    					res = [urllib.parse.unquote(p) for p in p1]  # 再次解码每个子串
    
  3. 在命令行启动mitmproxy和chome, 在页面上操作,就能看到抓包的数据已经写入到了 maidian.txt
    PYTHONPATH=. mitmdump -p 8080 -s /Users/anna/mitm/req_counter.py