Python实用工具:python-magic 零基础入门教程——文件类型检测与分析实战

一、python-magic 库核心概述

1.1 核心用途

python-magic 是一款基于 libmagic 库封装的 Python 工具库,其核心功能是通过文件内容而非扩展名来识别文件的真实类型。在日常开发中,我们经常会遇到文件扩展名被篡改、后缀名丢失的场景,比如下载的压缩包被恶意修改为 .txt 后缀,或者老旧文件的扩展名损坏,此时 python-magic 就能通过解析文件的二进制特征码,准确判断出文件的真实格式,广泛应用于文件校验、爬虫数据处理、系统安全检测等领域。

1.2 工作原理

python-magic 的底层依赖于 Unix/Linux 系统中的 libmagic 库(Windows 系统需手动安装对应依赖),该库内置了一个魔法数字数据库,这个数据库中存储了各种文件格式对应的二进制特征值。当 python-magic 处理文件时,会读取文件头部的若干字节数据,将其与魔法数字数据库中的特征值进行匹配,从而判定文件的真实类型。整个过程无需解析文件完整内容,因此执行效率高,且不受文件扩展名的干扰。

1.3 优缺点分析

优点

  • 识别精度高:基于文件内容的检测方式,能够绕过扩展名伪装,识别出文件的真实格式。
  • 支持格式广泛:涵盖了文档、图片、音频、视频、压缩包等数千种常见文件格式。
  • 跨平台兼容:支持 Windows、macOS、Linux 等主流操作系统(需注意依赖库的安装差异)。
  • 轻量级易用:API 设计简洁,几行代码即可完成文件类型检测,学习成本低。

缺点

  • 依赖外部库:Windows 系统下需要手动安装 libmagic 依赖包,相比纯 Python 库安装步骤稍复杂。
  • 对部分小众格式支持有限:对于一些冷门的自定义文件格式,可能无法匹配到对应的魔法数字,导致识别失败。
  • 无法解析文件内容细节:该库仅能判断文件类型,不能提取文件的具体内容信息,如图片分辨率、文档字数等。

1.4 License 类型

python-magic 采用的是 MIT License,这是一种宽松的开源许可证。用户可以自由地使用、复制、修改、分发该库的源代码,无论是个人项目还是商业项目,都无需支付任何费用,只需在分发的软件中保留原作者的版权声明即可。

二、python-magic 安装步骤

2.1 系统依赖准备

python-magic 依赖系统底层的 libmagic 库,不同操作系统的安装方式有所不同,具体步骤如下:

  1. Linux 系统
    对于 Debian/Ubuntu 系列发行版,执行以下命令安装:
    bash sudo apt-get update sudo apt-get install libmagic1
    对于 CentOS/RHEL 系列发行版,执行以下命令安装:
    bash sudo yum install file-devel
  2. macOS 系统
    使用 Homebrew 包管理器安装,执行命令:
    bash brew install libmagic
  3. Windows 系统 Windows 系统没有默认的包管理器,需要手动下载 libmagic 依赖文件:
    • 访问 GnuWin32 网站,下载 file-5.39-bin.zipfile-5.39-dep.zip 两个压缩包。
    • 解压两个压缩包,将 bin 目录下的 libmagic-1.dllmagic.exe 文件复制到 Python 的安装目录下的 Scripts 文件夹中。
    • share 目录下的 magic 文件夹复制到 Python 安装目录的根目录下。

2.2 Python 库安装

在完成系统依赖安装后,通过 pip 命令即可安装 python-magic 库,执行以下命令:

pip install python-magic

安装完成后,可以在 Python 交互环境中执行以下代码验证是否安装成功:

import magic
print(magic.__version__)

如果没有报错,并且输出了对应的版本号(如 0.4.27),则说明安装成功。

三、python-magic 核心 API 与使用实例

python-magic 提供了两种核心使用方式:一种是直接调用函数式 API,另一种是创建 Magic 类实例进行自定义配置。下面我们分别介绍这两种方式的使用方法,并结合实例代码进行演示。

3.1 函数式 API 快速使用

函数式 API 封装了最常用的文件类型检测功能,适合快速开发场景,核心函数包括 detect_from_filenamedetect_from_contentdetect_from_fobj

3.1.1 detect_from_filename:通过文件名检测文件类型

该函数接收一个文件路径作为参数,返回一个包含文件类型信息的字典,字典中包含 mime_type(MIME 类型)和 encoding(编码格式,仅文本文件有该字段)两个键。

实例代码

import magic

# 定义测试文件路径(替换为你自己的文件路径)
test_file_path = "test.jpg"

# 检测文件类型
result = magic.detect_from_filename(test_file_path)

# 输出检测结果
print(f"文件 MIME 类型: {result.mime_type}")
print(f"文件编码格式: {result.encoding}")

代码说明

  • 首先导入 magic 库,然后定义需要检测的文件路径。
  • 调用 detect_from_filename 函数,传入文件路径,该函数会自动读取文件内容并进行类型检测。
  • 打印返回结果中的 MIME 类型和编码格式。对于图片文件,encoding 字段通常为 None;对于文本文件(如 .txt),会返回具体的编码格式(如 utf-8gbk 等)。

运行结果示例

文件 MIME 类型: image/jpeg
文件编码格式: None

3.1.2 detect_from_content:通过文件内容检测文件类型

在某些场景下,我们可能没有完整的文件,只有文件的二进制内容(如网络请求中获取的文件流),此时可以使用 detect_from_content 函数,直接传入二进制数据进行检测。

实例代码

import magic

# 读取文件的二进制内容
with open("test.txt", "rb") as f:
    file_content = f.read()

# 通过二进制内容检测文件类型
result = magic.detect_from_content(file_content)

# 输出检测结果
print(f"文件 MIME 类型: {result.mime_type}")
print(f"文件编码格式: {result.encoding}")

代码说明

  • 使用 rb 模式打开文本文件,读取其二进制内容并存储到 file_content 变量中。
  • 调用 detect_from_content 函数,传入二进制内容,函数会根据内容特征判断文件类型。
  • 打印检测结果,对于 UTF-8 编码的文本文件,运行结果会显示 mime_typetext/plainencodingutf-8

运行结果示例

文件 MIME 类型: text/plain
文件编码格式: utf-8

3.1.3 detect_from_fobj:通过文件对象检测文件类型

如果已经打开了一个文件对象,不需要再次读取文件内容,直接使用 detect_from_fobj 函数传入文件对象即可完成检测,这种方式适合处理大文件,避免重复读取数据。

实例代码

import magic

# 打开文件对象
with open("test.zip", "rb") as f:
    # 通过文件对象检测文件类型
    result = magic.detect_from_fobj(f)

# 输出检测结果
print(f"文件 MIME 类型: {result.mime_type}")
print(f"文件编码格式: {result.encoding}")

代码说明

  • 使用 rb 模式打开压缩包文件,得到文件对象 f
  • 调用 detect_from_fobj 函数,传入文件对象,函数会从文件头部读取特征字节进行检测。
  • 打印检测结果,压缩包文件的 MIME 类型通常为 application/zip,编码格式为 None

运行结果示例

文件 MIME 类型: application/zip
文件编码格式: None

3.2 Magic 类实例化使用

函数式 API 虽然方便,但可配置性较低。如果需要自定义检测规则(如只检测 MIME 类型、显示详细的文件描述信息等),可以通过实例化 Magic 类来实现。Magic 类的构造函数支持多个参数,常用参数如下:

  • mime:布尔值,设置为 True 时,仅返回 MIME 类型;默认为 False,返回详细的文件描述信息。
  • mime_encoding:布尔值,设置为 True 时,返回 MIME 类型和编码格式;默认为 False
  • keep_going:布尔值,设置为 True 时,会输出所有匹配到的文件类型信息;默认为 False,仅输出第一个匹配结果。
  • uncompress:布尔值,设置为 True 时,会自动解压压缩文件后再进行检测;默认为 False

3.2.1 自定义检测 MIME 类型

通过设置 mime=True,可以让 Magic 实例仅返回文件的 MIME 类型,适合需要标准化文件类型标识的场景。

实例代码

import magic

# 实例化 Magic 类,指定仅返回 MIME 类型
mime_magic = magic.Magic(mime=True)

# 检测图片文件的 MIME 类型
image_type = mime_magic.from_file("test.png")
print(f"PNG 图片 MIME 类型: {image_type}")

# 检测音频文件的 MIME 类型
audio_type = mime_magic.from_file("test.mp3")
print(f"MP3 音频 MIME 类型: {audio_type}")

代码说明

  • 实例化 Magic 类时传入 mime=True 参数,创建一个专门用于检测 MIME 类型的实例 mime_magic
  • 调用实例的 from_file 方法,传入文件路径,分别检测 PNG 图片和 MP3 音频文件的 MIME 类型。
  • 打印检测结果,PNG 图片的 MIME 类型为 image/png,MP3 音频的 MIME 类型为 audio/mpeg

运行结果示例

PNG 图片 MIME 类型: image/png
MP3 音频 MIME 类型: audio/mpeg

3.2.2 获取文件详细描述信息

默认情况下,Magic 实例会返回文件的详细描述信息,包括文件格式、版本等内容,适合需要向用户展示直观文件类型的场景。

实例代码

import magic

# 实例化 Magic 类,获取详细文件描述
detail_magic = magic.Magic()

# 检测不同类型文件的详细信息
txt_detail = detail_magic.from_file("test.txt")
pdf_detail = detail_magic.from_file("test.pdf")
exe_detail = detail_magic.from_file("test.exe")

# 输出详细信息
print(f"文本文件详细信息: {txt_detail}")
print(f"PDF 文件详细信息: {pdf_detail}")
print(f"EXE 程序详细信息: {exe_detail}")

代码说明

  • 实例化 Magic 类时不传入任何参数,创建的 detail_magic 实例会返回详细的文件描述信息。
  • 分别调用 from_file 方法检测文本文件、PDF 文件和 Windows 可执行文件的详细信息。
  • 打印检测结果,文本文件会显示编码格式和文件类型,PDF 文件会显示 PDF document 相关描述,EXE 文件会显示 PE32 executable 相关信息。

运行结果示例

文本文件详细信息: UTF-8 Unicode text
PDF 文件详细信息: PDF document, version 1.5
EXE 程序详细信息: PE32 executable (GUI) Intel 80386, for MS Windows

3.2.3 同时获取 MIME 类型和编码格式

通过设置 mime_encoding=True,可以让 Magic 实例同时返回文件的 MIME 类型和编码格式,这种方式比函数式 API 中的 detect_from_filename 更灵活,支持自定义其他参数。

实例代码

import magic

# 实例化 Magic 类,同时获取 MIME 类型和编码格式
mime_enc_magic = magic.Magic(mime_encoding=True)

# 检测文本文件和 CSV 文件
result1 = mime_enc_magic.from_file("test.txt")
result2 = mime_enc_magic.from_file("test.csv")

# 输出结果
print(f"文本文件 MIME 及编码: {result1}")
print(f"CSV 文件 MIME 及编码: {result2}")

代码说明

  • 实例化 Magic 类时传入 mime_encoding=True 参数,创建的 mime_enc_magic 实例会返回 MIME 类型; 编码格式 的组合字符串。
  • 分别检测文本文件和 CSV 文件,CSV 文件本质上也是文本文件,但其 MIME 类型通常为 text/csv
  • 打印检测结果,UTF-8 编码的文本文件和 CSV 文件会分别显示对应的 MIME 类型和编码格式。

运行结果示例

文本文件 MIME 及编码: text/plain; charset=utf-8
CSV 文件 MIME 及编码: text/csv; charset=utf-8

3.3 处理特殊场景文件

3.3.1 检测伪装扩展名的文件

在实际开发中,经常会遇到文件扩展名被篡改的情况,比如将 .exe 病毒文件伪装成 .jpg 图片文件,此时使用 python-magic 可以轻松识别出文件的真实类型。

实例代码

import magic

# 假设存在一个伪装为图片的可执行文件 fake.jpg(实际是 exe 文件)
fake_file_path = "fake.jpg"

# 使用 Magic 类检测真实类型
real_magic = magic.Magic()
real_type = real_magic.from_file(fake_file_path)

# 使用 MIME 类型检测
mime_magic = magic.Magic(mime=True)
real_mime = mime_magic.from_file(fake_file_path)

# 输出检测结果
print(f"文件伪装扩展名: .jpg")
print(f"文件真实类型描述: {real_type}")
print(f"文件真实 MIME 类型: {real_mime}")

代码说明

  • 准备一个伪装扩展名的文件 fake.jpg,其实际是 Windows 可执行文件。
  • 分别使用返回详细描述的 real_magic 和返回 MIME 类型的 mime_magic 实例检测文件。
  • 打印检测结果,可以看到文件的真实类型是 PE32 可执行文件,MIME 类型为 application/x-dosexec,从而识破文件的伪装。

运行结果示例

文件伪装扩展名: .jpg
文件真实类型描述: PE32 executable (GUI) Intel 80386, for MS Windows
文件真实 MIME 类型: application/x-dosexec

3.3.2 检测压缩包内的文件类型

通过设置 uncompress=TrueMagic 实例可以自动解压压缩文件(如 .gz.bz2 等格式),并检测压缩包内文件的真实类型,适合处理压缩文件的场景。

实例代码

import magic

# 实例化 Magic 类,开启自动解压功能
uncompress_magic = magic.Magic(uncompress=True)

# 检测 gz 压缩包内的文件类型
gz_file_detail = uncompress_magic.from_file("test.txt.gz")
print(f"gz 压缩包内文件类型: {gz_file_detail}")

# 检测 bz2 压缩包内的文件类型
bz2_file_detail = uncompress_magic.from_file("test.csv.bz2")
print(f"bz2 压缩包内文件类型: {bz2_file_detail}")

代码说明

  • 实例化 Magic 类时传入 uncompress=True 参数,开启自动解压功能。
  • 分别检测 .gz.bz2 格式的压缩包文件,uncompress_magic 会先解压压缩包,再检测内部文件的类型。
  • 打印检测结果,.txt.gz 压缩包内的文件会显示为 UTF-8 编码的文本文件,.csv.bz2 压缩包内的文件会显示为 CSV 文本文件。

运行结果示例

gz 压缩包内文件类型: UTF-8 Unicode text (gzip compressed data, was "test.txt", last modified: ...)
bz2 压缩包内文件类型: CSV text (bzip2 compressed data, block size = 900k)

四、python-magic 实际应用案例

4.1 批量检测文件夹内文件类型

在数据处理场景中,我们经常需要对一个文件夹内的所有文件进行类型检测,筛选出特定类型的文件。下面的案例实现了批量检测文件夹内所有文件的类型,并将结果保存到 CSV 文件中。

实例代码

import os
import csv
import magic

def batch_detect_file_type(folder_path, output_csv):
    """
    批量检测文件夹内文件类型,并将结果保存到 CSV 文件
    :param folder_path: 目标文件夹路径
    :param output_csv: 输出 CSV 文件路径
    """
    # 实例化 Magic 类,获取 MIME 类型和编码
    mime_enc_magic = magic.Magic(mime_encoding=True)

    # 准备 CSV 表头
    headers = ["文件名", "文件路径", "MIME类型及编码"]

    # 打开 CSV 文件并写入数据
    with open(output_csv, "w", newline="", encoding="utf-8") as csv_file:
        writer = csv.writer(csv_file)
        writer.writerow(headers)

        # 遍历文件夹内所有文件
        for root, dirs, files in os.walk(folder_path):
            for file_name in files:
                # 获取文件完整路径
                file_path = os.path.join(root, file_name)
                try:
                    # 检测文件类型
                    file_type = mime_enc_magic.from_file(file_path)
                    # 写入 CSV 数据
                    writer.writerow([file_name, file_path, file_type])
                    print(f"已检测: {file_path} -> {file_type}")
                except Exception as e:
                    # 捕获异常,处理无法检测的文件
                    print(f"检测失败: {file_path} -> 错误信息: {str(e)}")
                    writer.writerow([file_name, file_path, f"检测失败: {str(e)}"])

# 调用函数,批量检测 test_folder 文件夹内文件,并保存到 file_types.csv
if __name__ == "__main__":
    target_folder = "test_folder"
    output_file = "file_types.csv"
    batch_detect_file_type(target_folder, output_file)

代码说明

  • 定义 batch_detect_file_type 函数,接收目标文件夹路径和输出 CSV 文件路径作为参数。
  • 实例化 Magic 类并开启 mime_encoding 模式,用于获取文件的 MIME 类型和编码格式。
  • 使用 os.walk 遍历目标文件夹内的所有文件,获取每个文件的完整路径。
  • 调用 from_file 方法检测文件类型,将文件名、文件路径和检测结果写入 CSV 文件。
  • 捕获检测过程中的异常(如文件无法访问、权限不足等),并将错误信息写入 CSV 文件。
  • if __name__ == "__main__" 代码块中,指定目标文件夹和输出 CSV 文件路径,调用函数执行批量检测。

运行效果
运行代码后,会在当前目录下生成 file_types.csv 文件,文件中包含了文件夹内所有文件的名称、路径和类型信息,方便后续数据分析和筛选。

4.2 基于文件类型的爬虫数据过滤

在爬虫开发中,我们经常需要下载网络资源,但有时候会遇到链接返回的文件类型与预期不符的情况(如预期下载图片,实际下载的是 HTML 错误页面)。下面的案例结合 requests 库和 python-magic,实现爬虫数据的类型过滤,只保存符合预期类型的文件。

实例代码

import os
import requests
import magic

def download_file_by_type(url, save_folder, expected_mime):
    """
    根据预期 MIME 类型下载文件,过滤不符合类型的资源
    :param url: 文件下载链接
    :param save_folder: 文件保存文件夹
    :param expected_mime: 预期的 MIME 类型(如 image/jpeg、application/pdf 等)
    """
    # 创建保存文件夹(如果不存在)
    if not os.path.exists(save_folder):
        os.makedirs(save_folder)

    try:
        # 发送 GET 请求,获取文件二进制内容
        response = requests.get(url, stream=True)
        response.raise_for_status()  # 抛出 HTTP 错误异常

        # 读取文件二进制内容(读取前 1024 字节即可满足类型检测需求)
        file_content = response.raw.read(1024)

        # 检测文件 MIME 类型
        mime_magic = magic.Magic(mime=True)
        file_mime = mime_magic.from_buffer(file_content)

        # 判断是否符合预期 MIME 类型
        if file_mime == expected_mime:
            # 提取文件名
            file_name = url.split("/")[-1]
            save_path = os.path.join(save_folder, file_name)

            # 完整下载文件并保存
            with open(save_path, "wb") as f:
                for chunk in response.iter_content(chunk_size=1024):
                    if chunk:
                        f.write(chunk)
            print(f"成功下载符合预期的文件: {save_path} -> MIME 类型: {file_mime}")
        else:
            print(f"文件类型不符,跳过下载 -> 预期: {expected_mime}, 实际: {file_mime}")
    except requests.exceptions.RequestException as e:
        print(f"下载失败: {url} -> 错误信息: {str(e)}")

# 调用函数,下载预期为 JPG 图片的资源
if __name__ == "__main__":
    # 测试链接(替换为实际的下载链接)
    test_urls = [
        "https://example.com/valid_image.jpg",
        "https://example.com/fake_image.html"
    ]
    save_dir = "downloaded_images"
    expected_mime_type = "image/jpeg"

    for url in test_urls:
        download_file_by_type(url, save_dir, expected_mime_type)

代码说明

  • 定义 download_file_by_type 函数,接收下载链接、保存文件夹和预期 MIME 类型作为参数。
  • 首先创建保存文件夹(如果不存在),然后使用 requests.get 方法发送请求,开启流式传输模式(stream=True)。
  • 读取响应的前 1024 字节数据,这部分数据足够 python-magic 进行文件类型检测,避免下载完整文件后才发现类型不符。
  • 实例化 Magic 类并开启 mime 模式,检测读取到的二进制内容的 MIME 类型。
  • 判断检测到的 MIME 类型是否与预期类型一致,如果一致,则提取文件名并完整下载文件到保存文件夹;如果不一致,则跳过下载。
  • 捕获 requests 库的请求异常(如网络错误、HTTP 404 错误等),并输出错误信息。
  • if __name__ == "__main__" 代码块中,定义测试链接列表、保存目录和预期 MIME 类型,遍历链接并调用函数进行下载。

运行效果
运行代码后,只有 MIME 类型为 image/jpeg 的文件会被下载并保存到 downloaded_images 文件夹中,不符合预期类型的资源会被跳过,有效过滤了无效数据。

五、相关资源链接

  • Pypi地址:https://pypi.org/project/python-magic
  • Github地址:https://github.com/ahupp/python-magic
  • 官方文档地址:https://python-magic.readthedocs.io/en/latest/

关注我,每天分享一个实用的Python自动化工具。