在数据驱动的时代,天气预报数据是气象分析、农业规划、物流调度等场景的重要基础。本文将通过一个完整案例,教你如何用Python的Requests库获取网页内容,再用BeautifulSoup解析HTML,最终实现天气预报数据的自动化采集。整个过程不涉及复杂理论,只讲实战技巧,即使你是编程新手也能轻松上手。
一、为什么选择Requests+BeautifulSoup组合?
在Python爬虫领域,Scrapy框架功能强大但学习曲线陡峭,Selenium能处理动态页面但效率较低。对于天气预报这类结构化数据采集,Requests+BeautifulSoup的组合具有显著优势:
- 轻量高效:Requests负责HTTP请求,BeautifulSoup专注解析,两者配合内存占用小
- 开发快速:30行代码就能实现基础功能,适合快速验证需求
- 维护简单:代码可读性强,便于后续修改和扩展
以中国天气网为例,其省级天气页面采用标准HTML结构,非常适合用这种组合采集。我们以采集"北京市天气预报"为例,展示完整实现过程。
二、环境准备与基础代码
1. 安装必要库
pip install requests beautifulsoup4 fake-useragent
requests
:发送HTTP请求beautifulsoup4
:解析HTMLfake-useragent
:生成随机User-Agent(反爬必备)
2. 基础请求代码
python
import requests
from bs4 import BeautifulSoup
from fake_useragent import UserAgent
def get_weather_page(url):
headers = {'User-Agent': UserAgent().random}
try:
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status() # 检查请求是否成功
response.encoding = 'utf-8' # 设置编码
return response.text
except requests.exceptions.RequestException as e:
print(f"请求失败: {e}")
return None
# 测试请求
url = "http://www.weather.com.cn/textFC/hb.shtml" # 华北地区天气
html_content = get_weather_page(url)
if html_content:
print("获取页面成功")
关键点说明:
- 随机User-Agent模拟不同浏览器访问
- 设置超时时间防止程序卡死
- 统一编码避免中文乱码
- 异常处理确保程序健壮性
三、HTML解析与数据提取
1. 分析页面结构
打开中国天气网华北地区页面,右键检查元素,找到天气数据所在的HTML结构:
xml
<div class="conMidtab">
<div class="conMidtab2">
<table class="twoInner">
<tr>
<td class="time">08时</td>
<td>晴</td>
<td>-2℃</td>
<td>3级</td>
</tr>
<!-- 更多行... -->
</table>
</div>
</div>
关键特征:
- 天气数据在
class="twoInner"
的表格中 - 每行数据包含时间、天气现象、温度、风力
2. 完整解析代码
ini
def parse_weather_data(html):
soup = BeautifulSoup(html, 'html.parser')
table = soup.find('table', class_='twoInner')
if not table:
print("未找到天气表格")
return []
weather_data = []
rows = table.find_all('tr')[1:] # 跳过表头
for row in rows:
cols = row.find_all('td')
if len(cols) >= 4:
data = {
'time': cols[0].get_text(strip=True),
'weather': cols[1].get_text(strip=True),
'temperature': cols[2].get_text(strip=True),
'wind': cols[3].get_text(strip=True)
}
weather_data.append(data)
return weather_data
# 测试解析
if html_content:
data = parse_weather_data(html_content)
for item in data[:3]: # 打印前3条
print(item)
输出示例:
css
{'time': '08时', 'weather': '晴', 'temperature': '-2℃', 'wind': '3级'}
{'time': '11时', 'weather': '晴', 'temperature': '3℃', 'wind': '2级'}
{'time': '14时', 'weather': '多云', 'temperature': '5℃', 'wind': '2级'}
3. 优化技巧
- 容错处理 :检查
table
是否存在,避免程序崩溃 - 数据清洗 :使用
get_text(strip=True)
去除空白字符 - 结构化输出:将每行数据转为字典,便于后续处理
四、完整采集流程
将上述代码整合为完整脚本,并添加数据存储功能:
python
import csv
from datetime import datetime
def save_to_csv(data, filename='weather.csv'):
if not data:
print("无数据可保存")
return
# 添加采集时间
for item in data:
item['update_time'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
# 写入CSV文件
with open(filename, 'w', newline='', encoding='utf-8-sig') as f:
writer = csv.DictWriter(f, fieldnames=data[0].keys())
writer.writeheader()
writer.writerows(data)
print(f"数据已保存到 {filename}")
def main():
url = "http://www.weather.com.cn/textFC/hb.shtml"
html = get_weather_page(url)
if html:
data = parse_weather_data(html)
save_to_csv(data)
if __name__ == '__main__':
main()
执行结果:
程序会在当前目录生成weather.csv文件,包含采集时间和所有天气数据。
五、进阶优化方向
1. 多城市采集
通过修改URL参数实现:
csharp
CITIES = {
'北京': 'hb.shtml', # 华北
'上海': 'hd.shtml', # 华东
# 添加更多城市...
}
def batch_collect():
for city, path in CITIES.items():
url = f"http://www.weather.com.cn/textFC/{path}"
html = get_weather_page(url)
if html:
data = parse_weather_data(html)
for item in data:
item['city'] = city # 添加城市字段
save_to_csv(data, f'weather_{city.lower()}.csv')
2. 定时采集
使用schedule
库实现每天8点自动采集:
scss
import schedule
import time
def job():
print("开始定时采集...")
main()
schedule.every().day.at("08:00").do(job)
while True:
schedule.run_pending()
time.sleep(60)
3. 数据可视化
用Matplotlib简单绘制温度变化曲线:
scss
import matplotlib.pyplot as plt
def plot_temperature(data):
times = [item['time'] for item in data]
temps = [int(item['temperature'].replace('℃', '')) for item in data]
plt.figure(figsize=(10, 4))
plt.plot(times, temps, marker='o')
plt.title('北京今日温度变化')
plt.xlabel('时间')
plt.ylabel('温度(℃)')
plt.grid(True)
plt.savefig('temperature.png')
plt.show()
六、常见问题Q&A
Q1:被网站封IP怎么办?
A:立即启用备用代理池,建议使用住宅代理(如站大爷IP代理),配合每请求更换IP策略。更简单的方案是设置请求间隔:
python
import time
import random
def safe_request(url):
time.sleep(random.uniform(1, 3)) # 随机延迟1-3秒
return get_weather_page(url)
Q2:网站结构变了怎么办?
A:定期检查解析代码是否还能正常工作。建议:
- 将选择器(如
class_='twoInner'
)提取为配置变量 - 添加页面结构校验逻辑
- 使用
try-except
捕获解析异常
Q3:如何采集动态加载的数据?
A:对于JavaScript渲染的数据,有两种方案:
- 分析接口:用浏览器开发者工具查找数据API(推荐)
- Selenium模拟:对复杂页面可使用Selenium+WebDriver
Q4:采集频率应该设置多少?
A:遵循robots.txt协议和网站服务条款。一般建议:
- 公开数据:每小时不超过1次
- 商业数据:联系网站获取授权
- 添加随机延迟避免规律性请求
Q5:如何存储大量历史数据?
A:根据数据量选择:
- 小规模:CSV/Excel
- 中等规模:SQLite数据库
- 大规模:MySQL/MongoDB等专业数据库
七、总结与展望
通过本文,你已掌握:
- 使用Requests发送HTTP请求
- 用BeautifulSoup解析HTML
- 提取结构化天气数据
- 存储和可视化数据
- 常见问题的解决方案
实际应用中,你可能需要处理:
- 登录验证
- 验证码识别
- 分布式采集
- 数据去重
建议从简单需求开始,逐步添加复杂功能。记住:爬虫开发的核心是模拟人类浏览行为,保持请求的随机性和合理性是长期运行的关键。