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

向Excel模板追加数据失败求助:代码报错与文件生成异常

问题排查与解决方案

问题概述

需求:读取含Parcel ID的CSV文件,爬取对应房产信息后插入现有Excel模板,最终保存至指定文件夹。
当前问题:

  • 无法将数据写入原有Excel模板,反而生成临时文件
  • 报错:An error occurred while appending the search results to the Excel worksheet.

核心错误分析

  1. 宽泛的异常捕获:所有except块未指定具体异常类型,也未打印错误详情,无法定位问题根源。
  2. Driver资源管理漏洞:perform_search中driver在try块内初始化,但finally块直接调用driver.quit(),若初始化失败(如Chrome驱动缺失),会触发NameError。
  3. 地址解析逻辑脆弱:硬编码按逗号/空格拆分地址,实际爬取的地址格式可能不符合预期,引发IndexError。
  4. 文件占用冲突:若模板Excel文件处于打开状态,openpyxl无法覆盖原文件,会生成类似~$EJW Template.xlsx的临时文件,被误认为是新文件。
  5. 行号匹配风险:append_search_results中固定使用row_number+6等行号,若CSV行数过多或模板行结构不匹配,会导致写入位置错误。

修复后的完整代码

import os
import csv
import openpyxl
from openpyxl import load_workbook
from openpyxl.styles import Alignment
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.common.exceptions import NoSuchElementException, WebDriverException
from bs4 import BeautifulSoup
import time
import pandas as pd

def run_search(input_csv, output_excel, output_folder):
    # 加载输入CSV
    df = pd.read_csv(input_csv)
    
    # 检查模板文件是否存在
    if not os.path.exists(output_excel):
        print(f"错误:模板文件 {output_excel} 不存在")
        return
    
    # 检查输出文件夹是否存在,不存在则创建
    if not os.path.exists(output_folder):
        os.makedirs(output_folder)
    
    try:
        # 加载Excel模板,保留公式和格式
        workbook = load_workbook(output_excel, data_only=False)
        worksheet = workbook['Justification Worksheet']
    except Exception as e:
        print(f"加载Excel模板失败:{str(e)}")
        return
    
    # 遍历CSV每行
    for index, row in df.iterrows():
        parcel_number = row['Tax_ID']
        print(f"正在处理Parcel ID: {parcel_number}")
        search_results = perform_search(parcel_number)
        if search_results:
            # 写入Excel模板
            if append_search_results(search_results, worksheet, index):
                print(f"Parcel ID {parcel_number} 写入成功")
            # 保存单条结果到CSV
            save_search_results(search_results, output_folder)
    
    # 保存修改后的模板
    try:
        workbook.save(output_excel)
        print(f"所有结果已保存到模板:{output_excel}")
    except PermissionError:
        print("错误:模板文件被占用,请关闭Excel后重试")
    except Exception as e:
        print(f"保存Excel失败:{str(e)}")

def perform_search(parcel_number):
    """爬取指定Parcel ID的房产信息"""
    driver = None
    try:
        driver = webdriver.Chrome()
        driver.get("https://esearch.mobilecopropertytax.com/")
        time.sleep(3) # 缩短等待时间,可根据网络调整
        
        # 输入Parcel ID并搜索
        search_bar = driver.find_element(By.XPATH, '//*[@id="keywords"]')
        search_bar.send_keys(parcel_number)
        search_button = driver.find_element(By.XPATH, '/html/body/div[2]/div[1]/div/div[2]/div/div/span/button')
        search_button.click()
        time.sleep(3)
        
        # 点击搜索结果行
        result_row = driver.find_element(By.XPATH, '/html/body/div[3]/div[3]/div[1]/div[2]/table/tbody/tr')
        result_row.click()
        time.sleep(3)
        
        # 解析页面内容
        soup = BeautifulSoup(driver.page_source, 'lxml')
        
        # 提取字段
        parcel_num = soup.find('th', text='Parcel Number:').find_next_sibling().text.strip()
        name = soup.find('th', text='Name:').find_next_sibling().text.strip()
        
        # 处理地址字段,增加容错
        address_elem = soup.find(lambda tag: tag.name=='th' and 'Address:' in tag.text)
        if not address_elem:
            raise ValueError("未找到地址字段")
        address = address_elem.find_next_sibling().text.strip()
        
        # 健壮性拆分地址
        city = state = zip_code = ""
        if ',' in address:
            parts = address.split(',', 1) # 只拆分第一个逗号
            city_part = parts[0].strip()
            city = city_part.split(' ')[-1] if ' ' in city_part else city_part
            state_zip_part = parts[1].strip()
            if ' ' in state_zip_part:
                state, zip_code = state_zip_part.rsplit(' ', 1) # 从右拆分第一个空格
        
        return [parcel_num, name, address, city, state, zip_code]
    
    except NoSuchElementException as e:
        print(f"爬取失败:页面元素未找到 - {str(e)}")
        return None
    except WebDriverException as e:
        print(f"浏览器驱动错误:{str(e)}")
        return None
    except Exception as e:
        print(f"爬取过程出错:{str(e)}")
        return None
    finally:
        if driver:
            driver.quit()

def append_search_results(search_results, worksheet, row_number):
    """将结果写入Excel指定位置,返回是否成功"""
    try:
        # 计算目标行号(根据模板结构调整)
        base_row = row_number + 6
        # 写入对应单元格
        worksheet[f'C{base_row}'].value = search_results[0] # Parcel Number
        worksheet[f'C{base_row+3}'].value = search_results[1] # Name
        worksheet[f'C{base_row+4}'].value = search_results[2] # Address
        worksheet[f'C{base_row+5}'].value = search_results[3] # City
        worksheet[f'E{base_row+5}'].value = search_results[4] # State
        worksheet[f'G{base_row+5}'].value = search_results[5] # Zip code
        
        # 设置单元格对齐
        align = Alignment(horizontal='left', vertical='center', shrink_to_fit=False)
        for cell in [f'C{base_row}', f'C{base_row+3}', f'C{base_row+4}', f'C{base_row+5}', f'E{base_row+5}', f'G{base_row+5}']:
            worksheet[cell].alignment = align
        
        return True
    except Exception as e:
        print(f"写入Excel出错:{str(e)}")
        return False

def save_search_results(search_results, output_folder):
    """保存单条结果到独立CSV"""
    filename = os.path.join(output_folder, f"{search_results[0]}.csv")
    with open(filename, 'w', newline='', encoding='utf-8') as file:
        writer = csv.writer(file)
        writer.writerow(['Parcel Number', 'Name', 'Address', 'City', 'State', 'Zip Code'])
        writer.writerow(search_results)

# 配置文件路径
input_csv = r'C:\Users\user\Desktop\parcel_numbers.csv'
output_excel = r'C:\Users\user\Desktop\EJW Template.xlsx'
output_folder = r'C:\Users\user\Desktop\EJW Jeffereson Co Text'

# 执行程序
run_search(input_csv, output_excel, output_folder)

关键修复说明

  • 精准异常捕获:替换宽泛except为具体异常类型(如PermissionError、NoSuchElementException),并打印错误详情,便于定位问题。
  • Driver安全管理:初始化driver为None,finally块先判断driver是否存在再调用quit(),避免未初始化时报错。
  • 健壮的地址解析:使用split(',',1)和rsplit(' ',1)拆分地址,避免多逗号/多空格导致的索引错误,增加字段检查。
  • 文件占用处理:捕获PermissionError,明确提示用户关闭Excel文件。
  • 日志输出:增加处理过程的打印信息,便于跟踪进度。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 19:48:17