数据获取 | python爬取CMA台风路径

2024-07-30 19:00:30 浏览数 (1)

数据获取 | python爬取CMA台风路径

前言

在自然灾害监测与预警领域,台风作为一种极具破坏力的自然现象,其路径预测和强度评估对于减少潜在损失至关重要。随着互联网技术的发展,国家气象中心等专业机构提供了详尽的台风历史数据和实时跟踪服务,通过网络接口可便捷地访问这些信息。

最近台风“格美”进化成超强台风了,碰巧同学投稿了一份代码用于爬取台风路径。

代码已开源,链接是https://github.com/SQYQianYe/scraping-cma-typhoon-data

代码主要利用Python编程语言和相关库(如requests, json, re, datetime, 和 pandas)从中国国家气象中心(NMC)获取台风数据,并对其进行解析、处理和存储。

通过定义一系列功能函数,如show_tc_nums_and_names_by_year()用于展示特定年份所有台风的编号和名称,get_tc_info_by_year_and_num()用于获取指定年份和编号的台风详细信息,以及get_tc_info()用于提取并整理台风的轨迹、强度变化等数据。

最终输出文件为csv和xlxs格式

代码语言:javascript复制
# 导入所需模块
import requests
import json
import re
import time
import pandas as pd
import datetime

# 设置请求头,模仿浏览器行为
headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'}

# 定义函数来显示某一年的所有台风编号和名称
def show_tc_nums_and_names_by_year(year):
    # 构建URL以获取JSON数据
    url = f"http://typhoon.nmc.cn/weatherservice/typhoon/jsons/list_{year}?callback=typhoon_jsons_list_{year}"
    # 发送GET请求并获取响应文本
    html_obj = requests.get(url, headers=headers).text
    
    # 处理字符串以提取有用的JSON部分
    json_obj = html_obj[html_obj.index("(")   1:html_obj.rindex(")")]
    # 将JSON字符串转换为字典
    json_dict = json.loads(json_obj)
    
    # 解析JSON数据中的台风编号和名称
    typhoon_list = json_dict.get("typhoonList", [])
    if typhoon_list:
        print(f"Year {year} has the following typhoons:")  # 打印年份和台风信息提示
        for typhoon in typhoon_list:
            # 格式化台风编号
            num = f"TC{typhoon[3]}"
            # 获取或生成中文名称
            name_cn = typhoon[2] if typhoon[2] != "null" else ""
            # 获取英文名称
            name_en = typhoon[1]
            # 打印台风编号及名称
            print(f"{num} ({name_en}, {name_cn})")
    else:
        print(f"No typhoon information found for year {year}")  # 如果没有找到台风信息,则打印提示

# 定义函数预测给定日期加上小时增量后的日期
def date_pred(date, deltahour):
    # 解析日期字符串为datetime对象
    time = datetime.datetime.strptime(date, "%Y%m%d%H%M")
    # 计算新日期
    new_date = (time   datetime.timedelta(hours=deltahour)).strftime("%Y%m%d%H%M")
    # 返回新日期字符串
    return new_date

# 定义函数根据类型字符串返回台风强度描述
def get_type(date_type):
    # 定义类型映射
    item = {'TC': '热带气旋', 'TD': '热带低压', 'TS': '热带风暴', 'STS': '强热带风暴',
            'TY': '台风', 'STY': '强台风', 'SuperTY': '超强台风', '': '',}
    # 返回对应描述或默认值
    return item.get(date_type, '')

# 定义函数获取特定台风的详细信息
def get_tc_info(item):
    # 创建13位时间戳
    t = int(round(time.time() * 1000))
    # 构建URL并发送GET请求
    url = 'http://typhoon.nmc.cn/weatherservice/typhoon/jsons/view_%s?t=%s&callback=typhoon_jsons_view_%s' % (item['id'], t, item['id'])
    html_obj = requests.get(url, headers=headers, verify=False).text
    # 提取JSON数据
    data = json.loads(re.match(".*?({.*}).*", html_obj, re.S).group(1))['typhoon']

    # 创建字典存储台风信息
    info_dicts = { 
        'tc_num':item['tc_num'],  # 台风编号
        'name_cn':item['name_cn'], # 中文名称
        'name_en':item['name_en'], # 英文名称
        'dateUTC':[],    # UTC日期
        'dateCST':[],    # CST日期
        'vmax':[],    # 最大风速 m/s
        'grade':[],   # 强度等级
        'lat':[],   # 纬度
        'lon':[],   # 经度
        'mslp':[],    # 中心气压 hPa
        'attr':[]   # 属性:预报或分析
    }

    # 遍历分析数据
    for v in data[8]:
        info_dicts['dateUTC'].append(v[1])
        info_dicts['dateCST'].append(date_pred(v[1], 8))  # 将UTC时间转换为CST时间
        info_dicts['vmax'].append(v[7])
        info_dicts['grade'].append(get_type(v[3]))
        info_dicts['lon'].append(v[4])
        info_dicts['lat'].append(v[5])
        info_dicts['mslp'].append(v[6])
        info_dicts['attr'].append('analysis')

    # 获取最新预报时间
    dateUTC0 = info_dicts['dateUTC'][-1]

    # 处理最新预报
    if len(data[8][-1]) > 11 and data[8][-1][11] is not None and 'BABJ' in data[8][-1][11]:
        BABJ_list = data[8][-1][11]['BABJ']
        for i in range(len(BABJ_list)):
            # 获取预报前置时间(小时)
            pred_hour = int(BABJ_list[i][0])
            # 预测UTC时间
            dateUTC_pred = date_pred(dateUTC0, pred_hour)
            info_dicts['dateUTC'].append(dateUTC_pred)
            info_dicts['dateCST'].append(date_pred(dateUTC_pred, 8))
            info_dicts['vmax'].append(BABJ_list[i][5])
            info_dicts['grade'].append(get_type(BABJ_list[i][7]))
            info_dicts['lon'].append(BABJ_list[i][2])
            info_dicts['lat'].append(BABJ_list[i][3])
            info_dicts['mslp'].append(BABJ_list[i][4])
            info_dicts['attr'].append('forecast')

    # 将字典转换为DataFrame
    tc_info = pd.DataFrame(info_dicts)
    # 返回DataFrame
    return tc_info

# 定义函数根据年份和编号获取台风信息
def get_tc_info_by_year_and_num(year, num):
    # 构建URL并发送GET请求
    url = f"http://typhoon.nmc.cn/weatherservice/typhoon/jsons/list_{year}?callback=typhoon_jsons_list_{year}"
    
    html_obj = requests.get(url, headers=headers, verify=False).text
    # 打印响应文本(调试用途)
    print(html_obj)
    # 提取JSON数据
    data = json.loads(re.match(".*?({.*}).*", html_obj, re.S).group(1))

    # 检查是否存在台风列表
    if data.get('typhoonList'):
        for item in data['typhoonList']:
            # 如果找到了匹配的台风编号
            if item[4] == num:
                # 创建包含台风ID、编号、中文名和英文名的字典
                tc = {
                    'id': item[0],
                    'tc_num': str(item[4]),
                    'name_cn': item[2],
                    'name_en': item[1]
                }
                # 返回台风详细信息
                return get_tc_info(tc)
    # 如果没有找到匹配的台风,则返回None
    return None

# 主程序入口
if __name__ == "__main__":
    # 设置请求头(重复,应避免)
    headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'}

    # 输入年份
    year = input("请输入年份: ")
    # 显示该年份的台风编号和名称
    show_tc_nums_and_names_by_year(year)
    # 输入台风TC编号(四位数字)
    num = input("请输入台风TC编号(TC后面四位数字): ")

    # 获取台风信息
    data = get_tc_info_by_year_and_num(year, num)

    # 如果数据存在,则打印并保存到CSV和Excel文件
    if data is not None:
        print(data)
        data.to_csv(rf'{year}_TC{num}.csv', index=False)
        print(f"台风{num}的数据已保存到文件{year}_TC{num}.csv")
        data.to_excel(rf'{year}_TY{num}.xlsx', index=False, engine='openpyxl')
        print(f"台风{num}的数据已保存到文件{year}_TC{num}.xlsx")
    # 如果未找到数据,则打印提示
    else:
        print(f"在{year}年未找到台风{num}的数据。")
代码语言:javascript复制
请输入年份: : 2024Year 2024 has the following typhoons:
TCNone (nameless, 热带低压)
TC2404 (PRAPIROON, 派比安)
TC2403 (GAEMI, 格美)
TC2402 (MALIKSI, 马力斯)
TC2401 (EWINIAR, 艾云尼)
请输入台风TC编号(TC后面四位数字): : 2403typhoon_jsons_list_2024({"typhoonList":[[2929137,"nameless","热带低压",null,null,20240003,null,"stop"],[2929257,"PRAPIROON","派比安",2404,"2404",20240004,"雨神","stop"],[2929285,"GAEMI","格美",2403,"2403",20240005,"一种非常细小、高度群居生活的昆虫;蚂蚁","start"],[2927830,"MALIKSI","马力斯",2402,"2402",20240002,"菲律宾语,快速的意思","stop"],[2924577,"EWINIAR","艾云尼",2401,"2401",20240001,"密克罗尼西亚楚克岛(Chuuk)传统的风暴之神","stop"]]})
   tc_num name_cn name_en       dateUTC       dateCST  vmax  grade      lat  
0    2403      格美   GAEMI  202407191200  202407192000    15   热带低压  13.7000   
1    2403      格美   GAEMI  202407191500  202407192300    15   热带低压  13.9000   
2    2403      格美   GAEMI  202407191800  202407200200    15   热带低压  14.5000   
3    2403      格美   GAEMI  202407192100  202407200500    15   热带低压  14.7000   
4    2403      格美   GAEMI  202407200000  202407200800    15   热带低压  15.3000   
..    ...     ...     ...           ...           ...   ...    ...      ...   
60   2403      格美   GAEMI  202407251000  202407251800    38     台风  25.5000   
61   2403      格美   GAEMI  202407252200  202407260600    28  强热带风暴  26.7167   
62   2403      格美   GAEMI  202407261000  202407261800    20   热带风暴  28.1083   
63   2403      格美   GAEMI  202407262200  202407270600    16   热带低压  29.4333   
64   2403      格美   GAEMI  202407271000  202407271800    15   热带低压  31.0333   

         lon  mslp      attr  
0   131.4000  1004  analysis  
1   130.8000  1004  analysis  
2   130.0000  1004  analysis  
3   129.7000  1004  analysis  
4   128.6000  1002  analysis  
..       ...   ...       ...  
60  119.2083   965  forecast  
61  118.1083   990  forecast  
62  117.0250   998  forecast  
63  116.1333   998  forecast  
64  115.3333  1000  forecast  

[65 rows x 11 columns]
台风2403的数据已保存到文件2024_TC2403.csv

小结

上述代码实现了以下几个关键功能:

数据获取:通过向NMC提供的API发送HTTP请求,获取指定年份的台风列表和特定台风的详细历史记录。 数据解析:使用正则表达式和JSON处理方法从原始响应中提取有用信息,包括台风的编号、名称、经纬度、风速、中心气压等。 数据展示与存储:将解析后的数据格式化输出至控制台,并将其保存为CSV和Excel文件,方便用户查阅和后续处理。 ps: 由于API数据可能随时间而变更,开发者需要定期检查并更新请求的URL和字段解析逻辑,以确保程序的持续可用性和准确性。

0 人点赞