如何用Python避免Excel旧文件被覆盖?爬虫数据留存问题
问题解决:爬虫数据被覆盖的修复方案
问题原因分析
你的代码出现数据覆盖的核心原因有三个:
- 每次遍历章节时,
Canada_Result都会被重新初始化为空列表,导致前序章节的数据被清空 - 每爬完一页就立即保存Excel文件,后续章节的数据会直接覆盖之前的文件内容
- 数据编辑后的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
相关产品推荐
相关产品推荐

