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

如何用Python避免Excel旧文件被覆盖?爬虫数据留存问题

问题解决:爬虫数据被覆盖的修复方案

问题原因分析

你的代码出现数据覆盖的核心原因有三个:

  1. 每次遍历章节时,Canada_Result都会被重新初始化为空列表,导致前序章节的数据被清空
  2. 每爬完一页就立即保存Excel文件,后续章节的数据会直接覆盖之前的文件内容
  3. 数据编辑后的CSV文件也是每次处理单个章节就覆盖,最终只保留最后一章的处理结果

关键修改点

  • 将总数据容器Canada_Result移到章节循环外部,确保所有章节的数据都能累加存储
  • 取消每页的保存操作,等所有章节、所有页面的数据全部爬取完成后,再一次性写入Excel
  • 调整数据编辑逻辑,在所有数据收集完成后统一处理并生成符合数据库标准的CSV文件
  • 替换Selenium中已弃用的find_element_by_id等方法,改用新的find_element(By.ID, ...)格式
  • 修正表格行XPATH的错误写法(移除tr["i"]中的引号,改为tr)
  • 删除章节循环末尾重复的提交按钮点击,避免无效请求

修复后的完整代码

from selenium.webdriver.support.select import Select
from prettytable import PrettyTable
import os, platform
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
import pandas as pd
import time

# 清屏函数
def clear():
    if platform.system() == 'Windows':
        os.system('cls')
    else:
        os.system('clear')

# 初始选择菜单
columns = ["请选择对应国家的编号", ""]
myTable = PrettyTable()
myTable.add_column(columns[0], ["1- 加拿大", "2- 英国","3- 韩国","4- 土耳其","5- 新西兰"])
myTable.add_column(columns[1], ["","","","",""])
print(myTable)

# 加拿大进口数据爬取函数
def Canada_Im():
    Ca_Im_Start_Year  = input("输入起始年份(格式:20XX):")
    Ca_Im_Start_Month = input("输入起始月份(格式:X):")
    Ca_Im_End_Year = input("输入结束年份(格式:20XX):")
    Ca_Im_End_Month= input("输入结束月份(格式:X):")
    
    # 初始化Chrome浏览器
    driver = webdriver.Chrome('C:\\Webdriver\\chromedriver.exe')
    driver.get('https://www150.statcan.gc.ca/n1/pub/71-607-x/71-607-x2021004-eng.htm')
    time.sleep(2)
    
    # 点击进口按钮
    driver.find_element(By.XPATH,'//*[@id="cimt_import"]/p[1]/a').click()
    time.sleep(2)
    
    # 点击数据提取按钮
    driver.find_element(By.XPATH,'//*[@id="topic3s"]').click()
    time.sleep(1)
    
    # 设置时间范围
    # 起始年份
    dropdown = driver.find_element(By.ID, 'fromYear')
    dd = Select(dropdown)
    dd.select_by_value(str(Ca_Im_Start_Year))
    # 起始月份
    dropdown_fM = driver.find_element(By.ID, 'fromMonth')
    dd_fM = Select(dropdown_fM)
    dd_fM.select_by_value(str(Ca_Im_Start_Month))
    # 结束年份
    dropdown_tY = driver.find_element(By.ID, 'toYear')
    dd_tY = Select(dropdown_tY)
    dd_tY.select_by_value(str(Ca_Im_End_Year))
    # 结束月份
    dropdown_tM = driver.find_element(By.ID, 'toMonth')
    dd_tM = Select(dropdown_tM)
    dd_tM.select_by_value(str(Ca_Im_End_Month))

    # 选择特定商品分类
    dropdown_rH = driver.find_element(By.ID, 'report_hs')
    dd_rH = Select(dropdown_rH)
    dd_rH.select_by_value("1") 

    # 需要采集的章节列表
    ch_numbers = ["02","04","10","11","12","15","20","23","38"]
    # 总数据容器,放在章节循环外,避免每次清空
    Canada_Result = []
    
    for ch_number in ch_numbers:
        print(f"正在采集章节 {ch_number} 的数据...")
        # 选择当前章节
        dropdown_rC = driver.find_element(By.ID, 'report_chapters')
        dd_rC = Select(dropdown_rC)
        dd_rC.select_by_value(ch_number) 
    
        # 提交查询
        driver.find_element(By.XPATH,'//*[@id="report"]/div[1]/div[3]/div[5]/p[2]/button').click()
        time.sleep(3)
        
        # 获取总页数
        page_elements = driver.find_elements(By.XPATH, '//a[@class="paginate_button" or @class="paginate_button current" and @title]')
        if page_elements:
            pages_text = page_elements[-1].text.strip("Page\n")
            pages = int(pages_text) if pages_text else 1
        else:
            pages = 1

        for J in range(pages):
            # 获取当前页的所有数据行元素(修复XPATH错误)
            commodities = driver.find_elements(By.XPATH, './/*[@id="report_table"]/tbody/tr/td[2]/a')
            Countries = driver.find_elements(By.XPATH, './/*[@id="report_table"]/tbody/tr/td[4]')
            quantities = driver.find_elements(By.XPATH, './/*[@id="report_table"]/tbody/tr/td[7]')
            weights = driver.find_elements(By.XPATH, './/*[@id="report_table"]/tbody/tr/td[8]/abbr')
            time.sleep(2)
            
            # 遍历当前页的所有条目,添加到总数据容器
            for i in range(len(commodities)):
                temporary_data = {
                    'Commodity': commodities[i].text,
                    'Country': Countries[i].text,
                    'quantity': quantities[i].text, 
                    'weight': weights[i].text 
                }
                Canada_Result.append(temporary_data)
            
            print(f"章节 {ch_number} 第 {J+1}/{pages} 页采集完成")
            
            # 如果不是最后一页,点击下一页
            if J != pages - 1:
                driver.find_element(By.XPATH,'//*[@id="report_results_next"]').click()
                time.sleep(1)
    
    # 所有数据采集完成后,保存到Excel
    print("所有章节数据采集完成,正在保存到Excel...")
    df_data = pd.DataFrame(Canada_Result)
    df_data.to_excel('Canada_scrapping_result.xlsx', index=False)
    print("原始数据已保存到 Canada_scrapping_result.xlsx")
    
    # 统一处理数据,适配数据库标准
    print("正在处理数据格式...")
    df = pd.read_excel('Canada_scrapping_result.xlsx') 
    for i in range(len(df)):
        string = df["Commodity"][i]
        split_str = string.split("—")  # 按"—"分割字符串
        if len(split_str) >= 1:
            number = split_str[0] 
            cleaned_number = number.replace(".", "")[:-5]  # 去掉小数点和末尾5个字符
            df.loc[i, 'Commodity'] = cleaned_number  # 使用loc避免SettingWithCopyWarning
    
    df.to_csv("Remove_characters.csv", index=False)
    print("处理后的数据已保存到 Remove_characters.csv")
    
    # 关闭浏览器
    driver.quit()

# 加拿大功能选择菜单
def canada_function():
    clear()
    columns = ["请选择加拿大的进口或出口功能",""]
    myTable_canada = PrettyTable()
    myTable_canada.add_column(columns[0],["1- 进口", "2- 出口"])
    myTable_canada.add_column(columns[1],["",""])
    print(myTable_canada)
    print("\n")
    canada_Im_Ex=input("请输入选择(1/2):")

    match canada_Im_Ex:
        case "1":
            Canada_Im()
        case "2":
            print("出口功能暂未实现,请输入月份:")

# 选择国家
country_number=input("请输入国家编号:")

match country_number:
    case "1":
        clear()    
        print("你选择了加拿大")
        canada_function()
    case "2":
        print("你选择了英国,功能暂未实现")

额外说明

  • 代码中添加了进度打印,方便查看采集状态
  • 修复了Selenium元素定位的过时方法,避免运行警告
  • 使用df.loc[i, 'Commodity']替代直接赋值,避免SettingWithCopyWarning警告
  • 所有数据采集完成后统一保存,彻底解决覆盖问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 05:10:12