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

使用pdfplumber与Regex提取银行交易数据写入CSV失败求助

问题:提取银行交易写入CSV时仅显示表头,无交易数据

我用以下代码能正确获取银行交易列表:

import re
import pdfplumber
import csv

line_re = re.compile(r"(\d{2}/\d{2}/\d{4}\s+\d{2}/\d{2}/\d{4}.+)$")

transactions = []

with pdfplumber.open('./Bank Acct statement.pdf') as pdf:
    for page in pdf.pages:
        text = page.extract_text()
        lines = text.split('\n')
        for line in lines:
            if re.match(line_re, line):
                transactions.append(line)

得到的交易列表如下:

26/01/2023 26/01/2023 Payment Received Z Kona 8 000.00 8 085.87
26/01/2023 26/01/2023 Banking App Payment: Sihle -2 000.00 6 085.87
26/01/2023 26/01/2023 Payment Fee -1.50 6 084.37
26/01/2023 26/01/2023 SMS Payment Notification Fee -0.25 6 084.12
26/01/2023 26/01/2023 Payment Received Z Kona 15 000.00 21 084.12
26/01/2023 26/01/2023 Payment Received Z Kona 1 500.00 22 584.12
26/01/2023 26/01/2023 Payment Received Z Kona 2 000.00 24 584.12
26/01/2023 26/01/2023 Banking App Transfer to Ms K Savings (1816578655) -18 500.00 6 084.12

但尝试提取交易字段写入CSV时,文件只有表头没有交易数据,修改后的完整代码如下:

import re
import pdfplumber
import csv

line_re = re.compile(r"(\d{2}/\d{2}/\d{4}\s+\d{2}/\d{2}/\d{4}.+)$")

transactions = []

with pdfplumber.open('./Bank Acct statement.pdf') as pdf:
    for page in pdf.pages:
        text = page.extract_text()
        lines = text.split('\n')
        for line in lines:
            if re.match(line_re, line):
                transactions.append(line)

# Define headers for the CSV file
csv_headers = [
    "Posting Date",
    "Transaction Date",
    "Description",
    "Amount",
    "Balance",
]

# Specify the CSV file path
csv_file_path = "transactions.csv"

# Write transactions to the CSV file
with open(csv_file_path, mode="w", newline="") as csv_file:
    csv_writer = csv.writer(csv_file)
    
    # Write the headers as the first row
    csv_writer.writerow(csv_headers)
    
    # Write each transaction as a row in the CSV file
    for transaction in transactions:
        # Split the transaction line into its components
        match = re.search(
            r"(\d{2}/\d{2}/\d{4})\s+(\d{2}/\d{2}/\d{4})\s+([\w\s\(\),]+)\s+(-?\d{1,10}\s\d{1,2}\.\d{2})\s+(-?\d{1,10}\s\d{1,2}\.\d{2})",
            transaction,
        )
        if match:
            csv_writer.writerow([match.group(1), match.group(2), match.group(3), match.group(4), match.group(5)])

print(f"Transactions saved to {csv_file_path}")

我不太懂正则表达式,请问问题出在哪里?


问题原因及解决方案

问题出在你用来拆分交易字段的正则表达式上,它无法匹配所有交易行,导致match始终为None,所以没有数据写入CSV。具体问题点:

  1. 金额格式匹配不全:正则里的-?\d{1,10}\s\d{1,2}\.\d{2}要求金额必须包含空格(比如8 000.00),但像-1.50、-0.25这种没有空格的金额完全匹配不上。
  2. 描述字段的字符范围不足:正则里的[\w\s\(\),]+没包含冒号(:),但交易行里有Banking App Payment: Sihle这种带冒号的描述,导致描述部分匹配失败,进而整个正则匹配失效。

修正后的正则表达式

把拆分字段的正则改成下面这样,就能覆盖所有交易行的格式:

r"(\d{2}/\d{2}/\d{4})\s+(\d{2}/\d{2}/\d{4})\s+([\w\s\(\),:]+)\s+(-?\d{1,10}(?:\s\d{3})*\.\d{2})\s+(-?\d{1,10}(?:\s\d{3})*\.\d{2})"

关键修改点说明

  • 描述部分:在字符集里加上:, 变成[\w\s\(\),:]+,支持带冒号的描述文本。
  • 金额部分:用(?:\s\d{3})*来匹配可选的千位分隔空格(比如8 000里的空格),同时允许没有空格的金额(比如-1.50),这样不管是带千位分隔还是不带的金额都能匹配。

完整修正后的代码

import re
import pdfplumber
import csv

line_re = re.compile(r"(\d{2}/\d{2}/\d{4}\s+\d{2}/\d{2}/\d{4}.+)$")

transactions = []

with pdfplumber.open('./Bank Acct statement.pdf') as pdf:
    for page in pdf.pages:
        text = page.extract_text()
        lines = text.split('\n')
        for line in lines:
            if re.match(line_re, line):
                transactions.append(line)

csv_headers = [
    "Posting Date",
    "Transaction Date",
    "Description",
    "Amount",
    "Balance",
]

csv_file_path = "transactions.csv"

with open(csv_file_path, mode="w", newline="") as csv_file:
    csv_writer = csv.writer(csv_file)
    csv_writer.writerow(csv_headers)
    
    for transaction in transactions:
        match = re.search(
            r"(\d{2}/\d{2}/\d{4})\s+(\d{2}/\d{2}/\d{4})\s+([\w\s\(\),:]+)\s+(-?\d{1,10}(?:\s\d{3})*\.\d{2})\s+(-?\d{1,10}(?:\s\d{3})*\.\d{2})",
            transaction,
        )
        if match:
            # 可选:去掉金额里的千位分隔空格,方便后续处理
            amount = match.group(4).replace(' ', '')
            balance = match.group(5).replace(' ', '')
            csv_writer.writerow([match.group(1), match.group(2), match.group(3).strip(), amount, balance])

print(f"Transactions saved to {csv_file_path}")

另外,还可以在写入CSV前把金额里的空格去掉(比如把8 000.00改成8000.00),这样后续用表格工具打开时会自动识别为数值类型,不用手动处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 04:50:02