欢迎光临
我们一直在努力

Python办公12:搜索文件夹内数千个文档中的特定关键字

12:内容检索——搜索文件夹内数千个文档中的特定关键字

第二阶段:文件管理与系统自动化(9-15)

场景引入

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

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

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


技术原理

核心流程:

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

支持的文件类型

文件类型读取方式依赖库
.txt, .csv, .md, .py 直接 open().read() 内置
.docx python-docx 需安装
.pdf PyPDF2 / pdfplumber 需安装
.xlsx pandas / 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:搜索速度太慢?

  • 使用 file_types 参数缩小搜索范围
  • 排除不需要搜索的大文件(如日志文件可能很大)
  • 对于频繁搜索的场景,建立索引(技巧 2)

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

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


总结

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

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

下一节预告:13:空间清理——自动识别并删除电脑中的重复文件与大内存垃圾!

赞(0)
未经允许不得转载:171主机测评 » Python办公12:搜索文件夹内数千个文档中的特定关键字
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址