You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python结构化PDF课程表解析求助:提取数据为字典列表

结构化PDF课程表解析实现方案

核心问题分析

你之前用PyPDF2、tabula-py、Camelot提取数据混乱,大概率是因为PDF表格存在合并单元格、不规则布局,而默认参数没适配这类场景。下面给出两种针对性的实现方案,优先推荐pdfplumber(对布局细节支持更好)。

方案一:使用pdfplumber解析原生结构化PDF

pdfplumber能精准获取PDF的文本位置、单元格边界,适合处理带合并单元格的课程表。

步骤1:安装依赖

pip install pdfplumber

步骤2:代码实现

import pdfplumber

def parse_timetable(pdf_path):
    timetable_data = []
    # 定义字段顺序,和你的课程表列对应
    fields = ["日期", "时段", "教职工", "教室", "课程类型", "开始时间", "结束时间"]
    
    with pdfplumber.open(pdf_path) as pdf:
        for page in pdf.pages:
            # 提取表格,设置参数识别合并单元格
            table = page.extract_table({
                "vertical_strategy": "lines",
                "horizontal_strategy": "lines",
                "intersection_tolerance": 5
            })
            
            if not table:
                continue
            
            # 处理合并单元格填充(以日期列为例,假设日期是合并单元格,跨多行)
            current_date = ""
            for row in table[1:]:  # 跳过表头行
                # 填充合并的日期
                if row[0].strip():
                    current_date = row[0].strip()
                else:
                    row[0] = current_date
                
                # 转换为字典,处理空值
                item = dict(zip(fields, [cell.strip() if cell else "" for cell in row]))
                
                # 标记空时段:判断核心字段是否为空(比如教职工、课程类型都为空)
                if not item["教职工"] and not item["课程类型"]:
                    item["空时段"] = True
                else:
                    item["空时段"] = False
                
                timetable_data.append(item)
    
    return timetable_data

# 调用示例
if __name__ == "__main__":
    result = parse_timetable("你的课程表.pdf")
    for idx, item in enumerate(result[:5]):  # 打印前5条测试
        print(f"时段{idx+1}: {item}")

关键技巧

  • 合并单元格处理:通过跟踪前一行的非空值,填充当前行的空单元格(比如日期列通常合并,跨多个时段)
  • 空时段判断:根据业务逻辑定义空时段(比如教职工、课程类型同时为空即可判定)
  • 参数调整:如果表格线条不清晰,可调整intersection_tolerance值(越大越容易识别线条交点)

方案二:调整Camelot参数适配

如果坚持用Camelot,针对合并单元格和不规则表格,调整flavor和split_text参数:

import camelot

def parse_with_camelot(pdf_path):
    # 根据PDF类型选flavor:lattice适合带清晰线条的表格,stream适合无线条的表格
    tables = camelot.read_pdf(pdf_path, flavor='lattice', split_text=True, pages='all')
    timetable_data = []
    fields = ["日期", "时段", "教职工", "教室", "课程类型", "开始时间", "结束时间"]
    
    for table in tables:
        df = table.df
        # 处理合并单元格(Camelot会把合并单元格的内容放在第一行,后续行对应位置为空)
        df = df.fillna(method='ffill')  # 向前填充空值
        # 转换为字典列表
        for _, row in df.iterrows():
            item = dict(zip(fields, row.str.strip()))
            item["空时段"] = not item["教职工"] and not item["课程类型"]
            timetable_data.append(item)
    
    return timetable_data

额外注意事项

  • 如果是扫描版PDF(图片转的PDF),上述方案无效,需要结合OCR工具,比如pytesseract+pdf2image,先把PDF转成图片,再识别表格内容
  • 测试时先打印提取的原始表格数据,确认表头和行的对应关系,再调整字段顺序和填充逻辑

内容的提问来源于stack exchange,提问作者Denver

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 07:42:21