一、项目背景与痛点分析
在日常生活中,无论是日常出行、户外活动规划、校园通勤还是农业气象参考,天气查询都是不可或缺的需求。然而,当前市面上的主流天气应用和网页工具存在诸多不足,同时传统的爬虫脚本缺乏可视化界面,难以实际落地使用。具体痛点如下:
1.1 第三方平台体验问题
- 广告干扰严重:主流天气网页充斥着弹窗广告、开屏广告,还会推送无关资讯内容,用户只想查看天气却被大量无关信息干扰
- 城市切换繁琐:每次查询不同城市天气都需要重新输入或定位,高频查看的家乡、工作城市无法一键快捷访问
1.2 传统爬虫局限性
- 缺乏可视化界面:绝大多数Python天气爬虫仅能在控制台打印文本数据,没有网页界面和趋势图表,实用性较差
- 数据更新滞后:手动触发爬虫获取天气数据,无法实现后台定时自动刷新,温度、风力、降雨预警数据存在延迟
- 无历史数据回溯:无法留存过往每日温度、湿度数据,不能查看近期气温变化走势,缺乏历史天气数据复盘能力
针对以上痛点,本项目基于Python网络爬虫 + Django4.2 + ECharts可视化技术栈,搭建轻量化天气预报系统。通过调用公开免费天气API结合定向爬虫抓取气象数据,实现城市天气搜索、常用城市收藏、实时天气详情、未来7天预报、气温趋势曲线图、历史天气数据留存、后台定时自动更新等全功能模块,打造纯净无广告的私有化天气查询平台。
二、核心目标与项目定位
2.1 核心目标
搭建无广告私有化网页版天气查询平台,实现完整业务流程:
- 用户城市搜索 → 爬虫拉取实时气象数据
- 天气数据入库持久化 → 当日详情卡片展示
- 7日预报折线图可视化 → 常用城市收藏管理
- Celery定时自动刷新 → 历史天气数据回溯
2.2 项目定位
- 技术栈定位:Django结合Python爬虫的轻量化可视化Web项目
- 架构选择:采用原生MVT架构,无需前后端分离,上手难度极低
- 权限设计:区分普通用户与管理员权限,管理员可后台管理城市列表、手动刷新全站天气数据
- 成本控制:全程使用免费公开气象数据源,零调用成本
- 学习价值:适合爬虫入门+Django网页联动实战学习
2.3 设计理念
- 页面极简干净:去除所有冗余元素,专注核心功能
- 数据实时同步:确保天气信息的时效性和准确性
- 图表直观易懂:通过可视化图表提升数据可读性
- 自动化免手动:减少用户操作步骤,提升使用体验
- 无广告无推送:回归天气查询工具的本质价值
三、整体技术架构设计
3.1 分层架构流程图
3.2 技术栈详细清单
| 技术组件 | 具体实现 | 主要作用 |
|---|---|---|
| 后端框架 | Python 3.11、Django 4.2 | 原生MVT架构,开发部署零门槛 |
| 爬虫工具 | requests、bs4、json | 接口请求与结构化数据解析 |
| 定时调度 | Celery 5.2 + Redis | 实现每日自动更新天气数据 |
| 数据可视化 | ECharts | 多维度展示气象变化趋势 |
| 缓存优化 | Redis | 缓存高频访问城市天气,降低接口请求次数 |
| 辅助工具 | time、pytz | 时区校准,避免气象时间偏差 |
| 权限控制 | Django原生登录鉴权 | 仅登录用户可使用收藏功能 |
四、核心功能模块详解
4.1 城市天气爬虫抓取模块
功能特性
- 数据抓取范围:实时温度、体感温度、风力风向、空气湿度、气压、能见度、天气状况
- 预报数据同步:未来7天日间夜间温度、天气类型、风力变化数据
- 反爬机制规避:浏览器UA请求头伪装、请求间隔设置、单IP请求频率限制
- 数据清洗处理:自动过滤无用冗余字段,统一温度、时间格式,适配前端展示
技术实现要点
# 请求头伪装示例headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36","Accept":"application/json","Accept-Language":"zh-CN,zh;q=0.9"}4.2 城市搜索与收藏管理模块
搜索功能
- 模糊搜索支持:支持输入城市全称/简称,智能匹配对应城市气象数据
- 实时搜索反馈:输入过程中实时显示匹配结果,提升搜索效率
收藏管理
- 个人收藏夹:登录用户可添加常用城市至个人收藏,首页一键点击切换查看
- 权限隔离机制:不同用户收藏数据相互隔离,确保数据隐私安全
- 批量操作支持:支持单条删除与批量清空收藏列表两种操作方式
4.3 天气数据可视化图表模块
图表类型与作用
7日气温折线图
- 展示日间最高温、夜间最低温变化曲线
- 直观查看降温升温趋势,辅助穿衣决策
湿度变化曲线图
- 展示一周空气湿度波动情况
- 辅助判断潮湿、干燥天气,提醒防潮防燥
风力风向柱状图
- 可视化展示每日风力等级
- 方便出行防风参考,特别适合户外活动规划
天气状况图标系统
- 晴天、雨天、多云、雪天匹配对应图标
- 提升页面视觉体验,信息传达更直观
4.4 Celery定时自动更新模块
定时任务配置
# Celery定时任务配置示例fromcelery.schedulesimportcrontab CELERY_BEAT_SCHEDULE={'refresh-weather-every-day':{'task':'weather.tasks.auto_refresh_all_city_weather','schedule':crontab(hour=2,minute=0),# 每日凌晨2点执行},}核心功能特性
- 无人值守更新:每日凌晨2点自动爬取全网所有已收录城市最新天气数据
- 缓存智能刷新:同步清理Redis过期天气缓存,保证页面展示最新数据
- 异常重试机制:爬虫请求失败自动重试2次,保障网络波动场景下的数据更新
- 运行日志留存:后台记录每一次自动爬取时间、成功城市数量、失败城市数量
4.5 历史天气数据回溯模块
数据留存机制
- 每日快照存储:系统自动留存当日天气完整快照
- 多维度数据记录:温度、湿度、风力、天气状况等全方位记录
查询功能
- 日期选择查询:支持用户选择过往日期,回看历史气象数据
- 数据对比分析:支持多日期数据对比,查看气温变化趋势
- 月度统计报表:生成月度平均气温、降雨天数统计图表
4.6 后台城市管理模块
管理员功能
- 城市数据管理:自主新增、编辑、删除城市数据
- 手动数据刷新:一键触发全站天气数据刷新
- 运行日志查看:实时查看爬虫运行日志,快速排查问题
- 系统状态监控:监控接口请求成功率、数据完整性等关键指标
五、项目创新价值与核心亮点
5.1 用户体验优化
- 纯净无广告界面:自研网页无任何广告、资讯推送、弹窗干扰,专注天气查询核心功能
- 极速页面加载:Redis缓存优化+前端资源压缩,页面打开速度远快于第三方天气网页
5.2 技术实现创新
- 爬虫与Web深度整合:将爬虫后端与网页可视化有机结合,实现爬虫项目真正网页化落地
- 全自动化数据更新:依托Celery实现全自动无人值守更新,用户无需关心底层爬虫逻辑
- 多维度数据可视化:通过折线图、柱状图等可视化手段,将枯燥文本数据转化为直观图表
5.3 成本与实用性
- 零成本运营:全程使用免费公开气象接口,无需付费调用第三方天气API
- 高实用性设计:从个人使用到团队协作,满足不同场景下的天气查询需求
- 易部署易维护:提供Docker容器化部署方案,一键启动,降低运维门槛
六、应用场景与落地价值
6.1 个人使用场景
- 日常出行助手:本地或内网部署,作为个人专属无广告天气查询页面
- 户外活动规划:结合历史天气数据,科学规划户外活动时间
6.2 团队协作场景
- 校园气象看板:部署在校内服务器,作为公共气象大屏供师生使用
- 企业内网服务:公司内部部署,为员工提供统一的天气查询服务
- 农业气象参考:为农业生产提供历史天气数据分析和趋势预测
6.3 学习与教学价值
- 全栈开发实战:融合爬虫、定时任务、数据可视化三大热门后端技能
- Django进阶学习:涵盖MVT架构、Celery异步任务、Redis缓存等核心知识点
- 简历项目亮点:区别于常规业务管理系统,项目辨识度高,技术栈全面
七、完整代码实现与部署
7.1 项目目录结构
django-weather-crawl/ ├── manage.py ├── weather_project/ # 项目全局配置目录 │ ├── settings.py # Celery、Redis缓存、爬虫请求全局配置 │ ├── urls.py # 前端页面与接口路由分发 │ └── celery.py # 每日天气自动更新定时任务配置 ├── apps/ # 模块化业务应用拆分 │ ├── user_account/ # 用户登录、个人收藏管理模块 │ ├── city_manage/ # 城市基础信息、后台城市管理模块 │ ├── weather_crawl/ # 爬虫核心、数据清洗、接口请求模块 │ ├── weather_show/ # 天气页面渲染、ECharts图表数据封装模块 │ └── history_weather/ # 历史天气存储、历史数据查询模块 ├── core/ # 公共工具类封装 │ ├── crawl_tool.py # 天气爬虫核心请求工具类 │ ├── data_clean.py # 气象数据格式化清洗工具 │ ├── weather_task.py # Celery定时自动爬取任务 │ └── ua_pool.py # 爬虫请求头UA池,提升反爬能力 ├── static/ # ECharts图表、天气图标静态资源 ├── templates/ # 天气首页、详情页、收藏页前端模板 ├── requirements.txt # Python爬虫+Django全套依赖清单 └── docker-compose.yml # 一键容器化部署脚本7.2 核心代码实现
7.2.1 天气爬虫核心工具类
# core/crawl_tool.pyimportrequestsimportjsonimporttimefromtypingimportOptional,Dictfromcore.ua_poolimportget_random_ua# 免费公开天气API地址WEATHER_API_URL="https://v0.yiketianqi.com/free/day"classWeatherCrawlTool:"""天气数据爬虫工具类 - 负责与第三方天气API交互"""@staticmethoddefget_city_weather(city_name:str)->Optional[Dict]:""" 根据城市名爬取实时天气+7日预报数据 Args: city_name: 城市名称,支持中文城市名 Returns: 结构化天气字典数据,包含实时天气和7日预报 如果请求失败返回None """headers={"User-Agent":get_random_ua(),"Accept":"application/json","Accept-Language":"zh-CN,zh;q=0.9"}params={"appid":"demo",# 实际使用时替换为申请的appid"appsecret":"demo",# 实际使用时替换为对应的appsecret"city":city_name,"version":"v9"}try:# 添加请求延迟,避免触发反爬机制time.sleep(0.5)# 发起接口请求,设置超时时间response=requests.get(WEATHER_API_URL,headers=headers,params=params,timeout=10)# 状态码检查ifresponse.status_code!=200:print(f"【HTTP错误】城市:{city_name},状态码:{response.status_code}")returnNone# 解析JSON响应res_data=json.loads(response.text)# 业务状态码检查ifres_data.get("code")!=0:print(f"【业务错误】城市:{city_name},错误信息:{res_data.get('msg')}")returnNonereturnres_dataexceptrequests.exceptions.Timeout:print(f"【请求超时】城市:{city_name},接口响应超时")returnNoneexceptrequests.exceptions.ConnectionError:print(f"【连接错误】城市:{city_name},网络连接异常")returnNoneexceptjson.JSONDecodeError:print(f"【JSON解析错误】城市:{city_name},响应数据格式异常")returnNoneexceptExceptionase:print(f"【未知错误】城市:{city_name},错误信息:{str(e)}")returnNone7.2.2 天气数据模型设计
# apps/weather_crawl/models.pyfromdjango.dbimportmodelsfromdjango.utilsimporttimezonefromapps.city_manage.modelsimportCityclassRealTimeWeather(models.Model):"""实时天气数据表 - 存储当前时刻的天气信息"""city=models.ForeignKey(City,on_delete=models.CASCADE,verbose_name="关联城市",related_name="realtime_weather")date=models.CharField(max_length=20,verbose_name="查询日期")week=models.CharField(max_length=10,verbose_name="星期")wea=models.CharField(max_length=20,verbose_name="天气状况")tem_now=models.CharField(max_length=10,verbose_name="当前温度")tem_day=models.CharField(max_length=10,verbose_name="日间最高温")tem_night=models.CharField(max_length=10,verbose_name="夜间最低温")win=models.CharField(max_length=30,verbose_name="风力风向")humidity=models.CharField(max_length=10,verbose_name="空气湿度")pressure=models.CharField(max_length=10,verbose_name="气压",default="1013")visibility=models.CharField(max_length=10,verbose_name="能见度",default="10")update_time=models.DateTimeField(default=timezone.now,verbose_name="数据更新时间")classMeta:verbose_name="实时天气数据"verbose_name_plural=verbose_name ordering=["-update_time"]indexes=[models.Index(fields=['city','date']),models.Index(fields=['update_time']),]def__str__(self):returnf"{self.city.city_name}-{self.date}-{self.wea}"classWeekWeather(models.Model):"""七日天气预报数据表 - 存储未来7天的天气预报"""city=models.ForeignKey(City,on_delete=models.CASCADE,verbose_name="关联城市",related_name="week_weather")forecast_date=models.CharField(max_length=20,verbose_name="预报日期")forecast_wea=models.CharField(max_length=20,verbose_name="预报天气")forecast_tem_day=models.CharField(max_length=10,verbose_name="日间温度")forecast_tem_night=models.CharField(max_length=10,verbose_name="夜间温度")forecast_win=models.CharField(max_length=30,verbose_name="预报风力")forecast_humidity=models.CharField(max_length=10,verbose_name="预报湿度",default="60")create_time=models.DateTimeField(auto_now_add=True,verbose_name="数据录入时间")classMeta:verbose_name="七日天气预报"verbose_name_plural=verbose_name ordering=["city","forecast_date"]unique_together=['city','forecast_date']7.2.3 Celery每日凌晨自动更新天气定时任务
# apps/weather_crawl/celery_tasks.pyfromceleryimportshared_taskfromapps.city_manage.modelsimportCityfromcore.crawl_toolimportWeatherCrawlToolfromcore.data_cleanimportclean_weather_data@shared_taskdefauto_refresh_all_city_weather():"""每日凌晨定时任务:自动刷新全城市天气数据"""# 获取系统内所有收录城市city_list=City.objects.all()success_count=0fail_count=0forcityincity_list:# 爬虫获取原始天气数据raw_data=WeatherCrawlTool.get_city_weather(city.city_name)ifnotraw_data:fail_count+=1continue# 清洗并入库天气数据clean_weather_data(city.id,raw_data)success_count+=1# 返回本次定时任务执行结果return{"total_city":city_list.count(),"success_refresh":success_count,"fail_refresh":fail_count,"task_status":"finished"}八、总结与展望
本篇博客全新切入Python爬虫+Django网页可视化赛道,弥补了之前专栏缺少爬虫实战项目的空白,依托免费公开天气接口,从零实现自动化天气爬虫、网页展示、图表可视化、定时自动更新全套功能,全程无付费接口、无复杂第三方依赖,新手极易上手。
项目融合爬虫反爬处理、Django模型设计、Celery定时任务、Redis缓存优化、ECharts前端图表渲染、用户收藏权限隔离六大核心知识点,区别于常规业务管理系统,兼具爬虫脚本能力与Web项目落地能力,作为简历项目辨识度极高,同时和专栏过往8个项目场景、代码完全无重复。
后续迭代规划
- 新增天气预警推送功能,暴雨、大风、寒潮恶劣天气自动站内消息提醒;
- 增加生活指数推荐,根据天气自动推送穿衣、洗车、运动、出行建议;
- 接入IP自动定位,用户打开页面自动获取本地城市天气,无需手动搜索;
- 增加月度天气统计报表,生成月度平均气温、降雨天数统计图表。