python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python全文内容搜索

基于Python实现一个简单的全文内容搜索工具

作者:小庄-Python办公

本文主要为大家详细介绍了一个使用Python实现的全文内容搜索工具,可快速在数千份文档中查找特定关键字,该工具支持多种文件格式,包括txt、docx、pdf、xlsx等,有需要的小伙伴参考下

场景引入

领导问你:“去年 3 月份关于华为项目的合同在哪里?”

你面对 50 个文件夹、3000 多个文档,用 Windows 自带的搜索只能搜文件名,搜不到文件内容。逐份打开文件 Ctrl+F 查找?太慢了。

本节教你用 Python 实现全文内容搜索,3000 份文档只需几秒钟。

技术原理

核心流程:遍历文件夹 → 识别文件类型 → 读取文本内容 → 正则/字符串匹配关键词 → 输出匹配结果

支持的文件类型

文件类型读取方式依赖库
.txt, .csv, .md, .py直接 open().read()内置
.docxpython-docx需安装
.pdfPyPDF2 / pdfplumber需安装
.xlsxpandas / openpyxl需安装

环境准备

pip install python-docx PyPDF2 openpyxl

完整代码

import os
import re
from pathlib import Path
from datetime import datetime

# ==================== 文本提取器 ====================

def extract_text_txt(file_path):
    """读取纯文本文件"""
    encodings = ['utf-8', 'gbk', 'gb2312', 'latin-1']
    for enc in encodings:
        try:
            with open(file_path, 'r', encoding=enc) as f:
                return f.read()
        except UnicodeDecodeError:
            continue
    return ""


def extract_text_docx(file_path):
    """读取 Word 文档"""
    try:
        from docx import Document
        doc = Document(str(file_path))
        return '\n'.join([p.text for p in doc.paragraphs])
    except Exception:
        return ""


def extract_text_pdf(file_path):
    """读取 PDF 文档"""
    try:
        import PyPDF2
        text = ""
        with open(str(file_path), 'rb') as f:
            reader = PyPDF2.PdfReader(f)
            for page in reader.pages:
                page_text = page.extract_text()
                if page_text:
                    text += page_text + "\n"
        return text
    except Exception:
        return ""


def extract_text_xlsx(file_path):
    """读取 Excel 文件的所有单元格文本"""
    try:
        import pandas as pd
        df = pd.read_excel(file_path, engine='openpyxl')
        return df.to_string()
    except Exception:
        return ""


# 提取器映射
EXTRACTORS = {
    '.txt': extract_text_txt,
    '.csv': extract_text_txt,
    '.md': extract_text_txt,
    '.py': extract_text_txt,
    '.log': extract_text_txt,
    '.ini': extract_text_txt,
    '.json': extract_text_txt,
    '.docx': extract_text_docx,
    '.pdf': extract_text_pdf,
    '.xlsx': extract_text_xlsx,
    '.xls': extract_text_xlsx,
}


# ==================== 核心搜索函数 ====================
def search_files_content(search_dir, keywords, file_types=None, max_results=50, case_sensitive=False):
    """
    在文件夹中搜索包含特定关键字的文件

    参数:
        search_dir: 搜索目录
        keywords: 搜索关键字(字符串或列表)
        file_types: 文件后缀过滤(如 ['.docx', '.pdf']),None 表示全部
        max_results: 最多返回结果数
        case_sensitive: 是否区分大小写
    """
    if isinstance(keywords, str):
        keywords = [keywords]

    search_path = Path(search_dir)
    results = []
    files_searched = 0

    print(f"开始搜索: {search_dir}")
    print(f"关键字: {', '.join(keywords)}")
    print("-" * 50)

    for file_path in search_path.rglob('*'):
        if file_path.is_file():
            suffix = file_path.suffix.lower()

            # 文件类型过滤
            if file_types and suffix not in file_types:
                continue

            # 获取提取器
            extractor = EXTRACTORS.get(suffix)
            if not extractor:
                continue

            files_searched += 1

            try:
                content = extractor(file_path)

                if not content:
                    continue

                # 搜索关键字
                matched_keywords = []
                search_content = content if case_sensitive else content.lower()

                for kw in keywords:
                    search_kw = kw if case_sensitive else kw.lower()
                    if search_kw in search_content:
                        matched_keywords.append(kw)

                if matched_keywords:
                    # 提取关键字周围的上下文
                    context = extract_context(content, keywords, case_sensitive)

                    results.append({
                        'file': str(file_path),
                        'matched': matched_keywords,
                        'context': context,
                        'size': file_path.stat().st_size,
                        'modified': datetime.fromtimestamp(file_path.stat().st_mtime)
                    })

                    print(f"[匹配] {file_path.name}")
                    print(f"  关键字: {', '.join(matched_keywords)}")
                    print(f"  上下文: ...{context}...")
                    print()

                    if len(results) >= max_results:
                        break

            except Exception as e:
                pass  # 跳过无法读取的文件

    # 汇总报告
    print("=" * 50)
    print(f"搜索完成!")
    print(f"扫描文件: {files_searched}")
    print(f"匹配文件: {len(results)}")

    # 导出报告
    if results:
        import pandas as pd
        report = pd.DataFrame(results)
        report_file = "搜索结果报告.xlsx"
        report.to_excel(report_file, index=False, engine='openpyxl')
        print(f"详细报告已导出: {report_file}")

    return results


def extract_context(text, keywords, case_sensitive, context_length=50):
    """提取关键字周围的上下文文本"""
    search_text = text if case_sensitive else text.lower()

    for kw in keywords:
        search_kw = kw if case_sensitive else kw.lower()
        pos = search_text.find(search_kw)
        if pos >= 0:
            start = max(0, pos - context_length)
            end = min(len(text), pos + len(kw) + context_length)
            return text[start:end].replace('\n', ' ')

    return ""


# ==================== 使用示例 ====================
if __name__ == "__main__":
    # ========== 示例 1:搜索单个关键字 ==========
    results = search_files_content(
        search_dir=r"D:\工作文档",
        keywords="华为",
        file_types=['.docx', '.pdf', '.xlsx']
    )

    # ========== 示例 2:搜索多个关键字 ==========
    # results = search_files_content(
    #     search_dir=r"D:\工作文档",
    #     keywords=["合同", "华为", "2024"],
    #     max_results=20
    # )

    # ========== 示例 3:正则表达式搜索 ==========
    # (需要自定义扩展,在提取内容后用 re.search 匹配)

代码逐行解析

1. 多编码兼容

encodings = ['utf-8', 'gbk', 'gb2312', 'latin-1']
for enc in encodings:
    try:
        with open(file_path, 'r', encoding=enc) as f:
            return f.read()
    except UnicodeDecodeError:
        continue

Windows 中文环境下,文本文件可能使用 GBK 编码。依次尝试多种编码,确保能正确读取中文内容。

2. 提取器映射

EXTRACTORS = {
    '.txt': extract_text_txt,
    '.docx': extract_text_docx,
    '.pdf': extract_text_pdf,
    ...
}

通过字典映射,根据文件后缀自动选择对应的文本提取函数,扩展性极强。添加新类型只需增加一行映射。

3. 上下文提取

def extract_context(text, keywords, context_length=50):
    pos = search_text.find(search_kw)
    start = max(0, pos - context_length)
    end = min(len(text), pos + len(kw) + context_length)
    return text[start:end]

在搜索结果中显示关键字前后 50 个字符的上下文,方便快速判断是否为目标文件。

进阶技巧

技巧 1:使用正则表达式搜索

import re

def search_with_regex(search_dir, pattern):
    """使用正则表达式搜索"""
    regex = re.compile(pattern, re.IGNORECASE)
    for file_path in Path(search_dir).rglob('*'):
        if file_path.is_file() and file_path.suffix == '.txt':
            content = file_path.read_text(encoding='utf-8', errors='ignore')
            matches = regex.findall(content)
            if matches:
                print(f"{file_path}: {matches}")

技巧 2:全文索引加速(适合频繁搜索)

如果经常搜索同一批文件,可以先建立索引:

import sqlite3

def build_index(search_dir, db_file="file_index.db"):
    conn = sqlite3.connect(db_file)
    conn.execute('''CREATE TABLE IF NOT EXISTS files
                    (path TEXT, content TEXT, modified REAL)''')

    for file_path in Path(search_dir).rglob('*'):
        if file_path.is_file():
            content = extract_text(file_path)
            conn.execute(
                "INSERT OR REPLACE INTO files VALUES (?, ?, ?)",
                (str(file_path), content, file_path.stat().st_mtime)
            )

    conn.commit()
    conn.close()

然后用 SQL 查询:

results = conn.execute("SELECT path FROM files WHERE content LIKE '%华为%'")

常见问题

Q1:PDF 搜索不到内容?

有些 PDF 是扫描件(图片格式),PyPDF2 无法提取文本。需要使用 OCR:

pip install pdfplumber pytesseract pillow

Q2:搜索速度太慢?

Q3:搜索结果太多怎么看?

导出为 Excel 报告后,可以按文件大小、修改时间排序,或在 Excel 中筛选。

总结

步骤方法说明
识别类型file_path.suffix获取文件扩展名
提取文本多提取器字典按类型选择提取方法
匹配关键字kw in content字符串包含判断
提取上下文extract_context()显示关键字周围文本
导出报告pd.DataFrame().to_excel()Excel 格式结果

本节掌握了全文内容搜索的能力,再也不怕"找不到文件"的问题。

到此这篇关于基于Python实现一个简单的全文内容搜索工具的文章就介绍到这了,更多相关Python全文内容搜索内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文