首页 > 编程语言 >mht文件图片提取 python

mht文件图片提取 python

时间:2023-10-26 14:22:22浏览次数:38  
标签:content 提取 python base64 Content file mht line

简介

mhtml文件又称为聚合html文档、web档案或单一文件网页。单个文件网页可将网站的所有元素(包括文本和图形)都保存到单个文件中。总的来说mht文件保存了一个网页内的所有元素,让用户可以在没有网络的情况下访问网页。

本程序提取mht文件中的图片并保存至新建文件夹,同时将其压缩。食用方法:

  • 将代码复制存为python文件
  • mht文件放在代码同级目录下
  • 双击运行代码

随后即可在同级目录下生成图片文件夹和压缩文件夹。

实现效果

以下是保存的网页,是一章漫画。

运行程序截图:

>>>>>>> python -u "d:\CODE\extract_test\mht_img_extract.py"
[Find File] 第52话 - 想要成为影之实力者.mht
[File Nums] 1

------------------------------------------PROCESS [1/1]-----------------------------------
[File Name] 第52话 - 想要成为影之实力者.mht
[File Path] D:\CODE\extract_test
[New Folder] 第52话 - 想要成为影之实力者
[Saved Img] 36
[Raw/Compressed] 9.50 / 8.78 MB

文件保存截图:

实现思路

下面是截取mht文件部分内容:

------MultipartBoundary--K1usUkalTqg3WEUJLmLQ5xNVwipkHNGg7EXVdLUiFp----
Content-Type: image/jpeg
Content-Transfer-Encoding: base64
Content-Location: https://s1-a3-ussv.baozicdn.com/scomic/xiangyaochengweiyingzhishilizhe-fengzedajiebanyexingli/0/52-lros/1.jpg  

/9j/4SSgRXhpZgAATU0AKgAAAAgADAEAAAMAAAABBFoAAAEBAAMAAAABBkAAAAECAAMAAAADAAAA
ngEGAAMAAAABAAIAAAESAAMAAAABAAEAAAEVAAMAAAABAAMAAAEaAAUAAAABAAAApAEbAAUAAAAB
AAAArAEoAAMAAAABAAIAAAExAAIAAAAhAAAAtAEyAAIAAAAUAAAA1YdpAAQAAAABAAAA7AAAASQA
CAAIAAgACvyAAAAnEAAK/IAAACcQQWRvYmUgUGhvdG9zaG9wIDIyLjMgKE1hY2ludG9zaCkAMjAy
MzowNDozMCAwOTo1Njo1OQAAAAAABJAAAAcAAAAEMDIzMaABAAMAAAABAAEAAKACAAQAAAABAAAE
.................源文件base64编码太长,这里截取部分作为演示....................
+04k3NZyLMy+w+/+O38K9CgmjngSaJ90cihlb2PSuIkgjnieKVEaORdrKycMD/T+VT/De/kfQ7jR
bn/j50aZrX5uvldYj/3xigDt6KKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKK
ACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA
in/495P9014r+z397xV/19r/AOzV7VP/AMe8n+6a8V/Z7+94q/6+1/8AZqAPb6KKKACiiigAoooo
AKKKKACkpaSgD//Z

------MultipartBoundary--K1usUkalTqg3WEUJLmLQ5xNVwipkHNGg7EXVdLUiFp----
Content-Type: image/jpeg
Content-Transfer-Encoding: base64
Content-Location: https://s1-a3-ussv.baozicdn.com/scomic/xiangyaochengweiyingzhishilizhe-fengzedajiebanyexingli/0/52-lros/6.jpg

从这里我们可以看出这是一个图片,使用base64编码。接下来我们就需要遍历mht文件,寻找------MultipartBoundary--K1usUkalTqg3WEUJLmLQ5xNVwipkHNGg7EXVdLUiFp----。找到这一行,紧随其后就是一个图片文件的说明部分,据此我们可以获取图片的基本信息。

  • Content-Type 说明了图片文件类型
  • Content-Transfer-Encoding 说明了文件编码方式
  • Content-Location 说明了文件的网址

在base64编码的末尾有一个空行,读取到空行即说明遍历完了一张图片,接下来我们只需使用python的base64.b64decode()即可还原图片,之后将其保存即可。当然其中还有许多细节问题,比如图片名获取、图片大小限制、空行判断问题等等,在以下代码中均已实现。

实现代码

import base64
import os
import zipfile

FILE_EXIST_AUTO_REWRITE = 1 
IMG_NAME_REWRITE = 1
BASE64_LINE_THRESHOLD = 500


def saveImg(file_path, folder_path):
    img_dic = dict()     # key:img name, value:lines
    skipped_dic = dict() # key:file name, value:encode
    sifted_dic = dict()  # key:img name, value:lines     
    with open(file_path, 'rb') as file:
        line = file.readline().decode()

        while line != '':
            # seek to the header of base64 code
            line = file.readline().decode()
            if 'Boundary' in line and line[0] == '-':
                content_type = file.readline().decode().replace(':', '').replace('/', ' ').split() # Content-Type
                content_encode = file.readline().decode().replace(':', '').replace('/', ' ').split() # Content-Location
                content_location = file.readline().decode().replace(':', '').replace('/', ' ').split() # Content-Transfer-Encoding
                if content_type == [] or content_encode == [] or content_location == []:
                    continue
                file_type = content_type[-1]
                file_encode = content_encode[-1]
                file_name = content_location[-1].split('?')[0]
                img_name = ''

                # file type is image
                if content_type[1] == 'image' and file_encode == 'base64':
                    line = file.readline()                            # blank line after Content-Location
                    line = file.readline().decode().replace('\n', '') # first line of base64
                    base64_str = line 
                    lines = 0  
                    while True:  
                        line = file.readline().decode()  
                        lines += 1
                        base64_str += line.replace('\n', '')
                        if len(line) <= 2: # blank line after base64 code has 2 bytes
                            break               
                    # img is too small
                    if lines <= BASE64_LINE_THRESHOLD:
                        sifted_dic[file_name] = lines
                    # img fit the threshold
                    else:      
                        if IMG_NAME_REWRITE == 1:
                            img_name = str(len(img_dic)+1).zfill(4) + '.' + file_type  # fill leading_zero
                        elif IMG_NAME_REWRITE == 0:
                            img_name = file_name.split('.')[0] + '.' + file_type                           
                        img_dic[img_name] = lines
                        base64_decode = base64.b64decode(base64_str)    
                        img = open(folder_path + '/' + img_name, "wb")
                        img.write(base64_decode)
                        img.close()
                # file type is not image
                else:
                    skipped_dic[file_name] = file_encode
    # reach the end of file
    print('[Saved Img] %d'%(len(img_dic)))
    # print('[Saved Img] [name:lines]: \n', img_dic)
    # print('[Sifted Img] [name:lines]: \n', sifted_dic)
    # print('Skipped [name:encode]: ', skipped_dic)


def getDirSize(dir):
   size = 0
   for root, dirs, files in os.walk(dir):
      size += sum([os.path.getsize(os.path.join(root, name)) for name in files])
   return size


def zipImg(folder_path, folder_name):
    zip_name = folder_name+'.zip'
    zip = zipfile.ZipFile(zip_name, 'w', zipfile.ZIP_DEFLATED)   
    for file in os.listdir(folder_path):
        zip.write(folder_path + os.sep + file, file)
    zip.close()
    dir_size = getDirSize(folder_path)
    zip_size = os.path.getsize(zip_name)
    print(r'[Raw/Compressed] %.2f / %.2f MB'%(dir_size/1024/1024, zip_size/1024/1024))


def extractFile(FILE_NAME):
    CUR_PATH = os.getcwd()
    cur_file = os.path.join(CUR_PATH, FILE_NAME)
    # file exist
    if(os.path.isfile(cur_file)):
        print("[File Name]", FILE_NAME)
        print("[File Path]", CUR_PATH)
        folder_name = '.'.join(FILE_NAME.split('.')[0:-1])
        folder_path = os.path.join(CUR_PATH, folder_name)
        # folder exist
        if os.path.exists(folder_path):   
            if FILE_EXIST_AUTO_REWRITE == 1:
                pass
            elif FILE_EXIST_AUTO_REWRITE == 0:
                print("Folder Exist:", folder_name, "Rewrite It? [y/n]", end=" ")
                confirm = input()
                if confirm == 'y':
                    pass
                elif confirm == 'n':
                    return
        # folder not exist, create it
        else:
            os.makedirs(os.path.join(CUR_PATH, folder_name))
            print("[New Folder]", folder_name)
        saveImg(cur_file, folder_path)
        zipImg(folder_path, folder_name)   
    #file not exist, exit
    else:
        print("No This File!")
        return


def getTargetFile():
    file_list = os.listdir(os.getcwd())
    target_file_list = []
    for file in file_list:
        if file.split('.')[-1] == 'mht':
            target_file_list.append(file)
    for file in target_file_list:
        print('[Find File]', file)
    print('[File Nums]', len(target_file_list))
    return target_file_list


if __name__ == '__main__':
    target_file_list = getTargetFile()
    for index, file in enumerate(target_file_list):
        print("\n------------------------------------------PROCESS [{}/{}]-----------------------------------".format(index+1, len(target_file_list)))
        extractFile(file)
        

标签:content,提取,python,base64,Content,file,mht,line
From: https://www.cnblogs.com/PaintingSky/p/17789210.html

相关文章

  • 第一个python程序-计算机
    defadd(num1,num2):returnnum1+num2defsub(num1,num2):returnnum1-num2defmul(num1,num2):returnnum1*num2defdiv(num1,num2):returnnum1/num2calc={1:add,2:sub,3:mul,4:div}print('欢迎使用计算器!')fst_num=flo......
  • python博客园下载所有文章保存为Mardown
    简易代码importrequestsfrombs4importBeautifulSoupimportreimporthtml2textimportossession=requests.session()cookies={#换成自己的cookies}headers={'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/av......
  • python 多线程的使用,爬取新发地菜价
    今天使用多线程来获取200页数据公众号回复 菜价 获取源码目标网站:#新发地菜价http://www.xinfadi.com.cn/priceDetail.html打开网站,发现是异步加载,然后点击xhr可以看到,数据就在这里然后我们点击负载,观察发现20代表每页展示多少条数据,不用管current则是代表页数点击标头,可以看......
  • VCSA重装后或者更新证书后,vsan 无法提取请求的数据。有关详细信息,请查看 vSphere Clie
    VCSA重装后或者更新证书后,VSAN磁盘组信息无法显示 重装VCSA接管VSAN环境后,查看VSAN磁盘组报错无法提取请求的数据。首先VCSA开启SSH后台连接到VC环境。vi/tmp/check-trust-anchors  #内容如下#!/bin/bashfunctionsetOptionColorize(){RED=$(tputsetaf1)......
  • python读取和写入txt等文件,文件打开模式,文件对象常用函数
     ......
  • 《最新出炉》系列初窥篇-Python+Playwright自动化测试-23-处理select下拉框-下篇
    1.简介上一篇中宏哥主要讲解和分享了一下,我们常见或者传统的select下拉框的操作,但是近几年又出现了了一种新的select下拉框,其和我们传统的select下拉框完全不一样,那么我们如何使用playwright对其进行定位操作了。宏哥今天就来讲解和分享一下仅供大家参考,不喜勿喷。2.新的select......
  • Python requirements.txt安装用法介绍
    一、什么是requirements.txt文件在Python项目开发中,通常需要安装多个Python包。当我们在新的项目中启动一个虚拟环境,并且想要在新的虚拟环境中安装之前的依赖包时,就可以使用requirements.txt文件来完成。这个文件包含了所有需要安装的依赖包和其版本号。requirements.txt文件可以在......
  • 如何使用Python实现一个完整的排列
    一、前言排列是数学中一个重要的概念,也是计算机程序设计中经常用到的工具之一。Python是一门优秀的编程语言,在实现排列方面也非常方便。本文将从多个方面详细介绍如何使用Python实现一个完整的排列。二、什么是排列排列是将一组元素按照一定的顺序进行排列,每个元素只能出现一次。例......
  • 2023年电影票房王者!学会使用Python轻松抓取猫眼电影网站的票房排行榜数据
    电影票房一直是人们津津乐道的话题,想知道哪些电影在2023年票房大卖吗?本文将为你揭秘2023年猫眼电影网站的票房排行榜,更重要的是,我们将教你如何使用Python一键抓取这些数据,并将它们保存到Excel文件中。跟随本文,让我们一起探索这个有趣的世界吧!底部获取源代码第一部分:了解猫眼电影网......
  • Python 实现抢购脚本--Mac 环境
    说明介绍该脚本使用Selenium库来实现自动登录并在指定的时间购买商品。运行前准备mac的safari浏览器本身已经集成了safaridriver,只要启用并开启即可,步骤如下:终端启用safaridriver:sudosafaridriver--enable尝试运行safraidriver,看是否有权限问题。/usr/bin/safaridr......