来源: 阅读:- 2020-04-01 07:39:11
我们通常使用的抓包工具就是Fiddler和Charles这种图形化的,Charles的优点是跨平台,Windows和Mac都可以使用,Fiddler的优点是功能“极其”强大,不仅拥有抓包功能,还拥有中间人攻击的功能,但是使用成本太高了,我们做爬虫开发,使用到Fiddler的功能不过十之二三罢了。今天我们主要讲的是mitmproxy这款工具,这是一款专业的中间人攻击工具,mitmproxy 不仅可以截获请求帮助开发者查看、分析,最最重要的是支持Python进行定制化二次开发。例如:截获浏览器的请求内容,并将数据处理后存储到数据库,再将内容交给浏览器;如果出现异常时,发出邮件通知,并返回给浏览器一个空的页面。mitmproxy有以下几个特点:
pip 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。
为什么要先安装浏览器代理插件呢?因为我们在使用抓包工具的时候,必须要通过代理访问网络,才能抓到包,可以通过设置系统代理的方式来实现,但是直接设置浏览器代理会更加方便,而且使用代理插件我们可以配置多种代理模式。Chrome浏览器安装插件需要科学上网,只要在度娘搜索谷歌上网助手,安装以后重启浏览器,就可以访问谷歌商店来安装插件了,插件我们这里推荐SwitchyOmega。安装完以后要进行设置。
然后在浏览器中访问地址前,先选择代理方式,再进行访问
正常情况下,mitmproxy启动后,只能抓取到HTTP请求的信息,我们要抓取HTTPS请求信息需要安装证书。证书安装有两种方式:
如果你没有打开mitmproxy进行抓包的话,在这一步你会得到如下错误
上面这种方法我一直访问不到mitm.it这个页面,可以采用以下方式进行安装
.cer是Mac或Linux下的证书,.p12是Windows下的证书,.pem是安卓下的证书。
通过上述两种方式得到证书文件后,证书按照步骤在网上找,非常多,这里就不再敖述了。
要启动 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。
flow.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直接带的键值参数
flow.response.status_code # 状态码flow.response.text # 返回内容,已解码flow.response.content # 返回内容,二进制flow.response.cookies # 返回的cookiesflow.response.headers # 返回的请求头flow.response.replace() # 使用正则替换content中的内容
要特别注意,返回值为字典的类型的,不能直接在控制台打印,可以使用str修饰,或者按照字典方式进行输出。
以下为测试示例:
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'class Demo2: def response(self, flow: http.HTTPFlow): print('response name', flow.request.query.get('name'))addons = [ Demo1(), Demo2()]
示例中使用两个类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()]
参考文章:
1.使用 mitmproxy + python 做拦截代理 https://blog.wolfogre.com/posts/usage-of-mitmproxy/
2.如何突破网站对selenium的屏蔽 https://blog.csdn.net/qq_26877377/article/details/83307208
(正文已结束)
免责声明及提醒:此文内容为本网所转载企业宣传资讯,该相关信息仅为宣传及传递更多信息之目的,不代表本网站观点,文章真实性请浏览者慎重核实!任何投资加盟均有风险,提醒广大民众投资需谨慎!