资讯动态

Python爬虫实战:抓取天气后报空气质量数据

发布时间:2026/9/14 22:43:33 来源:尧图企业网站定制
1. 项目背景与核心需求最近在做一个空气质量分析的小项目需要获取北京地区的历史空气质量数据。经过一番调研发现天气后报网站www.tianqihoubao.com提供了比较完整的历史AQI数据记录。这个网站的数据结构清晰非常适合用Python爬虫来抓取。空气质量数据对于城市环境研究、健康分析等领域都有重要价值。特别是PM2.5、AQI等指标能直观反映一个地区的空气污染程度。通过爬取这些数据我们可以进行时间序列分析、城市间对比、污染源追踪等多种研究。2. 目标网站分析2.1 网站结构解析天气后报网站的空气质量数据页面URL格式非常规范基本遵循以下模式http://www.tianqihoubao.com/aqi/城市拼音-年月.html例如北京2022年9月的数据页面就是http://www.tianqihoubao.com/aqi/beijing-202209.html2.2 数据表格定位通过浏览器开发者工具查看页面元素可以发现目标数据存储在一个标准的HTML表格中table tbody tr.../tr !-- 表头行 -- tr.../tr !-- 数据行1 -- tr.../tr !-- 数据行2 -- ... /tbody /table每行数据包含日期、AQI指数、PM2.5浓度、空气质量等级等关键指标。3. 爬虫实现方案3.1 技术选型考虑到网站没有复杂的反爬机制我们选择以下技术栈Requests轻量级HTTP请求库BeautifulSoupHTML解析工具Pandas数据处理和存储Matplotlib数据可视化3.2 核心爬取代码import requests from bs4 import BeautifulSoup import pandas as pd def get_aqi_data(city, year_month): url fhttp://www.tianqihoubao.com/aqi/{city}-{year_month}.html headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 } response requests.get(url, headersheaders) soup BeautifulSoup(response.text, html.parser) table soup.find(table) rows table.find_all(tr) data [] for row in rows[1:]: # 跳过表头 cols row.find_all(td) cols [col.text.strip() for col in cols] data.append(cols) return data3.3 多个月份数据抓取为了获取完整年份的数据我们需要循环抓取每个月的数据def get_year_data(city, year): all_data [] for month in range(1, 13): month_str f{month:02d} # 补零 year_month f{year}{month_str} print(f正在抓取 {city} {year_month} 数据...) monthly_data get_aqi_data(city, year_month) all_data.extend(monthly_data) time.sleep(2) # 礼貌性延迟 columns [日期, AQI, 质量等级, PM2.5, PM10, SO2, NO2, CO, O3] df pd.DataFrame(all_data, columnscolumns) return df4. 数据处理与存储4.1 数据清洗原始数据抓取后需要进行以下处理去除重复数据转换数据类型字符串转数值处理缺失值def clean_data(df): # 去除重复 df df.drop_duplicates() # 转换数据类型 numeric_cols [AQI, PM2.5, PM10, SO2, NO2, CO, O3] for col in numeric_cols: df[col] pd.to_numeric(df[col], errorscoerce) # 处理缺失值 df df.dropna() return df4.2 数据存储清洗后的数据可以保存为CSV或Excel文件df.to_csv(beijing_aqi_2021.csv, indexFalse) # 或 df.to_excel(beijing_aqi_2021.xlsx, indexFalse)5. 数据可视化分析5.1 AQI时间序列图import matplotlib.pyplot as plt import matplotlib.dates as mdates plt.figure(figsize(15, 6)) df[日期] pd.to_datetime(df[日期]) plt.plot(df[日期], df[AQI], labelAQI) plt.title(北京2021年AQI变化趋势) plt.xlabel(日期) plt.ylabel(AQI指数) plt.gca().xaxis.set_major_formatter(mdates.DateFormatter(%m-%d)) plt.gcf().autofmt_xdate() plt.grid() plt.show()5.2 空气质量等级分布quality_counts df[质量等级].value_counts() plt.figure(figsize(8, 8)) plt.pie(quality_counts, labelsquality_counts.index, autopct%1.1f%%) plt.title(北京2021年空气质量等级分布) plt.show()6. 反爬策略应对虽然天气后报网站没有严格的反爬机制但为了长期稳定运行建议设置请求间隔每次请求间加入2-5秒随机延迟使用代理IP防止单一IP被封模拟浏览器头使用常见的User-Agent异常处理捕获请求异常并重试import random import time def safe_request(url, max_retry3): headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 } for i in range(max_retry): try: time.sleep(random.uniform(1, 3)) response requests.get(url, headersheaders, timeout10) if response.status_code 200: return response except Exception as e: print(f请求失败重试 {i1}/{max_retry}: {e}) return None7. 项目扩展思路多城市对比同时爬取多个城市数据进行横向比较长期趋势分析抓取多年数据分析空气质量变化趋势气象数据关联结合温度、湿度等气象数据分析影响因素实时监控系统定期自动抓取最新数据构建监控看板8. 常见问题与解决方案8.1 数据抓取不全现象某些日期的数据缺失解决检查是否有反爬限制确认目标月份数据确实存在尝试更换IP或增加延迟8.2 中文乱码问题现象抓取的中文显示为乱码解决response.encoding utf-8 # 或 gbk8.3 数据格式不一致现象不同月份的数据列顺序不一致解决# 统一列顺序 expected_columns [日期, AQI, 质量等级, PM2.5, PM10, SO2, NO2, CO, O3] df df[expected_columns]9. 完整代码示例import requests from bs4 import BeautifulSoup import pandas as pd import time import random import matplotlib.pyplot as plt import matplotlib.dates as mdates class AQISpider: def __init__(self): self.headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 } def get_aqi_data(self, city, year_month): url fhttp://www.tianqihoubao.com/aqi/{city}-{year_month}.html response self.safe_request(url) if not response: return None soup BeautifulSoup(response.text, html.parser) table soup.find(table) if not table: return None rows table.find_all(tr) data [] for row in rows[1:]: cols row.find_all(td) cols [col.text.strip() for col in cols] data.append(cols) return data def get_year_data(self, city, year): all_data [] for month in range(1, 13): month_str f{month:02d} year_month f{year}{month_str} print(f正在抓取 {city} {year_month} 数据...) monthly_data self.get_aqi_data(city, year_month) if monthly_data: all_data.extend(monthly_data) time.sleep(random.uniform(1, 3)) columns [日期, AQI, 质量等级, PM2.5, PM10, SO2, NO2, CO, O3] df pd.DataFrame(all_data, columnscolumns) return df def safe_request(self, url, max_retry3): for i in range(max_retry): try: time.sleep(random.uniform(1, 3)) response requests.get(url, headersself.headers, timeout10) if response.status_code 200: return response except Exception as e: print(f请求失败重试 {i1}/{max_retry}: {e}) return None def clean_data(self, df): df df.drop_duplicates() numeric_cols [AQI, PM2.5, PM10, SO2, NO2, CO, O3] for col in numeric_cols: df[col] pd.to_numeric(df[col], errorscoerce) df df.dropna() return df def visualize_aqi_trend(self, df): plt.figure(figsize(15, 6)) df[日期] pd.to_datetime(df[日期]) plt.plot(df[日期], df[AQI], labelAQI) plt.title(北京2021年AQI变化趋势) plt.xlabel(日期) plt.ylabel(AQI指数) plt.gca().xaxis.set_major_formatter(mdates.DateFormatter(%m-%d)) plt.gcf().autofmt_xdate() plt.grid() plt.show() def visualize_quality_distribution(self, df): quality_counts df[质量等级].value_counts() plt.figure(figsize(8, 8)) plt.pie(quality_counts, labelsquality_counts.index, autopct%1.1f%%) plt.title(北京2021年空气质量等级分布) plt.show() # 使用示例 if __name__ __main__: spider AQISpider() df spider.get_year_data(beijing, 2021) df spider.clean_data(df) df.to_csv(beijing_aqi_2021.csv, indexFalse) spider.visualize_aqi_trend(df) spider.visualize_quality_distribution(df)10. 注意事项与经验分享请求频率控制即使网站没有严格限制也应保持合理请求间隔建议2-5秒/次数据验证抓取后立即检查数据完整性特别是月末几天数据容易缺失异常处理网络请求要添加重试机制避免因临时问题导致中断数据备份定期保存中间结果防止程序崩溃导致数据丢失长期运行建议使用日志记录运行状态考虑使用数据库存储而非文件对于大规模抓取建议使用Scrapy框架法律合规确保数据抓取和使用符合网站服务条款和相关法律法规在实际项目中我发现天气后报网站的数据更新会有1-2天的延迟如果需要最新数据建议结合其他数据源进行补充验证。另外冬季数据特别是供暖季的PM2.5值通常会明显高于其他季节这在数据分析时需要特别注意。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价