5分钟搞定:用Python+Flask快速搭建天气预报API服务(附完整代码)

张开发
2026/5/4 15:53:09 15 分钟阅读
5分钟搞定:用Python+Flask快速搭建天气预报API服务(附完整代码)
从零构建高可用天气API服务Python Flask实战指南天气预报数据在现代应用中扮演着重要角色从出行App到智能家居系统都可能需要实时天气信息。本文将带你用Python Flask框架构建一个功能完备的天气API服务不仅包含基础数据获取还会实现缓存优化、限流保护和文档自动化等生产级功能。1. 项目架构设计在开始编码前我们需要明确服务的核心组件。一个完整的天气API服务应该包含以下模块数据获取层负责与第三方天气API交互业务逻辑层处理数据转换和业务规则API接口层对外提供RESTful接口辅助功能层包括缓存、限流、日志等技术选型方面我们使用Flask轻量级Web框架Redis缓存和限流存储Celery异步任务队列SwaggerAPI文档生成提示生产环境建议使用gunicorn或uWSGI作为WSGI服务器而不是直接运行Flask开发服务器2. 基础服务搭建首先创建项目结构mkdir weather-api cd weather-api python -m venv venv source venv/bin/activate # Linux/Mac # venv\Scripts\activate # Windows pip install flask redis celery python-dotenv创建基础Flask应用app.pyfrom flask import Flask, jsonify import os app Flask(__name__) app.config.from_mapping( SECRET_KEYos.getenv(SECRET_KEY, dev), REDIS_URLos.getenv(REDIS_URL, redis://localhost:6379/0) ) app.route(/health) def health_check(): return jsonify({status: healthy}) if __name__ __main__: app.run(host0.0.0.0, port5000)3. 集成天气数据接口我们使用和风天气作为数据源首先封装API客户端# services/weather.py import requests from datetime import datetime, timedelta from flask import current_app class WeatherService: BASE_URL https://devapi.qweather.com/v7/weather def __init__(self, api_key): self.api_key api_key self.cache_expire timedelta(hours1) def get_current_weather(self, location): cache_key fcurrent_{location} cached self._get_cache(cache_key) if cached: return cached url f{self.BASE_URL}/now?location{location}key{self.api_key} response requests.get(url) data response.json() if data.get(code) 200: self._set_cache(cache_key, data) return data raise ValueError(fWeather API error: {data.get(message)}) def _get_cache(self, key): # 实现Redis缓存获取 pass def _set_cache(self, key, value): # 实现Redis缓存设置 pass4. 实现核心API端点创建主要API路由api/weather.pyfrom flask import Blueprint, request, jsonify from services.weather import WeatherService from utils.rate_limit import rate_limited bp Blueprint(weather, __name__, url_prefix/api/v1) bp.route(/weather/current, methods[GET]) rate_limited(limit60, per300) # 每分钟60次请求 def current_weather(): location request.args.get(location) if not location: return jsonify({error: Location parameter is required}), 400 try: weather WeatherService(current_app.config[HEFENG_KEY]) data weather.get_current_weather(location) return jsonify(data) except ValueError as e: return jsonify({error: str(e)}), 5005. 高级功能实现5.1 Redis缓存集成# utils/cache.py import redis from flask import current_app from datetime import timedelta import pickle class Cache: def __init__(self): self.redis redis.from_url(current_app.config[REDIS_URL]) def get(self, key): val self.redis.get(key) return pickle.loads(val) if val else None def set(self, key, value, expireNone): if expire is None: expire current_app.config.get(CACHE_DEFAULT_EXPIRE, 3600) self.redis.setex(key, expire, pickle.dumps(value))5.2 请求限流保护# utils/rate_limit.py from functools import wraps from flask import request, jsonify import redis from datetime import timedelta def rate_limited(limit60, per300): def decorator(f): wraps(f) def wrapped(*args, **kwargs): # 获取客户端IP作为标识 identifier request.remote_addr key frate_limit:{identifier}:{request.endpoint} r redis.from_url(current_app.config[REDIS_URL]) current r.get(key) if current and int(current) limit: return jsonify({ error: Too many requests, retry_after: per }), 429 pipe r.pipeline() pipe.incr(key) pipe.expire(key, per) pipe.execute() return f(*args, **kwargs) return wrapped return decorator5.3 异步任务处理对于耗时的天气数据预处理可以使用Celery# tasks/weather.py from celery import Celery from services.weather import WeatherService celery Celery(__name__, brokerredis://localhost:6379/1) celery.task(bindTrue) def fetch_weather_data(self, location): try: weather WeatherService(current_app.config[HEFENG_KEY]) return weather.get_current_weather(location) except Exception as e: self.retry(exce, countdown60)6. API文档与测试使用Flask-RESTX自动生成Swagger文档# api/docs.py from flask_restx import Api, Resource, fields from flask import Blueprint bp Blueprint(api, __name__, url_prefix/api) api Api(bp, version1.0, titleWeather API, descriptionA simple Weather API service) weather_model api.model(Weather, { location: fields.String(requiredTrue, descriptionCity name or ID), temperature: fields.String(descriptionCurrent temperature), condition: fields.String(descriptionWeather condition) }) api.route(/weather) class WeatherResource(Resource): api.doc(get_current_weather) api.marshal_with(weather_model) def get(self): Get current weather for a location pass7. 部署与优化建议项目完成后可以考虑以下优化方向容器化部署使用Docker打包应用负载均衡Nginx反向代理多个实例监控告警Prometheus Grafana监控日志收集ELK日志分析系统一个简单的Dockerfile示例FROM python:3.9-slim WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt COPY . . ENV FLASK_APPapp.py ENV FLASK_ENVproduction EXPOSE 5000 CMD [gunicorn, --bind, 0.0.0.0:5000, app:app]在实际项目中我发现Redis缓存命中率对性能影响很大。通过调整缓存过期策略可以将API响应时间从平均800ms降低到200ms以下。另一个实用技巧是使用HTTP缓存头让客户端缓存不常变的数据app.route(/weather/current) def current_weather(): # ...获取天气数据... response jsonify(data) response.headers[Cache-Control] public, max-age300 # 5分钟缓存 return response

更多文章