如何用PDF Plumber在Python中完整提取PDF表格圈速数据?
PDF圈速数据提取问题修复方案
问题分析
当前代码存在两个核心问题:
- 仅能提取车手前30圈的数据,后续圈数无法捕获
- 每页仅能识别第一个车手,其余车手数据为空
问题原因
1. 30圈后数据提取失败
原代码使用pattern.match(line)匹配,该方法仅从行首开始匹配。如果30圈之后的圈数行存在缩进、前缀符号(如表格边框残留字符),就会匹配失败。此外,原正则未明确覆盖"P"(进站圈)的前置情况,也可能导致特殊圈数漏捕。
2. 每页仅识别第一个车手
drivers_list中存在重复的Nicholas LATIFI条目,干扰匹配逻辑,导致后续车手无法被正确检测- 原代码用
driver in line的模糊匹配,若后续车手行包含额外文本(如车队名、编号),会导致匹配失败 - 仅当遇到"LAP TIME"字样时才开启圈速收集,若后续车手的圈速区域没有该标识,数据无法被捕获
修改后的代码
import pdfplumber import re # 修复重复车手条目,避免匹配逻辑混乱 drivers_list = ["Max VERSTAPPEN", "Daniel RICCIARDO", "Nicholas LATIFI", "Lewis HAMILTON", "Lando NORRIS", "Sebastian VETTEL", "Pierre GASLY", "Sergio PEREZ", "Fernando ALONSO", "Charles LECLERC", "George RUSSELL", "Alexander ALBON", "Lance STROLL", "Kevin MAGNUSSEN", "Yuki TSUNODA", "ZHOU Guanyu", "Esteban OCON"] # 初始化车手圈速存储字典 driver_lap_times = {driver: [] for driver in drivers_list} # 优化正则:支持圈数前有非数字字符,覆盖更多时间格式,包含进站圈标识"P" pattern = re.compile(r'(\d+|P)\s+(\d{1,2}:\d{2}:\d{2}|\d{1,2}:\d{2}\.\d{3}|\d{1,2}:\d{2})') pdf_path = "Lap Analysis - SIN.pdf" with pdfplumber.open(pdf_path) as pdf: for page in pdf.pages: text = page.extract_text() if not text: continue # 跳过无文本的空白页 lines = text.split('\n') current_driver = None current_lap_times = [] in_lap_time_section = False for line in lines: line = line.strip() if not line: continue # 跳过空行,减少无效处理 # 全词匹配车手名字,避免部分文本误触发 driver_match = None for driver in drivers_list: if re.search(rf'\b{re.escape(driver)}\b', line): driver_match = driver break if driver_match: # 保存上一位车手的圈速数据 if current_driver: driver_lap_times[current_driver].extend(current_lap_times) # 切换到当前车手,重置临时存储 current_driver = driver_match current_lap_times = [] in_lap_time_section = False # 处理车手行与首圈数据同线的情况 match = pattern.search(line) if match: lap_number, lap_time = match.groups() current_lap_times.append({lap_number: lap_time}) continue # 不区分大小写检测圈速区域,适配"LAP TIME"、"LAP TIMES"等变体 if re.search(r'lap\s+time', line, re.IGNORECASE): in_lap_time_section = True continue # 收集圈速:使用search而非match,无需行首匹配 if in_lap_time_section and current_driver: match = pattern.search(line) if match: lap_number, lap_time = match.groups() current_lap_times.append({lap_number: lap_time}) # 保存当前页最后一位车手的数据 if current_driver: driver_lap_times[current_driver].extend(current_lap_times) # 打印有数据的车手结果 for driver, laps in driver_lap_times.items(): if laps: formatted_laps = ', '.join(f"{{'{num}': '{time}'}}" for lap in laps for num, time in lap.items()) print(f"{driver}: [{formatted_laps}]")
关键修改点说明
- 修复重复车手条目:移除
drivers_list中重复的Nicholas LATIFI,避免匹配逻辑混乱 - 正则匹配优化:将
match改为search,确保圈数不在行首时也能被捕获;扩展正则覆盖更多时间格式和进站圈标识 - 车手匹配逻辑升级:使用全词匹配(
\b边界)避免误触发,比如避免其他文本中包含车手名字片段而被误识别 - 圈速区域检测增强:不区分大小写检测圈速区域,适配更多文本变体
- 空行与空白页处理:跳过空行和无文本页面,减少无效处理
- 同线数据兼容:处理车手行与首圈数据在同一行的情况
内容的提问来源于stack exchange,提问作者howlieT
相关产品推荐
相关产品推荐

