使用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。具体问题点:
- 金额格式匹配不全:正则里的
-?\d{1,10}\s\d{1,2}\.\d{2}要求金额必须包含空格(比如8 000.00),但像-1.50、-0.25这种没有空格的金额完全匹配不上。 - 描述字段的字符范围不足:正则里的
[\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
相关产品推荐
相关产品推荐

