You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

网页爬取气象数据转CSV:列对齐与日期优化问题

解决Wunderground气象数据爬取的CSV错位与日期优化问题

我来帮你搞定爬取Wunderground机场气象数据时遇到的CSV数据错位、日期显示不清晰的问题,咱们一步步优化代码:

核心问题分析

你遇到的两个主要问题:

  1. CSV数据错位:页面表格中部分行的列数和表头不一致,直接写入CSV时会导致列对应混乱
  2. 日期归属模糊:爬取的每行数据没有明确绑定日期,无法直观知道数据属于哪天

优化方案与代码实现

1. 先导入所需库

import urllib3
from bs4 import BeautifulSoup
import csv
from datetime import datetime

2. 封装单页爬取函数

把单天数据的爬取逻辑封装成函数,减少重复代码,同时统一处理列数和日期:

def scrape_daily_weather(airport_code, year, month, day):
    # 构造带日期的请求URL
    url = f"https://www.wunderground.com/history/airport/{airport_code}/{year}/{month}/{day}/DailyHistory.html?req_city=&req_state=&req_statename=&reqdb.zip=&reqdb.magic=&reqdb.wmo="
    http = urllib3.PoolManager()
    response = http.request("GET", url)
    soup = BeautifulSoup(response.data, "lxml")
    
    # 定位气象表格区域
    table_div = soup.find('div', {"class":"high-res"})
    if not table_div:
        print(f"⚠️ 未找到{year}-{month}-{day}的有效数据")
        return [], []
    
    # 获取表头,确定标准列数
    header_row = table_div.find('tr')
    if not header_row:
        return [], []
    headers = [th.strip() for th in header_row.stripped_strings]
    standard_col_count = len(headers)
    
    # 处理每一行数据
    daily_data = []
    # 跳过表头行,遍历数据行
    for tr in table_div.findAll('tr')[1:]:
        row_data = [td.strip() for td in tr.stripped_strings]
        # 统一列数:不足补空字符串,多余则截断到标准列数
        if len(row_data) < standard_col_count:
            row_data += [''] * (standard_col_count - len(row_data))
        elif len(row_data) > standard_col_count:
            row_data = row_data[:standard_col_count]
        # 添加标准化日期到行首(格式:YYYY-MM-DD)
        row_date = datetime(year, month, day).strftime("%Y-%m-%d")
        row_data.insert(0, row_date)
        daily_data.append(row_data)
    
    return headers, daily_data

3. 主逻辑:遍历机场和日期,整合数据并写入CSV

# 替换成你的机场代码列表,比如 ['KJFK', 'LAX', 'ORD']
airports = ['KJFK']
all_weather_data = []
final_headers = None

for airport in airports:
    # 处理1月(31天)
    for day in range(1, 32):
        headers, daily_data = scrape_daily_weather(airport, 2018, 1, day)
        # 只在首次获取到表头时,添加日期表头并写入
        if headers and final_headers is None:
            final_headers = ['日期'] + headers
            all_weather_data.append(final_headers)
        all_weather_data.extend(daily_data)
    
    # 处理2月(2018是平年,共28天)
    for day in range(1, 29):
        headers, daily_data = scrape_daily_weather(airport, 2018, 2, day)
        all_weather_data.extend(daily_data)

# 写入CSV文件,指定编码和换行符避免乱码/空行问题
with open('weather.csv', 'w', newline='', encoding='utf-8') as file:
    writer = csv.writer(file)
    writer.writerows(all_weather_data)

关键优化点说明

  • 统一列数:通过表头获取固定列数,对每一行数据做补空或截断操作,确保所有行的列数和表头完全匹配,彻底解决CSV错位问题
  • 明确日期标识:把日期(标准化为YYYY-MM-DD格式)添加到每行数据的开头,让每一条气象数据都能清晰对应到具体日期
  • 代码复用:将单页爬取逻辑封装成函数,避免重复写相同的请求、解析代码,后续维护更方便
  • 文件写入优化:使用w模式覆盖写入(而非a追加),确保每次生成干净的文件;指定newline=''避免CSV出现多余空行,encoding='utf-8'保证特殊字符正常显示

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

火山引擎 最新活动