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

使用Tabula转换PDF为CSV时特殊字符乱码、列提取异常问题咨询

问题根因

现有代码无法正常输出结果的核心原因有两个:

  • 编码配置错误:代码中指定的cp1252是西欧字符集,不支持土耳其语特殊字符(ğ、ü、ç、İ、ş等),必然出现乱码。
  • 识别逻辑缺陷:Tabula默认开启自动表格检测,会被对账单顶部的姓名/账期文本、底部页脚备注、跨页重复表头干扰,导致列识别偏移;另外代码中CSV输出路径后缀错写为.pdf,本身文件格式就不符合要求。
修正后的Tabula实现方案

针对格式固定的银行对账单,不要依赖自动检测,手动指定编码、表格区域、列坐标即可解决问题,完整代码如下:

import tabula
import pandas as pd
import re

# 基础路径配置
PDF_FILE_PATH = "C:/Users/Desktop/abstract/abstract.pdf"
CSV_SAVE_PATH = "C:/Users/Desktop/abstract/transaction.csv"
# 土耳其语文档使用cp1254编码,兼容所有土语特殊字符
DOC_ENCODING = "cp1254"
# 四个目标列的X轴坐标,可通过Tabula桌面预览工具快速测量后微调
COLUMN_POSITIONS = [122, 278, 447, 532]
# 交易表格在页面中的边界坐标,格式为[上, 左, 下, 右],排除顶部账户信息区、底部页脚区
TABLE_BOUNDARY = [118, 18, 782, 585]

# 第一步:提取全页文本,单独获取姓名、账期信息
full_page_text = tabula.read_pdf(
    PDF_FILE_PATH,
    encoding=DOC_ENCODING,
    pages="all",
    output_format="text",
    silent=True
)
account_name = re.search(r"Müşteri Adı\s*:\s*(.+)", full_page_text).group(1).strip()
statement_period = re.search(r"Dönem\s*:\s*(.+)", full_page_text).group(1).strip()
print(f"账户姓名:{account_name}")
print(f"对账单账期:{statement_period}")

# 第二步:按指定区域提取交易表格
page_tables = tabula.read_pdf(
    PDF_FILE_PATH,
    encoding=DOC_ENCODING,
    pages="all",
    area=TABLE_BOUNDARY,
    columns=COLUMN_POSITIONS,
    lattice=True, # 带实线边框的表格开启该参数,识别准确率更高
    pandas_options={"header": None},
    multiple_tables=True,
    silent=True
)

# 合并跨页表格,过滤重复表头、空行
transaction_list = []
for table_df in page_tables:
    table_df.columns = ["İşlem tarihi", "Açıklama", "Tutar", "Bankomat Para"]
    # 剔除重复的表头行、全空行
    table_df = table_df[table_df["İşlem tarihi"] != "İşlem tarihi"].dropna(how="all")
    transaction_list.append(table_df)
final_transaction_df = pd.concat(transaction_list, ignore_index=True)

# 保存为CSV,使用utf-8-sig编码保证Excel直接打开无乱码
final_transaction_df.to_csv(CSV_SAVE_PATH, index=False, encoding="utf-8-sig")
print(f"交易记录已成功存储至:{CSV_SAVE_PATH}")
更优替代方案

如果Tabula调整参数后仍存在列偏移问题,可换用pdfplumber库,对银行类带边框固定格式表格的识别精度比Tabula更高,字符提取容错性更好,参考实现如下:

import pdfplumber
import pandas as pd
import re

PDF_FILE_PATH = "C:/Users/Desktop/abstract/abstract.pdf"
CSV_SAVE_PATH = "C:/Users/Desktop/abstract/transaction.csv"

account_name = ""
statement_period = ""
transaction_records = []

with pdfplumber.open(PDF_FILE_PATH) as pdf:
    for page_idx, page in enumerate(pdf.pages):
        # 第一页提取顶部账户信息
        if page_idx == 0:
            page_text = page.extract_text()
            account_name = re.search(r"Müşteri Adı\s*:\s*(.+)", page_text).group(1).strip()
            statement_period = re.search(r"Dönem\s*:\s*(.+)", page_text).group(1).strip()
        # 按固定线位提取交易表格
        transaction_table = page.extract_table(table_settings={
            "vertical_strategy": "lines",
            "horizontal_strategy": "lines",
            "explicit_vertical_lines": [122, 278, 447, 532, 590],
            "explicit_horizontal_lines": [118, 782]
        })
        # 逐行清洗数据
        for row in transaction_table:
            if not row[0] or row[0] == "İşlem tarihi":
                continue
            transaction_records.append({
                "交易日期": row[0].strip(),
                "交易说明": row[1].strip(),
                "交易金额": row[2].strip(),
                "赠金(Bankomat Para)": row[3].strip()
            })

# 存储结果
pd.DataFrame(transaction_records).to_csv(CSV_SAVE_PATH, index=False, encoding="utf-8-sig")
注意事项
  • 处理土耳其语等非西欧语言文档时,必须先匹配对应语言的编码,禁止直接默认使用cp1252/gbk等不兼容字符集。
  • 固定格式的文档不要依赖工具的自动识别能力,手动指定表格边界、列坐标可以把识别准确率提升到100%,避免反复调试。
  • CSV存储优先使用utf-8-sig编码,兼容Windows系统下Excel直接打开的场景,不会出现二次乱码。
  • 跨页表格必须手动过滤重复表头、页脚混入的非交易行,不能直接拼接工具输出的原始表格结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 08:15:43