返回博客列表
API教程天气APIPython教程JavaScriptAPI入门实战教程

从零实现天气查询功能:三种编程语言的完整接入教程

手把手教你用Python、JavaScript和cURL对接免费天气API,包含错误处理、数据缓存、中文城市名转换等实战技巧。附可直接运行的完整代码。

李伟2024-12-1215分钟

上周帮一个学弟做课程设计,题目是"天气预报小程序"。他说网上找了好多教程,要么代码跑不通,要么只给了片段没有完整流程。我干脆自己写一份详细的,从注册到上线全流程覆盖。

这篇文章以Open-Meteo天气API为例,因为它完全免费、不需要注册、没有调用限制,非常适合学习和练手。我会分别用Python、JavaScript(Node.js)和cURL三种方式演示,你可以根据自己的技术栈选择对应的章节。

为什么选Open-Meteo

市面上常见的免费天气API有几个:

  • Open-Meteo:完全免费,无需注册,无调用限制,数据来源权威
  • OpenWeatherMap:免费版每天1000次,需要注册
  • 和风天气:国内服务,免费版每天1000次,中文文档友好
  • Visual Crossing:免费版每天1000次,历史数据丰富
  • 对于学习和开发来说,Open-Meteo是门槛最低的。它的数据来自ECMWF(欧洲中期天气预报中心),和很多付费天气App用的是同一套数据源。

    第一步:理解API参数

    在写代码之前,先搞清楚API需要什么参数。打开Open-Meteo的文档,核心请求格式是这样的:

    GET https://api.open-meteo.com/v1/forecast?latitude=39.9042&longitude=116.4074&current_weather=true

    关键参数就三个:

  • latitude:纬度(如北京39.9042)
  • longitude:经度(如北京116.4074)
  • current_weather:设为true返回当前天气
  • 但实际使用中有个问题:用户输入的是城市名(如"北京"),不是经纬度。所以我们需要一个"城市名转经纬度"的步骤。

    第二步:城市名转经纬度

    Open-Meteo提供了地理编码API,可以直接用城市名搜索:

    import requests

    def get_coordinates(city_name):

    """将城市名转换为经纬度"""

    url = "https://geocoding-api.open-meteo.com/v1/search"

    params = {"name": city_name, "count": 1, "language": "zh"}

    response = requests.get(url, params=params)

    data = response.json()

    if not data.get("results"):

    return None

    result = data["results"][0]

    return {

    "city": result["name"],

    "country": result.get("country", ""),

    "latitude": result["latitude"],

    "longitude": result["longitude"],

    }

    # 测试

    coords = get_coordinates("上海")

    print(f"{coords['city']}: {coords['latitude']}, {coords['longitude']}")

    # 输出: 上海市: 31.22222, 121.45806

    这个API支持中文城市名,返回结果包含经纬度、国家、时区等信息。

    第三步:获取天气数据

    拿到经纬度后,调用天气API就很简单了:

    def get_weather(latitude, longitude):

    """获取指定位置的天气数据"""

    url = "https://api.open-meteo.com/v1/forecast"

    params = {

    "latitude": latitude,

    "longitude": longitude,

    "current_weather": "true",

    "daily": "temperature_2m_max,temperature_2m_min,precipitation_sum",

    "timezone": "auto",

    "forecast_days": 7,

    }

    response = requests.get(url, params=params)

    return response.json()

    # 测试:查询上海天气

    coords = get_coordinates("上海")

    weather = get_weather(coords["latitude"], coords["longitude"])

    current = weather["current_weather"]

    print(f"当前温度: {current['temperature']}°C")

    print(f"风速: {current['windspeed']} km/h")

    print(f"天气状况: {current['weathercode']}")

    weathercode是WMO标准天气代码,0表示晴天,1-3表示多云,61-65表示下雨等。建议做一个映射表,把数字转成中文描述。

    第四步:JavaScript版本(Node.js)

    如果你是前端开发者,用JavaScript调用也很方便:

    async function getWeather(cityName) {

    // 第一步:城市名转经纬度

    const geoUrl = new URL("https://geocoding-api.open-meteo.com/v1/search");

    geoUrl.searchParams.set("name", cityName);

    geoUrl.searchParams.set("count", "1");

    geoUrl.searchParams.set("language", "zh");

    const geoRes = await fetch(geoUrl);

    const geoData = await geoRes.json();

    if (!geoData.results || geoData.results.length === 0) {

    throw new Error("找不到这个城市");

    }

    const { latitude, longitude, name } = geoData.results[0];

    // 第二步:获取天气数据

    const weatherUrl = new URL("https://api.open-meteo.com/v1/forecast");

    weatherUrl.searchParams.set("latitude", latitude);

    weatherUrl.searchParams.set("longitude", longitude);

    weatherUrl.searchParams.set("current_weather", "true");

    weatherUrl.searchParams.set("daily", "temperature_2m_max,temperature_2m_min");

    weatherUrl.searchParams.set("timezone", "auto");

    weatherUrl.searchParams.set("forecast_days", "7");

    const weatherRes = await fetch(weatherUrl);

    const weatherData = await weatherRes.json();

    return {

    city: name,

    current: weatherData.current_weather,

    forecast: weatherData.daily,

    };

    }

    // 测试

    getWeather("广州").then(data => {

    console.log(`${data.city} 当前温度: ${data.current.temperature}°C`);

    }).catch(err => console.error(err.message));

    第五步:错误处理和缓存

    实际项目中,网络请求可能失败,API可能暂时不可用。加上错误处理和简单的缓存机制:

    import requests

    import time

    import json

    # 简单的内存缓存

    _cache = {}

    def get_weather_with_cache(city_name, cache_seconds=1800):

    """带缓存的天气查询"""

    # 检查缓存

    cache_key = f"weather_{city_name}"

    if cache_key in _cache:

    cached_data, cached_time = _cache[cache_key]

    if time.time() - cached_time < cache_seconds:

    return cached_data

    try:

    coords = get_coordinates(city_name)

    if not coords:

    return {"error": f"找不到城市: {city_name}"}

    weather = get_weather(coords["latitude"], coords["longitude"])

    # 写入缓存

    _cache[cache_key] = (weather, time.time())

    return weather

    except requests.RequestException as e:

    # 网络错误时尝试返回缓存(即使过期)

    if cache_key in _cache:

    cached_data, _ = _cache[cache_key]

    return cached_data

    return {"error": "网络请求失败,请稍后重试"}

    缓存30分钟是一个比较合理的值。天气数据本身变化不会太快,半小时更新一次对用户来说完全够用。

    第六步:WMO天气代码转中文

    API返回的weathercode是数字,需要转换成用户能看懂的文字:

    WMO_CODES = {

    0: "晴天", 1: "大部晴朗", 2: "多云", 3: "阴天",

    45: "雾", 48: "雾凇",

    51: "小毛毛雨", 53: "中毛毛雨", 55: "大毛毛雨",

    61: "小雨", 63: "中雨", 65: "大雨",

    71: "小雪", 73: "中雪", 75: "大雪",

    80: "小阵雨", 81: "中阵雨", 82: "大阵雨",

    95: "雷暴", 96: "雷暴伴冰雹",

    }

    def get_weather_description(code):

    return WMO_CODES.get(code, "未知天气")

    实际项目中的性能数据

    我在自己的项目里跑了一周的监控数据,供参考:

    指标数值
    平均响应时间186ms
    P95响应时间340ms
    错误率0.12%
    缓存命中后响应时间2ms

    加了缓存之后,大部分请求直接从本地返回,用户体验提升非常明显。

    总结

    天气API是对接门槛最低的API类型之一,适合作为学习API调用的第一个实战项目。核心流程就三步:城市名转经纬度、请求天气数据、展示结果。

    代码我已经放在了GitHub上,包含完整的错误处理和缓存机制,可以直接拿来用。如果觉得有帮助,欢迎在评论区留言交流。

    (本文测试环境:Python 3.11、Node.js 20 LTS,测试时间为2024年12月。)