Python PDF爬取:所有者姓名及地址相关字段提取错误/缺失问题求助
Python PDF爬取:所有者姓名及地址相关字段提取错误/缺失问题求助
大家好,我在使用Python处理PDF数据爬取时遇到了棘手的问题,想请教社区的朋友们帮忙排查:
问题描述
我用pdfplumber库抓取PDF里的税务数据,控制台没有任何报错,但生成的CSV文件里,Owner's First Name到Zip Code这6个字段要么填充了错误内容,要么完全为空。这些数据本该从PDF左侧、TAX MAP PARCEL NUMBER下方的所有者信息区域提取,其他字段(比如地块ID、地址、面积、估值等)的提取都是正常的。
当前结果示例
我手动补充了部分缺失数据的CSV截图如下,方便大家理解我需要的正确结果样式:
目标PDF文件
我处理的是哥伦比亚县2022年Ancram的暂定税务记录PDF,文件地址:
https://www.columbiacountyny.com/uploads/1/0/6/8/106827239/2022_ancram_tentative_roll.pdf
我当前使用的代码
import re import csv import pdfplumber # Define the file path root_path = "C:\\Users\\jfdal\\OneDrive\\Desktop\\2022" file_name = "austerlitz_2022_fr.pdf" file_path = f"{root_path}\\{file_name}" # Retain your property address pattern property_address_pattern = r"\n([A-Za-z0-9\s]+(?:\d{1,4}\s[A-Za-z0-9\s]+)?)\n" acreage_pattern = r"ACRES\s+(\d{1,3}\.\d{1,2})" value_pattern = r"FULL MARKET VALUE\s+([\d,]+)" tax_pattern = r"COUNTY TAXABLE VALUE\s+([\d,]+)" ag_tax_pattern = r"AG\s+DISTRIC\s+41720\s+([\d,]+)" forest_tax_pattern = r"FOREST\s+LND\s+47460\s+([\d,]+)" solar_tax_pattern = r"RPTL 487\s+([\d,]+)" # List to store extracted data results = [] # Read the entire PDF with pdfplumber.open(file_path) as pdf: content = "".join([page.extract_text() for page in pdf.pages]) # Process all pages # Remove page headers before splitting into property sections content = re.sub(r"TAX MAP PARCEL NUMBER PROPERTY LOCATION & CLASS.*?ACCOUNT NO\..*?\n", "", content, flags=re.S) # Split content by property sections properties = re.split(r"\*{50,}", content) for prop in properties: try: lines = [line.strip() for line in prop.split("\n") if line.strip()] # Initialize placeholders prop_id = "0" owner_first_name, owner_last_name = "0", "0" street_address, owner_town, owner_state, zip_code = "0", "0", "0", "0" # First line for Prop ID and Address if len(lines) > 0: first_line = lines[0] # Extract Prop ID from the first line if structured like "123.-1-45" prop_id_match = re.match(r"(\d{1,3}\.\-?\d{1,3}\-?\d{1,3}\.?\d{0,3})", first_line) prop_id = prop_id_match.group(1) if prop_id_match else "0" # Owner's information parsing logic for line in lines: if len(line.split()) > 3: # Likely contains owner or address information if "CURRENT OWNERS NAME" in line: owner_name_parts = line.replace("CURRENT OWNERS NAME", "").strip().split() owner_first_name = owner_name_parts[0] if len(owner_name_parts) > 0 else "0" owner_last_name = owner_name_parts[-1] if len(owner_name_parts) > 1 else "0" elif "CURRENT OWNERS ADDRESS" in line: address_parts = line.replace("CURRENT OWNERS ADDRESS", "").strip().split(", ") if len(address_parts) == 3: street_address = address_parts[0] owner_town, owner_state, zip_code = address_parts[1], address_parts[2].split()[0], address_parts[2].split()[1] # Extract data using regex patterns property_address_match = re.search(property_address_pattern, prop) acreage_match = re.search(acreage_pattern, prop) full_market_value_match = re.search(value_pattern, prop) tax_value_match = re.search(tax_pattern, prop) ag_tax_match = re.search(ag_tax_pattern, prop) forest_tax_match = re.search(forest_tax_pattern, prop) solar_tax_match = re.search(solar_tax_pattern, prop) # Handle numeric fields with commas def parse_numeric(value_match): return value_match.group(1).replace(",", "") if value_match else "0" # Get acreage and filter properties with less than 100 acres acreage = float(acreage_match.group(1)) if acreage_match else 0 if acreage < 100: continue # Append extracted results results.append({ "Property Town": "Austerlitz", "Prop ID": prop_id, "Property Address": property_address_match.group(1).strip() if property_address_match else "0", "Acreage": f"{acreage:.2f}", "Owner First Name": owner_first_name, "Owner Last Name": owner_last_name, "Street Address": street_address, "Town": owner_town, "State": owner_state, "Zip Code": zip_code, "Full Market Value": parse_numeric(full_market_value_match), "Tax Value": parse_numeric(tax_value_match), "AG Tax": parse_numeric(ag_tax_match), "Forest Tax": parse_numeric(forest_tax_match), "Solar Tax": parse_numeric(solar_tax_match) }) except Exception as e: # Handle parsing errors print(f"Error parsing property: {e}") # Write results to CSV (only properties with 100+ acres) output_file = f"{root_path}\\austerlitz_results.csv" with open(output_file, 'w', newline='') as csvfile: fieldnames = [ "Property Town", "Prop ID", "Property Address", "Acreage", "Owner First Name", "Owner Last Name", "Street Address", "Town", "State", "Zip Code", "Full Market Value", "Tax Value", "AG Tax", "Forest Tax", "Solar Tax" ] writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writeheader() writer.writerows(results) print(f"Data extraction complete. Results saved to {output_file}")
预期结果
我期望代码能生成和我手动填充类似的结果,把CSV中那些填充为0的所有者姓名、街道地址、城镇、州、邮编字段,替换为PDF中对应的正确数据。
备注:内容来源于stack exchange,提问作者user29394340
相关产品推荐
相关产品推荐

