ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Python爬虫与机器学习实战:重庆天气数据采集分析与空气质量预测

Python爬虫与机器学习实战:重庆天气数据采集分析与空气质量预测 简介本资源是一份面向计算机、电子信息工程及数学等专业本科生的机器学习课程实践项目聚焦重庆地区天气数据采集与空气质量分析全流程覆盖爬虫开发、数据清洗、特征分析与基础预测建模等典型机器学习任务。压缩包共6个文件3个Excel数据表用于存储爬取的天气与空气质量原始数据、合并数据及质量指标3个Python脚本分别实现网页爬取、数据读取与简单预测功能总大小仅369KB轻量易部署。已有367人下载学习适合作为课程设计、期末大作业或毕业设计的参考范例。代码采用参数化设计关键配置如URL、时间范围、保存路径等均集中可调每段逻辑配有详细中文注释运行结果已内嵌验证经实测可直接执行配套文档说明清晰梳理了技术路线与注意事项便于理解爬虫原理、数据处理流程与机器学习入门实践。1. 项目缘起从一份作业到一个实用的数据分析项目最近在整理过去的项目资料翻到了一个挺有意思的“作业”——一个关于重庆天气数据爬取与分析的机器学习项目。说它是作业因为它确实源于一次课程实践但我觉得它更像是一个麻雀虽小、五脏俱全的实战案例。很多朋友在入门机器学习和数据分析时总感觉理论和实践之间隔着一道鸿沟要么是找不到合适的数据集要么是拿到数据后不知道从何下手。这个项目恰好提供了一个完整的闭环从零开始获取数据、清洗整理、分析探索到最终建立简单的预测模型。重庆这座城市本身就很有特点山城、雾都、火炉这些标签背后是复杂多变的气候特征。分析它的天气数据不仅能练习技术栈还能得到一些有趣的、有地域特色的结论。当时做这个项目我用Python实现了对历史天气数据的自动化爬取构建了一个本地数据库并在此基础上进行了空气质量分析与简单的天气预测尝试。整个过程踩了不少坑也积累了一些心得今天就把这个项目的完整思路、核心代码和那些“教科书上不会写”的细节分享出来希望能给正在学习数据科学、机器学习或者单纯对用技术解决实际问题感兴趣的朋友一些参考。2. 数据获取设计一个健壮、可持续的天气爬虫任何数据分析项目的第一步都是获取数据。对于天气数据虽然有一些开放的API接口但往往有调用次数限制或者历史数据不完整。因此自己动手写一个爬虫从气象网站抓取数据是一个更灵活、更能锻炼技术能力的选择。这里的关键是你的爬虫不能只是一个“一次性”脚本它需要具备应对网站结构变动、网络异常、反爬机制等问题的能力。2.1 目标网站分析与请求策略当时我选择了一个提供历史天气查询的公共网站作为数据源。第一步不是直接写代码而是仔细分析网站结构。URL规律分析通过手动修改查询参数如城市、日期观察URL的变化。我发现目标数据的URL通常呈现规律例如http://example.com/weather/chongqing-20240101.html这种格式其中包含了城市拼音和日期。这为批量构造请求提供了基础。数据定位使用浏览器的开发者工具F12的“检查”功能查看目标数据如温度、湿度、风力、空气质量指数AQI在网页HTML结构中的位置。重点是找到包裹这些数据的唯一性标签和CSS选择器路径。例如温度数据可能在一个span classtemp标签里。请求头Headers设置这是绕过基础反爬的关键。直接使用requests.get()而不设置任何头信息很容易被服务器识别为爬虫并拒绝。必须模拟真实浏览器的行为。最核心的字段是User-Agent你可以从自己浏览器的开发者工具“网络Network”标签中复制任意一次请求的User-Agent值。此外Referer字段有时也很重要它告诉服务器你是从哪个页面跳转过来的。import requests from fake_useragent import UserAgent headers { User-Agent: UserAgent().random, # 使用库随机生成一个常用浏览器的UA Referer: http://example.com/weather/chongqing.html # 模拟从城市主页跳转而来 }2.2 核心爬取逻辑与异常处理爬虫的核心逻辑是一个循环遍历我们想要抓取的日期范围。但网络世界充满不确定性我们必须为各种异常情况做好准备。import pandas as pd from datetime import datetime, timedelta import time def fetch_weather_data(start_date, end_date, citychongqing): 抓取指定城市在指定日期范围内的天气数据。 base_url http://example.com/weather/{}-{}.html date_range pd.date_range(startstart_date, endend_date) all_data [] for single_date in date_range: date_str single_date.strftime(%Y%m%d) url base_url.format(city, date_str) try: response requests.get(url, headersheaders, timeout10) # 设置超时 response.raise_for_status() # 如果状态码不是200抛出HTTPError异常 response.encoding response.apparent_encoding # 自动识别编码 # 解析HTML提取数据 data parse_weather_html(response.text, date_str) if data: # 确保解析到有效数据 all_data.append(data) print(f成功抓取 {date_str} 数据) else: print(f警告{date_str} 页面结构可能已变化未解析到数据) except requests.exceptions.RequestException as e: print(f请求 {url} 失败: {e}) # 可以在这里加入重试逻辑例如最多重试3次 except Exception as e: print(f处理 {url} 时发生未知错误: {e}) # 礼貌性延迟避免对服务器造成过大压力也是重要的反反爬措施 time.sleep(1 random.random()) # 随机延迟1-2秒 return pd.DataFrame(all_data)这里有几个至关重要的经验点超时设置timeout网络状况不好时一个请求可能一直挂起。设置超时如10秒可以防止程序无限期等待。状态码检查raise_for_status不是所有返回都是成功的。404页面不存在、403禁止访问、503服务不可用等状态码需要被捕获和处理。编码处理网页编码可能是UTF-8也可能是GBK。使用response.apparent_encoding比硬编码更可靠。延迟Sleep这是网络爬虫的“道德”和“生存”准则。过于频繁的请求会被视为攻击。随机延迟如1-3秒能显著降低被封IP的风险。异常捕获的粒度我们分别捕获了网络请求异常和通用异常这样能更精确地定位问题。在真实项目中你甚至需要为JSON解析错误、数据库连接错误等设置单独的异常处理。2.3 数据解析与结构化存储parse_weather_html函数是另一个核心它使用BeautifulSoup或lxml库来解析HTML。from bs4 import BeautifulSoup def parse_weather_html(html_content, date_str): soup BeautifulSoup(html_content, html.parser) data {date: date_str} # 使用try-except包裹每一个数据提取步骤防止因某个标签缺失导致整个解析失败 try: # 示例提取最高温度 temp_high_tag soup.find(span, class_high) data[temp_high] float(temp_high_tag.text.replace(℃, )) if temp_high_tag else None # 提取空气质量指数AQI aqi_tag soup.find(div, class_aqi) if aqi_tag: aqi_text aqi_tag.text # 可能文本是“AQI: 85”需要分割提取数字 data[aqi] int(aqi_text.split(:)[-1].strip()) else: data[aqi] None # 类似地提取湿度、风力、天气状况等... data[humidity] extract_humidity(soup) # 可以封装更细的函数 data[weather] extract_weather_condition(soup) data[wind] extract_wind(soup) except AttributeError as e: print(f解析日期 {date_str} 时遇到标签缺失错误: {e}) return None # 解析失败返回None except ValueError as e: print(f解析日期 {date_str} 时数据格式转换错误: {e}) return None return data数据抓取并解析成DataFrame后应立即持久化存储。我推荐使用SQLite数据库它轻量、无需安装服务器非常适合个人项目。import sqlite3 def save_to_db(df, db_pathweather_data.db): conn sqlite3.connect(db_path) # 如果表不存在则创建IF NOT EXISTS 是关键 df.to_sql(chongqing_weather, conn, if_existsappend, indexFalse) conn.close() print(f数据已保存至数据库 {db_path})注意使用if_existsappend时要特别注意数据重复问题。更好的做法是在创建表时设置date字段为UNIQUE约束或者在插入前检查日期是否已存在。一个更健壮的模式是df.to_sql(..., if_existsappend, indexFalse, methodmulti)并结合异常处理来跳过重复项。3. 数据清洗与探索性分析从原始数据到可用特征爬虫抓取的数据是“脏”的直接用于分析或建模会导致结果不可靠。数据清洗Data Cleaning和探索性数据分析EDA是承上启下的关键步骤。3.1 常见数据问题与清洗策略将数据从数据库读入PandasDataFrame后我们系统性地处理以下问题缺失值处理天气数据可能因为网站当天未更新、解析失败等原因缺失。查看缺失情况df.isnull().sum()策略选择对于数值型特征温度、AQI如果缺失不多可以用前后天的均值或中位数填充df[aqi].fillna(df[aqi].median(), inplaceTrue)。对于类别型特征天气状况可以用众数填充或单独标记为“未知”。如果某一天大量关键特征缺失考虑直接删除该条记录df.dropna(subset[temp_high, aqi], inplaceTrue)。异常值检测与处理传感器错误或解析错误可能导致数据异常如温度50℃、湿度200%。方法使用描述性统计df.describe()查看范围或利用箱线图Boxplot可视化识别。处理根据领域知识设定合理范围如重庆温度在-5℃到45℃之间超出范围的视为异常。可以采用盖帽法用上下限值替换或直接删除。格式统一确保数据类型正确。日期列应转换为datetime类型pd.to_datetime(df[date])这对后续按时间序列分析至关重要。天气状况等文本应去除首尾空格。特征工程初探从原始数据中创造更有意义的特征。日期衍生特征从日期中提取“月份”、“季节”、“是否周末”、“是否节假日”。天气和空气质量具有强烈的季节性。滞后特征对于时间序列预测前几天的数据如aqi_lag1,aqi_lag2可能是今天AQI的重要预测因子。移动统计特征计算过去7天的平均AQIrolling_mean_7d可以平滑日波动反映趋势。# 示例创建日期衍生特征和滞后特征 df[date] pd.to_datetime(df[date]) df[month] df[date].dt.month df[season] df[month] % 12 // 3 1 # 简单划分季节 df[is_weekend] df[date].dt.dayofweek 5 # 创建AQI的滞后特征 df[aqi_lag1] df[aqi].shift(1) # 前一天的AQI df[aqi_lag2] df[aqi].shift(2) # 前两天的AQI3.2 探索性数据分析用可视化发现故事EDA的目标是理解数据分布、发现规律和潜在问题。Matplotlib和Seaborn是主要工具。时间序列趋势图这是最直观的。绘制AQI、温度随时间变化的折线图。你可以立刻看到重庆空气质量在冬季可能由于静稳天气和采暖更差夏季更好的总体趋势以及温度的周期性变化。import matplotlib.pyplot as plt import seaborn as sns plt.figure(figsize(15,5)) plt.plot(df[date], df[aqi], labelAQI, alpha0.7) plt.title(重庆AQI时间序列变化) plt.xlabel(日期) plt.ylabel(AQI) plt.legend() plt.grid(True, linestyle--, alpha0.5) plt.show()相关性热力图计算数值特征温度、湿度、风速、AQI之间的皮尔逊相关系数并用热图展示。这能快速告诉你哪些因素与AQI强相关。例如你可能会发现风速与AQI呈负相关风越大污染物扩散越快AQI越低而湿度可能与AQI有正相关高湿可能利于颗粒物吸湿增长。numeric_cols [temp_high, temp_low, humidity, wind_speed, aqi] corr_matrix df[numeric_cols].corr() sns.heatmap(corr_matrix, annotTrue, cmapcoolwarm, center0) plt.title(特征相关性热力图) plt.show()箱线图分组对比按季节或月份分组绘制AQI的箱线图。这比看平均值更能了解数据的分布中位数、四分位距、异常值。可以清晰对比出哪个季节的空气质量最不稳定哪个季节的AQI中位数最高。天气状况与AQI的关系使用柱状图或小提琴图展示不同天气状况晴、多云、雨、霾下的AQI分布情况。直观验证“雨天空气质量通常较好”的常识。实操心得在EDA阶段不要只追求做出漂亮的图表更重要的是对每一个发现提出假设并尝试解释。例如“为什么春季的某个时段AQI会突然飙升是沙尘天气的影响吗” 这些假设会引导你进行更深层次的数据探查甚至需要引入外部数据如气象灾害记录来验证这才是数据分析的价值所在。4. 空气质量分析基于统计与可视化的深度洞察在完成基础清洗和EDA后我们可以针对“空气质量”这个核心主题进行专项分析。目标是将数据转化为有意义的结论。4.1 空气质量等级评估与统计首先根据国家《环境空气质量标准》GB 3095-2012将AQI数值转化为空气质量等级优、良、轻度污染、中度污染等。def categorize_aqi(aqi_value): if 0 aqi_value 50: return 优 elif 51 aqi_value 100: return 良 elif 101 aqi_value 150: return 轻度污染 elif 151 aqi_value 200: return 中度污染 elif 201 aqi_value 300: return 重度污染 else: return 严重污染 df[aqi_level] df[aqi].apply(categorize_aqi)然后进行统计各级别天数及占比df[aqi_level].value_counts(normalizeTrue)。你可能会发现重庆一年中“良”的天数最多“优”和“轻度污染”次之严重污染天数极少。污染日的时间分布统计每个月中“轻度污染”及以上天数。用柱状图展示可以明确看到污染高发月份。4.2 关键影响因素分析通过统计和可视化量化不同因素对空气质量的影响。风速的影响将风速分段如0-1级为静风1-3级为微风等计算每个风速段下的平均AQI。绘制柱状图可以清晰看到随着风速增大平均AQI下降的趋势。甚至可以计算风速与AQI的相关系数。降水的影响对比有降水天气状况包含“雨”、“雪”和无降水日的平均AQI。通常降水对颗粒物有清除作用有雨日的平均AQI应显著低于无雨日。可以用T检验来验证这种差异是否具有统计学显著性。季节与月份分析计算每个季节的AQI平均值、中位数、最大值。结合重庆的地理和气候特点如冬季易出现逆温层不利于污染物扩散夏季降水多利于清除进行解释。制作一个“月历热图”用颜色深浅表示每月平均AQI视觉效果非常直观。4.3 空气污染过程的识别空气质量变化不是孤立的日变化常常表现为连续几天的污染过程。我们可以编写算法来识别这些过程。# 简单识别连续污染日例如AQI100连续超过3天 df[is_polluted] df[aqi] 100 # 标记连续True的组 df[polluted_group] (df[is_polluted] ! df[is_polluted].shift()).cumsum() # 筛选出每组中污染的天数 polluted_periods df[df[is_polluted]].groupby(polluted_group).agg( start_date(date, min), end_date(date, max), duration(date, count), avg_aqi(aqi, mean) ) # 筛选持续时间长的过程 significant_periods polluted_periods[polluted_periods[duration] 3]分析这些significant_periods结合当时的天气数据是否持续静风、低湿度可以归纳出重庆典型的污染气象条件。这份分析结果比单纯说“冬天空气质量差”要有力得多。5. 机器学习建模尝试预测空气质量数据分析的更高阶应用是利用历史数据预测未来。我们可以尝试建立一个机器学习模型用前几天的天气特征来预测明天的AQI或AQI等级。这是一个经典的回归或分类问题。5.1 问题定义与数据准备目标变量明天的AQI值回归任务或明天的空气质量等级分类任务。特征变量今天及之前若干天的天气特征温度、湿度、风速、风向、天气状况编码、以及它们的历史值如aqi_lag1,aqi_lag2等。数据划分绝对不能随机划分因为时间序列数据具有自相关性。必须按时间顺序划分例如用前80%的数据做训练集后20%做测试集以评估模型在“未来”数据上的表现。# 创建滞后特征和移动平均特征 for i in range(1, 4): df[ftemp_high_lag{i}] df[temp_high].shift(i) df[fwind_speed_lag{i}] df[wind_speed].shift(i) # ... 为其他特征创建滞后 df[aqi_rolling_mean_3] df[aqi].shift(1).rolling(window3).mean() # 过去3天平均AQI # 定义目标预测明天的AQI df[target_aqi] df[aqi].shift(-1) # 删除因创建滞后特征和目标变量而产生的缺失行 df_model df.dropna().copy() # 按时间划分数据集 split_idx int(len(df_model) * 0.8) train df_model.iloc[:split_idx].copy() test df_model.iloc[split_idx:].copy() # 分离特征和目标 feature_cols [temp_high, humidity, wind_speed, temp_high_lag1, aqi_lag1, aqi_rolling_mean_3, month_sin, month_cos] # 示例特征列 X_train, y_train train[feature_cols], train[target_aqi] X_test, y_test test[feature_cols], test[target_aqi]5.2 模型选择、训练与评估对于初学者可以从简单的模型开始如线性回归、决策树再尝试集成模型如随机森林Random Forest或梯度提升树如XGBoost、LightGBM。这些树模型对特征无需复杂预处理且能捕捉非线性关系。from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score # 初始化模型 model RandomForestRegressor(n_estimators100, random_state42, n_jobs-1) # 训练模型 model.fit(X_train, y_train) # 在测试集上预测 y_pred model.predict(X_test) # 评估模型 mae mean_absolute_error(y_test, y_pred) rmse mean_squared_error(y_test, y_pred, squaredFalse) r2 r2_score(y_test, y_pred) print(f测试集评估结果) print(f 平均绝对误差 (MAE): {mae:.2f}) print(f 均方根误差 (RMSE): {rmse:.2f}) print(f 决定系数 (R²): {r2:.4f})如何解读结果MAE/RMSE表示模型预测的AQI与实际AQI的平均偏差。例如MAE8意味着平均来看预测值比真实值高或低8个单位。你可以对比AQI的整体波动范围比如从20到150来判断这个误差是否可接受。R²表示模型能解释目标变量AQI波动的比例。越接近1越好。如果R²只有0.3说明仅用这些天气特征只能解释AQI变化的30%还有大量波动由其他未考虑的因素如区域污染物排放、特殊气象事件决定。5.3 特征重要性分析与模型优化随机森林等模型可以提供特征重要性评分这本身就是一个重要的分析结果。importances model.feature_importances_ feature_importance_df pd.DataFrame({feature: feature_cols, importance: importances}) feature_importance_df feature_importance_df.sort_values(importance, ascendingFalse) plt.figure(figsize(10,6)) sns.barplot(datafeature_importance_df, ximportance, yfeature) plt.title(特征重要性排序随机森林) plt.show()你可能会发现aqi_lag1昨天的AQI是最重要的特征这符合常识空气质量具有连续性。其次是aqi_rolling_mean_3过去3天平均和当天的wind_speed。这个分析可以指导你特征筛选剔除重要性极低的特征简化模型。指导数据收集如果风速很重要那么确保风速数据的准确性就非常关键。业务解释量化了不同因素对空气质量预测的贡献度。模型优化方向超参数调优使用网格搜索GridSearchCV或随机搜索RandomizedSearchCV寻找n_estimators,max_depth,min_samples_split等参数的最佳组合。更复杂的特征工程引入气压、能见度、云量等更多气象要素将风向从类别型转换为正弦-余弦编码因为风向是周期性的考虑节假日效应。尝试时序模型如ARIMA、LSTM神经网络它们专门为时间序列数据设计可能能更好地捕捉长期依赖关系。踩坑实录在第一次建模时我犯了“数据泄露”的错误——不小心在特征中包含了“未来”的信息例如使用了包含当天在内的移动平均。这导致模型在训练集上表现极好但在测试集上惨不忍睹。切记用于预测第t天目标的所有特征其信息必须严格来自第t-1天及以前。在划分训练测试集后任何基于全局的标准化如StandardScaler都必须在训练集上拟合然后仅用训练集的参数去转换测试集否则也会引入微小的时间泄露。6. 项目总结与扩展思考回顾这个从爬虫到机器学习的完整项目它不仅仅是一份作业更是一个典型的数据科学工作流缩影。我们经历了数据采集、清洗、探索、分析、建模的全过程。对于重庆天气数据的分析我们能够得出一些定性的结论比如空气质量与风速、降水、季节的关联性并通过机器学习模型初步量化了这种关系。我个人在操作中的几点深刻体会数据质量决定天花板无论模型多复杂如果原始数据脏、乱、缺失多结果都不可信。爬虫的健壮性和数据清洗的细致程度往往比后续的算法选择更重要。花在理解和清洗数据上的时间通常占整个项目的一半以上。领域知识是导航仪如果不了解重庆“雾都”、“盆地静风”的气候特点很多数据模式如冬季AQI偏高就无法给出合理解释。在特征工程阶段领域知识能帮你创造更有意义的特征如是否处于逆温层。可视化是沟通的桥梁一张清晰的热力图或时间序列图比千言万语更能说明问题。EDA不仅是给自己看的更是为了向他人或未来的自己清晰地展示数据故事。机器学习不是万能钥匙在这个项目中简单的天气特征对AQI的预测能力R²可能有限。这恰恰反映了真实世界的复杂性——空气质量受本地排放、区域传输等多重因素影响。模型结果不理想本身也是一个有价值的结论它告诉我们仅靠本地历史气象数据不足以精准预测空气质量。这个项目还可以从多个方向扩展多城市对比爬取成都、西安等周边城市数据进行横向对比分析地形、经济结构对空气质量的影响。引入外部数据融合环保部门的污染物浓度PM2.5, PM10, NO2数据建立更精细的预测模型。构建实时监控系统将爬虫部署到云服务器定时运行将数据存入数据库并连接一个简单的Web仪表盘用Flask或Streamlit实现空气质量历史和实时数据的可视化展示。深化机器学习应用尝试更复杂的时序预测模型如Prophet、LSTM或将问题转化为分类问题预测明天是“良”还是“轻度污染”评估不同算法的性能。最后这个项目的所有源代码、清洗后的数据集以及更详细的文档说明我都整理在了一个结构清晰的GitHub仓库中。通过亲手复现这个过程你不仅能掌握Python爬虫、Pandas数据分析、Sklearn建模的技术栈更能建立起一套解决实际数据问题的完整思维框架。这才是比完成作业本身更重要的收获。本文还有配套的精品资源点击获取
返回列表