• 使用MitmProxy离线缓存360度全景网页


    📢博客主页:https://blog.csdn.net/as604049322

    📢欢迎点赞 👍 收藏 ⭐留言 📝 欢迎讨论!

    📢本文由 小小明-代码实体 原创,首发于 CSDN🙉

    昨天遇到一个问题:

    image-20220705085126329

    有些涉及动态加载的网页,有游览器自带的保存网页功能是无法保存全部资源的。

    假如我们手工挨个文件去保存,未免也太多了:

    image-20220705085423728

    超多的文件夹,一层一层的。

    此时我为了实现离线缓存目标网页,想到了一个好方法,那就是通过支持python编程的代理,让每一个请求都根据URL保存对应的文件到本地。

    MitmProxy的安装

    比较推荐MitmProxy,安装方法在命令行中执行:

    pip install mitmproxy
    
    • 1

    MitmProxy分为mitmproxy,mitmdump和mitmweb三个命令,其中mitmdump支持使用指定的python脚本处理每个请求(使用-s参数指定)。

    安装后我们需要安装证书MitmProxy对应的证书,访问:http://mitm.it/

    直接访问会显示:If you can see this, traffic is not passing through mitmproxy.

    这里我们先执行mitmweb启动一个网页版的代理服务器:

    image-20220705093554905

    我们给所使用的游览器,设置代理服务器的地址,以360安全游览器为例:

    image-20220705093759680

    在设置并使用MitmProxy提供的代理服务器之后再次访问http://mitm.it/就可以下载并安装证书了:

    image-20220705094637765

    下载后打开证书不断点击下一步即可安装完成。

    此时访问百度,可以看到MitmProxy的证书验证信息:

    image-20220705095101007

    编写mitmdump所需的脚本

    mitmdump所支持的脚本的模板代码如下:

    # 所有发出的请求数据包都会被这个方法所处理
    def request(flow):
        # 获取请求对象
        request = flow.request
        
    # 所有服务器响应的数据包都会被这个方法处理
    def response(flow):
        # 获取响应对象
        response = flow.response
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    request和response对象与requests库中的对象几乎一致。

    我们的需求是根据url保存文件,只需要处理响应即可,先尝试缓存百度首页:

    import os
    import re
    
    dest_url = "https://www.baidu.com/"
    
    
    def response(flow):
        url = flow.request.url
        response = flow.response
        if response.status_code != 200 or not url.startswith(dest_url):
            return
        r_pos = url.rfind("?")
        url = url if r_pos == -1 else url[:r_pos]
        url = url if url[-1] != "/" else url+"index.html"
        path = re.sub("[/\\\\:\\*\\?\\<\\>\\|\"\s]", "_", dest_url.strip("htps:/"))
        file = path + "/" + url.replace(dest_url, "").strip("/")
        r_pos = file.rfind("/")
        if r_pos != -1:
            path, file_name = file[:r_pos], file[r_pos+1:]
        os.makedirs(path, exist_ok=True)
    
        with open(file, "wb") as f:
            f.write(response.content)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    将上述脚本保存为dump.py然后使用如下命令启动代理(先关闭之前启动的mitmweb):

    >mitmdump -s dump.py
    Loading script dump.py
    Proxy server listening at http://*:8080
    
    • 1
    • 2
    • 3

    刷新页面后已经顺利缓存了百度首页:

    image-20220705103348348

    使用python自带的服务器测试运行并访问一下:image-20220705103914089

    可以看到已经顺利访问了本地的百度。

    离线缓存360全景网页

    将上述脚本的dest_url修改为如下地址并保存:

    dest_url = "https://img360wcs.soufunimg.com/2022/03/25/gz/720/3943919a3a7b46769db6f2db1f4250e5/html"
    
    • 1

    再次访问:https://img360wcs.soufunimg.com/2022/03/25/gz/720/3943919a3a7b46769db6f2db1f4250e5/html/index.html

    如果发现保存的文件不够全,可以打开开发者工具,在网络选项卡勾选 禁用缓存 后,再次刷新网页:

    image-20220705105213843

    此时主体文件已经全部缓存:

    image-20220705105256078

    此时只要尽量多的在原始网页上游览各个方向,并放大缩小就可以尽量多缓存更多高清细节图片。

    使用本地服务器启动测试已经顺利访问:

    image-20220705110127236

    不过原始脚本只缓存响应码为200的普通文件,上述网站还会返回响应码为206的分片音乐文件,如果也需要缓存就稍微复杂一些,下面我们研究一下如何缓存音乐文件。

    缓存206分片文件

    经过一番研究,将上述代码修改为如下形式即可:

    import os
    import re
    
    dest_url = "https://img360wcs.soufunimg.com/2022/03/25/gz/720/3943919a3a7b46769db6f2db1f4250e5/html"
    
    
    def response(flow):
        url = flow.request.url
        response = flow.response
        if response.status_code not in (200, 206) or not url.startswith(dest_url):
            return
        r_pos = url.rfind("?")
        url = url if r_pos == -1 else url[:r_pos]
        url = url if url[-1] != "/" else url+"index.html"
        path = re.sub("[/\\\\:\\*\\?\\<\\>\\|\"\s]", "_", dest_url.strip("htps:/"))
        file = path + "/" + url.replace(dest_url, "").strip("/")
        r_pos = file.rfind("/")
        if r_pos != -1:
            path, file_name = file[:r_pos], file[r_pos+1:]
        os.makedirs(path, exist_ok=True)
    
        if response.status_code == 206:
            s, e, length = map(int, re.fullmatch(
                r"bytes (\d+)-(\d+)/(\d+)", response.headers['Content-Range']).groups())
            if not os.path.exists(file):
                with open(file, "wb") as f:
                    pass
            with open(file, "rb+") as f:
                f.seek(s)
                f.write(response.content)
        elif response.status_code == 200:
            with open(file, "wb") as f:
                f.write(response.content)
    
    • 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

    保存修改完的脚本,mitmdump可以自动重载:

    image-20220705120628591

    清理缓存并重新访问之后,音乐文件已经顺利下载:

    image-20220705120742615

    总结

    通过mitmdump我们已经顺利实现了对指定网站的缓存,以后想缓存其他网站到本地只需要修改dest_url的网址即可。

  • 相关阅读:
    P272 小码君统统计字母频率-1
    WPF学习笔记-FlowDocument流文档基础知识和基本操作
    k8s+springcloud+nacos部署配置
    Redis发布订阅与原理
    中国电信CTWing OS最新进展
    别走,这里有一份摸鱼小妙招,别人我不告诉他!
    记录两次多端排查问题的过程
    C++中编写没有参数和返回值的函数
    暗恋云匹配匿名交友聊天系统开发
    【无标题】【3D建模制作技巧分享】zbrush中如何卡硬边?
  • 原文地址:https://blog.csdn.net/as604049322/article/details/125617140