1. 项目背景与目标
作为一名长期从事数据分析和爬虫开发的工程师,我经常需要处理各种公开数据源的采集和分析工作。其中,天气数据是一个极具价值的分析对象,它不仅能反映气候变化规律,还能为商业决策、农业生产、出行规划等提供参考依据。
这个项目的主要目标是:
- 使用Python爬虫技术从可靠的气象网站获取全年的历史天气数据
- 对采集到的原始数据进行清洗和结构化处理
- 通过可视化分析揭示数据中的规律和趋势
- 建立一套可复用的天气数据采集分析流程
相比简单的数据抓取,这个项目的难点在于:
- 需要处理反爬机制较为完善的商业气象网站
- 全年数据量较大,需要考虑存储和性能优化
- 天气数据包含多种指标(温度、降水、风速等),需要设计合理的分析维度
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术选型与工具准备
2.1 核心工具链
经过多次项目实践,我总结出一套稳定的技术组合:
python复制# 爬虫相关
import requests # HTTP请求库
from bs4 import BeautifulSoup # HTML解析
import selenium # 动态页面处理
# 数据处理
import pandas as pd # 数据结构化
import numpy as np # 数值计算
# 可视化
import matplotlib.pyplot as plt # 基础绘图
import seaborn as sns # 高级可视化
import plotly.express as px # 交互式图表
2.2 开发环境配置
对于新手来说,环境配置往往是第一个门槛。我推荐使用Anaconda管理Python环境:
- 下载安装Anaconda(建议Python 3.8+版本)
- 创建专用环境:
bash复制conda create -n weather python=3.8
conda activate weather
- 安装必要库:
bash复制pip install requests beautifulsoup4 selenium pandas matplotlib seaborn plotly
提示:如果遇到SSL证书问题,可以尝试更新证书库:
conda install -c anaconda certifi
3. 数据采集实战
3.1 目标网站分析
以中国天气网(www.weather.com.cn)为例,分析其数据接口:
- 查看robots.txt确认爬取限制
- 使用浏览器开发者工具(F12)观察网络请求
- 发现历史天气数据通过AJAX接口获取
- 接口需要城市代码和日期参数
3.2 爬虫实现代码
python复制import requests
import pandas as pd
from datetime import datetime, timedelta
def get_weather_data(city_code, start_date, end_date):
base_url = "http://www.weather.com.cn/weather1d/{}.shtml"
date_range = pd.date_range(start_date, end_date)
all_data = []
for single_date in date_range:
try:
url = base_url.format(city_code)
params = {
'date': single_date.strftime("%Y%m%d")
}
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...'
}
response = requests.get(url, params=params, headers=headers)
soup = BeautifulSoup(response.text, 'html.parser')
# 解析数据
temp_data = parse_weather_data(soup)
temp_data['date'] = single_date
all_data.append(temp_data)
# 礼貌爬取,添加延迟
time.sleep(1)
except Exception as e:
print(f"Error fetching data for {single_date}: {str(e)}")
return pd.DataFrame(all_data)
def parse_weather_data(soup):
# 实际解析逻辑需要根据页面结构调整
return {
'high_temp': soup.find('span', class_='tem').text,
'low_temp': soup.find('span', class_='tem').text,
'weather': soup.find('p', class_='wea').text,
'wind': soup.find('p', class_='win').text
}
3.3 反爬应对策略
商业网站通常有反爬措施,我们需要:
- 使用随机User-Agent
- 设置合理的请求间隔(建议1-3秒)
- 使用代理IP池(对高频率采集必需)
- 处理验证码(可使用第三方打码服务)
- 遵守robots.txt规定
4. 数据清洗与存储
4.1 常见数据问题
原始天气数据通常存在:
- 缺失值(特别是历史久远的数据)
- 异常值(如温度记录错误)
- 格式不一致(不同来源的数据格式不同)
- 单位不统一(摄氏/华氏温度)
4.2 清洗示例代码
python复制def clean_weather_data(df):
# 处理温度字段
df['high_temp'] = df['high_temp'].str.extract('(\d+)').astype(float)
df['low_temp'] = df['low_temp'].str.extract('(\d+)').astype(float)
# 处理天气状况分类
weather_map = {
'晴': 'sunny',
'多云': 'cloudy',
# 其他映射关系...
}
df['weather'] = df['weather'].map(weather_map)
# 处理缺失值
df = df.interpolate() # 线性插值
return df
4.3 数据存储方案
根据数据量选择存储方式:
- 小规模数据(<1GB):CSV或SQLite
python复制df.to_csv('weather_data.csv', index=False)
- 中等规模数据(1-10GB):MySQL/PostgreSQL
- 大规模数据(>10GB):MongoDB或专业时序数据库
5. 可视化分析实战
5.1 温度趋势分析
python复制plt.figure(figsize=(12, 6))
sns.lineplot(data=df, x='date', y='high_temp', label='High Temp')
sns.lineplot(data=df, x='date', y='low_temp', label='Low Temp')
plt.title('Temperature Trend Analysis')
plt.xlabel('Date')
plt.ylabel('Temperature (°C)')
plt.legend()
plt.show()
5.2 天气状况分布
python复制weather_counts = df['weather'].value_counts()
px.pie(weather_counts,
names=weather_counts.index,
title='Weather Condition Distribution')
5.3 高级可视化技巧
- 使用热力图展示温度矩阵:
python复制pivot_table = df.pivot_table(values='high_temp',
index=df['date'].dt.month,
columns=df['date'].dt.day)
sns.heatmap(pivot_table, cmap='coolwarm')
- 交互式时间序列分析:
python复制import plotly.express as px
fig = px.line(df, x='date', y=['high_temp', 'low_temp'],
title='Temperature Trend with Range Slider')
fig.update_xaxes(rangeslider_visible=True)
fig.show()
6. 项目优化与扩展
6.1 性能优化建议
- 使用异步请求提高采集效率:
python复制import aiohttp
import asyncio
async def fetch(session, url):
async with session.get(url) as response:
return await response.text()
async def main():
async with aiohttp.ClientSession() as session:
tasks = [fetch(session, url) for url in urls]
return await asyncio.gather(*tasks)
- 实现断点续爬功能:
python复制import os
import pickle
def save_progress(city, date):
with open(f'progress_{city}.pkl', 'wb') as f:
pickle.dump(date, f)
def load_progress(city):
if os.path.exists(f'progress_{city}.pkl'):
with open(f'progress_{city}.pkl', 'rb') as f:
return pickle.load(f)
return None
6.2 分析维度扩展
- 极端天气事件分析
- 季节变化模式识别
- 城市间气候对比
- 天气与空气质量关联分析
7. 经验总结与避坑指南
在实际项目中,我总结了以下关键经验:
-
数据源选择:
- 优先选择提供API的官方数据源
- 商业网站数据更准确但反爬严格
- 注意数据版权问题
-
爬虫开发:
- 一定要设置合理的请求间隔
- 处理各种HTTP状态码(403/429等)
- 实现完善的错误处理和日志记录
-
数据分析:
- 注意处理时区问题(特别是全球数据)
- 温度数据要考虑单位转换
- 可视化前务必检查数据质量
-
法律合规:
- 严格遵守网站的robots.txt规定
- 不要对网站造成过大访问压力
- 商业用途需获得数据授权
这个项目最让我意外的是,在分析北京2019年的天气数据时,发现3月15日的温度记录明显异常(最高气温比前后日期高出10°C)。经过多方验证,确认是数据录入错误而非真实天气现象。这提醒我们,数据分析前必须进行严格的质量检查。
