powershell无法启动虚拟环境
0. 准备工作 参考文档:
什么是mitmproxy?
为什么要用mitmproxy?相比Fiddler 和 Charles它有什么优势?
mitmproxy
不仅可以截获请求帮助开发者查看、分析,更可以通过自定义脚本进行二次开发。举例来说,利用 Fiddler
可以过滤出浏览器对某个特定 url
的请求,并查看、分析其数据,但实现不了高度定制化的需求,类似于:“截获对浏览器对该 url
的请求,将返回内容置空,并将真实的返回内容存到某个数据库,出现异常时发出邮件通知”。而对于 **mitmproxy
**,这样的需求可以通过载入自定义 python
脚本轻松实现。特征
拦截HTTP和HTTPS请求和响应并即时修改它们 保存完整的HTTP对话以供以后重播和分析 重播HTTP对话的客户端 重播先前记录的服务器的HTTP响应 反向代理模式将流量转发到指定的服务器 macOS和Linux上的透明代理模式 使用Python对HTTP流量进行脚本化更改 实时生成用于拦截的SSL / TLS证书 还有更多…… 1. 安装 1.1 模块安装 安装:
查看安装成功与否:
出现以下字眼,则是成功安装了。
1 2 3 4 Mitmproxy: 5.2 Python: 3.7 .6 OpenSSL: OpenSSL 1.1 .1g 21 Apr 2020 Platform: Windows-10 -10.0 .18362 -SP0
1.2 证书安装 模块安装完成后,首次运行 mitmproxy
或 mitmdump
,在当前用户下面会生成几个 ca 证书。
从**Windows
**用户界面的 **.mitmproxy
**中,点击进去,可以看到有多个证书,
证书 作用 mitmproxy-ca.pem PEM格式的证书和私钥 。 mitmproxy-ca-cert.pem PEM格式的证书。使用它可以在大多数非Windows平台上分发。 mitmproxy-ca-cert.p12 PKCS12格式的证书。适用于Windows(安装这个 mitmproxy-ca-cert.cer 与.pem相同的文件,但某些Android设备需要扩展名。
**Windows
**端:
**手机
**端:
配置好wifi连接之后,访问 mitm.it
下载对应手机系统的证书,然后安装即可。 抓包示例:
**Windows
**端 **手机
**端配置**Windows
**端的ip + 指定代理!! 2. 组件 当我们谈论” **mitmproxy
**“时,我们通常指这三种工具中的任何一种–它们只是同一核心代理的不同前端。
正常使用用**mitmdump
**就足够了。
所以后面的案例也是使用 mitmdump
去做展示。
**mitmproxy
**默认绑定的端口为 127.0.0.1:8080
注意一下:
2.1 mitmproxy **Windows
**系统不可用,这里暂不展示。
2.2 mitmdump 查看所有命令:
查看版本:
常用命令:
1 2 3 4 5 -p 8888 -s xxx.py -w outfile -q quiet "~m post"
带有颜色的print:
**log
**,带有输出不同颜色的功能(个人觉得没有什么用 注意这里要使用cmd,使用PowerShell显示出来的颜色效果不完整。
mitmDemoOne.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Demo : def request (self, flow: mitmproxy.http.HTTPFlow ): """Print different colors""" url = flow.request.url if 'sunrise' in url: print (type (url)) ctx.log.info('Color White:' + url) ctx.log.warn('Color Yellow:' + url) ctx.log.error('Color Red:' + url) addons = [ Demo() ]
2.3 mitmweb 监听的端口是 127.0.0.1:8080
,
同时提供一个 web
交互界面在 127.0.0.1:8081
。
用 百度一下 示例。
介绍:
3. 简单使用示例 3.1 使用示例 正常使用用**mitmdump
**就足够了。所以这里主要用 mitmdump
来做一个展示,
后面的案例也是使用 mitmdump
去做展示。
基本操作的话,那只看 常规代理
方式就可以了;
操作模式:https://docs.mitmproxy.org/stable/concepts-modes/
脚本编写:https://docs.mitmproxy.org/stable/addons-scripting/
如何工作:https://docs.mitmproxy.org/stable/concepts-howmitmproxyworks/
测试网站:
常用的两个函数简单演示:
这里介绍一下使用的比较多的两个函数,其他的可以通过官方文档去进行一个系统的学习。
1 2 3 4 5 def request (flow ): pass def response (flow ): pass
common Description request = flow.request
request.url
url request.host
域名 request.headers
请求头 request.method
方式:POST、GET等 request.scheme
类型:http、https request.path
路径,URL除域名之外的内容 request.query
返回MultiDictView 类型的数据,URL的键值参数 request.query.keys()
获取所有请求参数键值的键 request.query.values()
获取所有请求参数键值的值 request.query.get('wd')
获取请求参数中**wd
** 键的值(前提是要有 wb
参数 request.query.set_all('wd', ['python'])
将wd
参数的值修改为 python
修改请求头:
mitmDemoTwo.py
1 flow.request.headers['User-Agent' ] = 'Mozilla/5.0'
将百度搜索修改为python:
mitmDemoThree.py
1 2 3 4 5 6 7 8 9 10 11 12 def request (flow ): if 'https://www.baidu.com' in flow.request.url: print (flow.request.query.get('wd' )) print (list (flow.request.query.keys())) print (list (flow.request.query.values())) flow.request.query.set_all('wd' ,['python' ]) print (flow.request.query.get('wd' ))
common Description response = flow.response
response.status_code
响应码 response.text
文本(同下) response.content
Bytes类型 response.headers
响应头 response.cookies
响应cookie response.set_text()
修改响应的文本 response.get_text()
文本(同上) flow.response= flow.response.make(404)
响应404
修改文本
mitmDemoFour.py
1 flow.response.set_text(text)
拒绝响应
mitmDemoFour.py
1 2 3 4 flow.response = mitmproxy.http.HTTPResponse.make(401 ) flow.response= flow.response.make(404 )
拒绝响应:在百度搜索 十八禁
mitmDemoFive.py
1 2 3 4 5 6 if flow.request.query.get('wd' ) == '十八禁' : flow.response = mitmproxy.http.HTTPResponse.make( 404 , b"You son of a bitch, Please leave." , {"Content-Type" : "text/html" } )
3.1.1 简单应用 需求 :
1 2 3 1. 修改请求(如果是搜索雷锋,则修改为 是小菜一碟吖2. 修改响应(将页面所有 Python 字眼 替换为 是小菜一碟吖3. 如果存在少儿不宜字眼(例:十八禁、迷药等),则拒绝响应,引导他向好
代码:
mitmDemoSix.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 import mitmproxy.httpfrom mitmproxy import ctxclass Demo : def request (self, flow: mitmproxy.http.HTTPFlow ): """Do somethings""" request = flow.request if 'https://www.baidu.com/' in request.url: keyword = request.query.get('wd' ) filter_words = ['迷药' , '十八禁' ] if keyword == '雷锋' : flow.request.query.set_all('wd' , ['是小菜一碟吖' ]) if keyword in filter_words: flow.response = mitmproxy.http.HTTPResponse.make( status_code=400 , content=''' <title>娘希匹!!!</title> <h1>警告!!!即将查水表</h1> <h2>望你善良,愿你向上</h2> <a>点击跳转:</a> <a href="https://space.bilibili.com/39880798" target="_blank">是小菜一碟吖的学习频道</a> ''' , headers={"Content-Type" : "text/html" } ) def response (self, flow: mitmproxy.http.HTTPFlow ): """Do somethings""" response = flow.response if flow.request.host == 'www.baidu.com' : replace_words = ['你好' , 'python' , 'Python' ] text = response.get_text() text = list (map (lambda x: text.replace(x, '是小菜一碟吖' ), replace_words))[0 ] flow.response.set_text(text=text) addons = [ Demo() ]
当然,这里超纲了,也就是觉得有趣,就拉出来讲一讲。
3.2 报错解决 1 2 502 Bad GatewayCertificate verification error for xxx: unable to get local issuer certificate (errno: 20 , depth: 0 )
网关证书验证错误,解决方法有二:
执行–ssl-insecure 下载最新的cacert.pem 替换( Python安装路径\Lib\site-packages\certifi
)的目录证书 4. 案例展示 4.1 mitmproxy + Selenium 电脑端自动化爬虫
案例说明:
Selenium 自动翻页,mitmproxy 进行信息采集,在指定网站,输入 指定关键词 以及 爬取的页码数量,即可。 注意点:
评论数量是另外一个文件,需要另外进行解析。 返回评论适量的链接有两个,要区别做判断。 selenium JD:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 """输入关键词 + 页码数量 Jd自动翻页程序""" import timefrom selenium import webdriverclass JdSpider : """OK""" def __init__ (self, keyword=None , page=None ): self.url = 'https://www.jd.com/' self.browser = None self.page = int (page) self.keyword = keyword def __del__ (self ): self.browser.close() def open_browser (self ): """打开浏览器""" self.browser = webdriver.Chrome() self.browser.set_window_size(1350 , 850 ) def search_keyword (self ): '''搜索关键字''' self.browser.get(self.url) self.browser.find_element_by_xpath('//*[@id="key"]' ).send_keys(self.keyword) self.browser.find_element_by_xpath('//*[@id="search"]/div/div[2]/button' ).click() def turn_page (self ): '''翻页''' self.browser.execute_script('window.scrollTo(0,document.body.scrollHeight)' ) time.sleep(3 ) if self.browser.page_source.find('pn-next disabled' ) == -1 : self.browser.find_element_by_class_name('pn-next' ).click() def main (self ): '''函数启动接口''' self.open_browser() self.search_keyword() for count in range (self.page): self.turn_page() if __name__ == '__main__' : keyword = input ("Enter the keywords to search:" ) page = input ("Enter the Page to download:" ) spider = JdSpider(keyword=keyword, page=page) spider.main()
网页解析 及 保存:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 import reimport osimport csvimport jsonfrom lxml import etreedef format_common (_list : list ): """格式化函数""" _str = '' .join(_list ) _str = _str .replace('\n' , '' ).replace('\t' , '' ).replace('¥' , '' ) return _str def format_state (_list : list ): """格式化函数""" _str = ' ' .join(_list ) _str = _str .replace('\n' , '' ).replace('\t' , '' ).replace('¥' , '' ) return _str class SaveData : """OK""" def __init__ (self, data ): self.comment_data = data[0 ] self.other_data = data[1 ] def judge_exists (self, path ): """判断文件是否已存在""" if os.path.exists(path): return title = ["商铺名称" , "说明" , "价格" , "评价人数" , "商品名称" ] with open (path, 'a+' , encoding='utf-8' , newline='' ) as f: writer = csv.writer(f) writer.writerow(title) def save_to_csv (self, data: list ): """保存为csv""" path = r'./data/JdGoodsInfo.csv' self.judge_exists(path) with open (path, 'a+' , encoding='utf-8' , newline='' ) as f: writer = csv.writer(f) writer.writerows(data) def parse_data (self ): """解析网页""" if not self.other_data or not self.comment_data: return comments_item = json.loads(re.findall("jQuery\d+\((.*?)\);" , self.comment_data)[0 ])['CommentsCount' ] if len (comments_item) != 30 : return _data = list () xpath_html = etree.HTML(self.other_data) xpath_items = xpath_html.xpath('//li[@class="gl-item"]' ) for xpath_item, comment_item in zip (xpath_items, comments_item): _parse = xpath_item.xpath shop = format_common(_parse('.//div[@class="p-shop"]//text()' )) icons = format_state(_parse('.//div[@class="p-icons"]//text()' )) price = format_common(_parse('.//div[@class="p-price"]//text()' )) name = format_common(_parse('.//div[@class="p-name p-name-type-2"]//text()' )) comment = comment_item['CommentCountStr' ] _data.append((shop, icons, price, comment, name)) self.save_to_csv(data=_data) def main (self ): """开始干活""" self.parse_data()
mitm代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 import jsonimport mitmproxy.httpfrom mitmSaveData import SaveDataclass Demo : def __init__ (self ): self.other_data = None def response (self, flow: mitmproxy.http.HTTPFlow ): url = flow.request.url if 'jd.com' not in url: return if 'https://search.jd.com/s_new.php?keyword=' in url: self.other_data = flow.response.text or None if 'https://club.jd.com/comment' in url: comment_data = flow.response.text SaveData([comment_data, self.other_data]).main() comment_data, self.other_data = None , None addons = [ Demo(), ]
遗留问题:
搜索的首页不是 XHR 形式加载出来的,这个不想做适配了。 4.2 mitmproxy + Appium 手机端自动化爬虫
案例说明:
Appium 自动翻页,mitmproxy 进行信息采集,在指定 App ,输入 指定关键词 以及 向下滑动的数量次数,即可。