Python实现爬虫:天气数据抓取(+折线图)

一、基本架构

1、URL管理器:爬虫的调度中枢

核心职责
功能 说明
URL去重 防止重复抓取
URL优先级管理 控制抓取顺序(广度优先/深度优先)
断点续爬支持 持久化存储抓取状态
分布式协同 多节点共享URL队列

2、网页下载器:数据获取的引擎

功能 实现方式
请求模拟 随机User-Agent/Cookie管理
代理管理 代理IP池+自动检测可用性
流量控制 自适应QPS限制
异常处理 自动重试+熔断机制
反反爬策略 TLS指纹伪装+请求随机延时

3、网页解析器:信息提取的核心

技术 适用场景 示例
XPath 结构化页面 //div[@class='content']
CSS选择器 简单页面 div.content > p.text
正则表达式 非结构化文本 \d{4}-\d{2}-\d{2}
OCR识别 验证码/图片文字 Tesseract引擎
深度学习 复杂语义抽取 BERT模型

二、代码展示

数据展示

代码展示

python 复制代码
"""
烟台市历史天气数据爬取及可视化
功能:从天气网站爬取2011-2012年数据,生成Excel表格并绘制气温折线图
"""

# ==================== 库导入 ====================
import requests  # 网络请求库
from bs4 import BeautifulSoup  # HTML解析库
import pandas as pd  # 数据处理库
import time  # 时间模块(用于延迟)
import random  # 随机数模块(用于随机延迟)
import matplotlib.pyplot as plt  # 绘图库
import matplotlib.dates as mdates  # 日期格式化模块


# ==================== 数据爬取函数 ====================
def save_a_month_data(url):
    """
    获取单个月份的天气数据
    :param url: 目标页面URL (格式: http://lishi.tianqi.com/yantai/YYYYMM.html)
    :return: 二维列表,包含该月每天的天气数据
    """
    a_month = []
    headers = {
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
    }

    try:
        # 发送带超时设置的GET请求(连接超时10秒,读取超时30秒)
        r = requests.get(url, headers=headers, timeout=(10, 30))
        r.raise_for_status()  # 检查HTTP状态码,非200会抛出异常
    except requests.exceptions.RequestException as e:
        print(f"请求失败:{url},错误:{e}")
        return a_month  # 返回空列表

    # 使用BeautifulSoup解析HTML
    soup = BeautifulSoup(r.text, 'html.parser')
    tianqi_zone = soup.find(class_='tian_three')  # 定位天气数据区域

    try:
        tianqi_data = tianqi_zone.find(class_='thrui')  # 定位数据列表
    except AttributeError:
        print(f"页面结构异常:{url}")
        return a_month

    # 提取每日数据(每个<li>标签代表一天)
    tianqi_data_a_month = tianqi_data.find_all('li')

    # 数据清洗处理
    for tianqi_data_a_day in tianqi_data_a_month:
        data = tianqi_data_a_day.text.split()  # 按空白字符分割文本

        # 处理异常格式:当某天有空气质量数据时字段数为7
        if len(data) == 7:
            data.pop(1)  # 移除第二个元素(原始数据中的冗余字段)
        a_month.append(data)

    return a_month


# ==================== 主程序:数据爬取 ====================
all_data = []  # 存储所有月份的数据

# 注意:range的结束值不包含,2011-2012年应写range(2011, 2013)
for year in range(2011, 2013):  # 修正后的年份范围
    for month in range(1, 13):
        month_str = f"{year}{month:02d}"  # 格式化月份为两位数(如201101)
        url = f"http://lishi.tianqi.com/yantai/{month_str}.html"
        print(f"正在抓取:{url}")

        # 调用爬取函数并合并数据
        a_month_data = save_a_month_data(url)
        all_data += a_month_data

        # 随机延迟(1~3秒)防止触发反爬机制
        time.sleep(random.uniform(1, 3))

# ==================== 数据保存 ====================
# 注意:如果桌面已存在weather_data.xlsx文件,需先关闭该文件
df = pd.DataFrame(all_data, columns=["日期", "最高温", "最低温", "天气", "风力风向", "空气质量"])
df.to_excel("C:/Users/lenovo/Desktop/weather_data.xlsx", index=False)
print("数据已保存至桌面")

# ==================== 数据可视化 ====================
# 重新读取数据(避免修改原始数据影响后续操作)
df = pd.read_excel("C:/Users/lenovo/Desktop/weather_data.xlsx")

# ---------- 数据预处理 ----------
# 1. 转换日期格式(将字符串转为datetime类型)
df['日期'] = pd.to_datetime(df['日期'])
# 2. 清洗温度数据(去除℃符号并转为浮点数)
df['最高温'] = df['最高温'].str.replace('℃', '').astype(float)
df['最低温'] = df['最低温'].str.replace('℃', '').astype(float)

# 筛选指定时间段数据
mask = (df['日期'] >= '2011-01-01') & (df['日期'] <= '2012-12-31')
df_filtered = df.loc[mask]

# ---------- 图表配置 ----------
# 设置中文字体(Windows系统使用SimHei)
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题

# 创建画布(单位:英寸,15x6英寸≈38x15厘米)
plt.figure(figsize=(15, 6))

# ---------- 绘制折线图 ----------
# 绘制最高温曲线(颜色代码:橙红色)
plt.plot(df_filtered['日期'], df_filtered['最高温'],
         label='最高温', color='#FF4500', linewidth=1.2)
# 绘制最低温曲线(颜色代码:道奇蓝)
plt.plot(df_filtered['日期'], df_filtered['最低温'],
         label='最低温', color='#1E90FF', linewidth=1.2)

# ---------- 图表美化 ----------
plt.title("烟台市气温变化 (2011-2012)", fontsize=14, pad=20)  # pad标题间距
plt.xlabel("日期", fontsize=12, labelpad=10)  # labelpad标签间距
plt.ylabel("温度 (℃)", fontsize=12, labelpad=10)
plt.grid(linestyle=':', color='gray', alpha=0.7)  # 虚线网格

# 设置x轴日期格式
ax = plt.gca()  # 获取当前坐标轴
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))  # 显示年月
ax.xaxis.set_major_locator(mdates.MonthLocator(interval=2))  # 每2个月一个主刻度
plt.xticks(rotation=45, ha='right')  # 标签旋转45度,右端对齐

# 添加图例(无边框,右上角位置)
plt.legend(loc='upper right', frameon=False)

# 自动调整子图参数(避免标签被截断)
plt.tight_layout()

# ---------- 保存与显示 ----------
# 保存高清图片(dpi=300为印刷级清晰度)
plt.savefig("C:/Users/lenovo/Desktop/2011-2012_temperature.png",
            dpi=300, bbox_inches='tight')  # bbox_inches='tight'去除白边
plt.show()  # 显示图表窗口

三、结果展示

相关推荐
Y1nhl1 小时前
搜广推校招面经五十五
人工智能·python·深度学习·机器学习·广告算法·推荐算法·搜索算法
老大白菜2 小时前
lunar是一款无第三方依赖的公历 python调用
前端·python
背着代码的蜗牛8 小时前
Pycharm远程开发注意事项
ide·python·pycharm·ssh·远程工作
墨绿色的摆渡人8 小时前
pytorch小记(十二):pytorch中 masked_fill_() vs. masked_fill() 详解
人工智能·pytorch·python
csdnsqst00508 小时前
QAI AppBuilder 快速上手(7):目标检测应用实例
python·ai·qualcomm·appbuilder·qnn·wos
mosquito_lover18 小时前
Python基于深度学习的多模态人脸情绪识别研究与实现
python·音视频·语音识别
迷鹿鹿鹿鹿鹿8 小时前
【基于深度学习的验证码识别】---- part3数据加载、模型等API介绍(1)
人工智能·pytorch·爬虫·深度学习
@jerry_tu8 小时前
DeepSeek Chat 自动化交互技术分析
运维·python·自动化
赛卡9 小时前
Python直方图:从核密度估计到高维空间解析
开发语言·人工智能·python·matlab