求助:Pandas DataFrame写入CSV仅保留最后一行的问题
解决CSV写入仅保留最后一行及追加异常的问题
看起来你遇到的问题核心在于每次循环都覆盖了之前的CSV内容,而改用mode='a'后又因为重复写入表头或者不必要的合并操作导致异常。咱们一步步来拆解问题,然后给出修复方案:
问题根源分析
你的代码在循环里做了这些多余且导致问题的操作:
- 每次循环都创建一个仅包含当前行数据的
tempDF和df,然后调用to_csv时默认用mode='w'(覆盖模式),所以之前的内容都会被清除,最后只剩最后一行。 - 循环里的
concat操作完全没必要——你每次只处理单条数据,根本不需要合并DataFrame,这只会增加复杂度。 - 如果直接加
mode='a',每次循环都会写入表头,导致CSV里重复出现表头行,这就是你说的“异常输出”。
修复方案(推荐高效写法)
最好的做法是先收集所有数据到列表,最后一次性写入CSV,这样既减少IO操作,也避免覆盖或重复表头的问题:
import pandas as pd import requests import json from datetime import datetime, timedelta # 文件路径 output_high_csv = r"C:\wab\outputempbeets1.csv" csvdata = "你的输入CSV路径" # 注意:原代码中csvdata变量需要补充定义 # 初始化会话 se_ = requests.Session() # 读取输入CSV,提取需要的列 df = pd.read_csv(csvdata) df = df[['lat', 'lon', 'field id']] # 获取昨日日期 dayVal = datetime.strftime(datetime.now() - timedelta(1), '%Y-%m-%d') # 初始化一个空列表,用来存储所有结果数据 results = [] # 遍历每一行的经纬度和field id for latrow, lonrow, field_id in zip(df['lat'], df['lon'], df['field id']): # 构造API请求URL(原代码中的&是HTML转义,替换为普通&) url = f'https://insight.api.wdtinc.com/daily-high-temperature/{latrow}/{lonrow}?start={dayVal}T00:00:00Z&end={dayVal}T01:00:00Z&unit=fahrenheit' try: # 发送请求并捕获HTTP错误 r = se_.get(url, auth=('USERNAME', 'PASSWORD'), timeout=10) r.raise_for_status() # 解析温度数据 hi_temp = json.loads(r.content)['series'][0]['value'] # 将当前行的数据添加到结果列表 results.append({ 'field id': field_id, 'high temperature': hi_temp }) except Exception as e: print(f"处理field id {field_id}时出错: {e}") # 可选择跳过错误行,或记录错误信息到日志 # 将结果列表转为DataFrame并写入CSV if results: result_df = pd.DataFrame(results, columns=['field id', 'high temperature']) result_df.to_csv(output_high_csv, encoding='utf-8', index=False) print("数据写入完成!") else: print("没有有效数据可写入!")
如果你坚持要追加写入(适合数据量极大的场景)
如果数据量非常大,不想一次性加载到内存,可以用追加模式,但要控制表头只写一次:
import pandas as pd import requests import json from datetime import datetime, timedelta import os output_high_csv = r"C:\wab\outputempbeets1.csv" csvdata = "你的输入CSV路径" se_ = requests.Session() df = pd.read_csv(csvdata) df = df[['lat', 'lon', 'field id']] dayVal = datetime.strftime(datetime.now() - timedelta(1), '%Y-%m-%d') # 检查文件是否存在,决定是否写入表头 write_header = not os.path.exists(output_high_csv) for latrow, lonrow, field_id in zip(df['lat'], df['lon'], df['field id']): url = f'https://insight.api.wdtinc.com/daily-high-temperature/{latrow}/{lonrow}?start={dayVal}T00:00:00Z&end={dayVal}T01:00:00Z&unit=fahrenheit' try: r = se_.get(url, auth=('USERNAME', 'PASSWORD'), timeout=10) r.raise_for_status() hi_temp = json.loads(r.content)['series'][0]['value'] # 创建单条数据的DataFrame temp_df = pd.DataFrame([{ 'field id': field_id, 'high temperature': hi_temp }]) # 追加写入,仅第一次写表头 temp_df.to_csv(output_high_csv, encoding='utf-8', index=False, mode='a', header=write_header) # 写完第一次后,后续不再写表头 write_header = False except Exception as e: print(f"处理field id {field_id}时出错: {e}")
额外优化点
- 原代码里的
dfText = df.astype(basestring)没必要,Pandas可以直接遍历列数据,不需要转成列表再处理。 - 原URL中的
&是HTML转义字符,会导致API参数解析错误,替换为普通&即可。 - 添加了异常处理,避免某一行出错导致整个程序崩溃,同时方便排查问题。
内容的提问来源于stack exchange,提问作者gwest
相关产品推荐
相关产品推荐

