前言
业务场景中需要获取几个主要办公城市(北上广深杭)的天气预警信息,并通过 IM 机器人发送到指定的 IM 群中,方便相关同事及时了解天气预警信息。天气预警信息要求具体到县区级别,并标注预警等级和相关防范警示,大概就像下面这样:
【广东省广州市】广州市气象台 于北京时间 04月07日12时33分 发布 暴雨 III级黄色 预警信号,具体内容如下:
广州市气象台07日12时24分发布暴雨黄色预警信号:受西北方向移近的强雷雨云团影响,预计未来2-3小时,广州市越秀区、天河区有暴雨,累积雨量30-50毫米,并伴有雷电和6-7级短时大风。从07日12时24分起,广州市越秀区、天河区暴雨黄色预警信号生效,后期有升级暴雨预警信号的可能性。目前花都区雷雨大风和暴雨黄色预警信号已经生效,请注意做好防御工作。
大家平时在日常生活中也能在移动端的天气插件中收到相关天气预警信息,比如我本人用的是小米手机,小米天气插件会在天气预警信息发布时弹出通知,前几天清明节期间,广州一直在打雷下雨,雷雨大风和暴雨警告震得手机一直在响,最严重时候几乎是每隔 5 分钟就会有预警更新,各种颜色的预警信息在手机上不停地闪烁,领导大概是受到类似的启发,最终诞生了这个业务需求。
数据调研
调研阶段查看了很多气象站的预警信息公告,发现格式大多都很类似,于是猜测应该是有一个统一的模板和发布网站,最终查到了 国家突发事件预警信息,这里汇总了全国各地气象局的预警信息,按照时间倒序排列,预警标题形如 XXX(气象台/气象局/气象站) (发布/继续发布/更新/解除) (预警类型) (预警等级颜色)预警,少数格式上会有所不同,比如 嫩江市气象台将大风黄色预警信号升级为大风橙色预警信号 等等。网站数据应该是实时更新的,只汇总了最近一整天的预警信息,比如说当前时间是 2024-04-11 16:50:01,网站汇总的预警信息最早截止到 2024-04-10 16:50:01。

进一步翻看网页源代码,发现数据请求接口为 /data/alarm_list_all.html,返回的 JSON 数据是一个预警信息的列表,每个预警信息包含了发布时间、预警时间、预警标题、预警描述等字段,根据以上信息,初步方案可以编写一个爬虫程序定时获取这些预警信息,在后台进行数据处理和清洗后,提取相关关键信息并发送到 IM 机器人中。
{
"ctime": "2024-04-11 16:50:01",
"description": "鄱阳县气象台2024年04月11日16时48分发布雷电黄色预警信号:预计未来6小时内,白沙洲乡、昌洲乡、高家岭镇、古县渡镇、侯家岗乡、凰岗镇、枧田街乡、金盘岭镇、莲湖乡、莲花山乡、农科所、鄱阳镇、饶丰镇、饶州街道、三庙前乡、石门街镇、双港镇、四十里街镇、田畈街镇、团林乡、响水滩乡、谢家滩镇、鸦鹊湖乡、银宝湖乡、油墩街镇、游城乡、柘港乡、珠湖乡的部分地区有雷电活动,局地伴有短时强降水、雷暴大风等强对流天气,请注意防范。",
"headline": "鄱阳县气象台发布雷电黄色预警信号[III级/较重]",
"identifier": "36112841600000_20240411164819",
"sendTime": "2024-04-11 16:48:00"
},
{
"ctime": "2024-04-11 16:50:01",
"description": "华亭市气象台2024年04月11日16时44分发布冰雹橙色预警信号:预计6小时内,我市神峪乡、上关镇、安口镇、工业园区、东华镇、西华镇、马峡镇、山寨乡、河西镇、策底镇、砚峡乡局部地方有冰雹天气,并可能造成雹灾,请注意防范。",
"headline": "华亭市气象台发布冰雹橙色预警信号",
"identifier": "62088141600000_20240411164404",
"sendTime": "2024-04-11 16:44:04"
},
{
"ctime": "2024-04-11 16:45:01",
"description": "泰宁县气象台2024年04月11日16时40分发布雷电黄色预警信号:预计未来6小时内我县有雷电活动,局地伴有短时强降水、6~8级雷雨大风等强对流天气,请注意防范!",
"headline": "泰宁县气象台发布雷电黄色预警信号",
"identifier": "35042941600000_20240411164000",
"sendTime": "2024-04-11 16:40:00"
},
以上列出了三个预警信息的示例,字段含义如下:
ctime:预警信息在汇总平台网站上的发布时间。description:预警信息的详细描述。headline:预警信息的标题。identifier:预警信息的唯一标识,这个信息非常关键,是后续判断预警影响区域的重要来源。sendTime:预警信息源头的发布时间。
这里面的两个时间字段 ctime 和 sendTime 都是字符串格式,一般来说只关心 sendTime 字段。
方案设计(和试错)
方案一开始需要解决一个问题:如何解决重复拉取和处理的问题。
预警信息由于是实时更新,通过接口返回的列表按照 ctime 倒序排列,所以笔者一开始的方案是记录每一次拉取的最新一条预警信息的 ctime 字段,下一次拉取处理时,只处理这个时间点之后的预警信息,实际运行时发现这个方案有一个问题,就是预警信息发布到平台时是有延迟的,旧的预警信息可能会在新的预警信息发布后才被更新,如果按照 ctime 字段来判断是否处理过,就会导致部分预警信息被漏处理。
那么只能通过哈希表的方式来判断是否处理过,这样就需要每一条预警信息的哈希值,一开始笔者考虑过地点和时间联合作为哈希值,但后来发现其实源数据自身就提供了这样的信息。还记得之前提到的 identifier 字段吗?这个字段是预警信息的唯一标识,我们可以通过这个字段来判断预警信息是否已经拉取过,除此以外,这个 identifier 还包含了一些重要的信息,我一开始以为是随机生成的数字,后来发现前面的数字是地区的行政区划代码,后面的数字是时间戳,比如说 35042941600000_20240411164000,前 6 位 350429 恰好就是泰宁县的行政区划代码,后面的时间戳 20240411164000 也正好是预警信息的发布时间,这样一来,我们就可以通过这个字段来判断预警信息是否已经处理过。
最新的行政区划编号可见 2022年中华人民共和国县以上行政区划代码。
预警信号知识科普
根据预警信号_国家突发事件预警信息发布网,国家气象局定义了 13 种预警信号,具体这里就不列了,大家可以参考链接查看。对于大多数人来说,最常见的应该就是暴雨、暴雪、寒潮、台风、大雾这几种,尤其是在广东这种经常遭受台风袭击的地方,台风预警信号是最常见的,我小时候每到七八月份,就眼巴巴地盼着台风来,因为台风来了就不用上学了,高中有一年台风硬生生把国庆假期又延长了三四天,那时候真是开心得不得了。
除了以上 13 种预警信号以外,其实还有地震和森林火险预警信号,由于这两种预警信号不属于气象局预警发布的范畴,所以经常会被忽视。在这个基础上,各地气象局还会根据实际情况发布一些地方性的预警信号,比如说广东省气象局增加了雷雨大风、寒冷、强季风、山体滑坡四种预警信号,上海和杭州气象局新增了低温预警信号,这些预警信号都是根据当地的气象特点和历史数据制定的,具体标准可以参考各地气象局的官方网站。
笔者参考的预警信号分类主要来自以下几个网站:
- 预警信号_国家突发事件预警信息发布网,主要推荐这个网站,这里面除了对预警信号有最权威的解释外,还给出对不同预警信号的应对措施。
- 氣象災害預警信號
- 廣東省氣象災害預警信號
- 杭州天气预警信号解读
预警信号的等级分为 4 级,数字越小表示预警等级越高,等级从低到高分别为:
- I 级:红色预警信号,代表特别严重的灾害,可能会造成重大损失。
- II 级:橙色预警信号,代表严重的灾害,可能会造成较大损失。
- III 级:黄色预警信号,代表一般的灾害,可能会造成一定损失。
- IV 级:蓝色预警信号,代表较轻的灾害,可能会造成轻微损失。
- V 级:白色预警信号,深圳气象局为台风灾害新增的预警等级,其他预警信号中是没有的。
不同灾害预警信号的等级标准不同,比如说暴雨预警信号的等级标准是:
- I 级暴雨红色预警:3 小时内降雨量达 100 毫米以上,或者已达 100 毫米以上且降雨可能持续
- II 级暴雨橙色预警:3 小时内降雨量达 50 毫米以上,或者已达 50 毫米以上且降雨可能持续
- III 级暴雨黄色预警:6 小时内降雨量达 50 毫米以上,或者已达 50 毫米以上且降雨可能持续
- IV 级暴雨蓝色预警:12 小时内降雨量达 50 毫米以上,或者已达 50 毫米以上且降雨可能持续
值得注意的是,即使是同一种灾害,不同地区的预警信号等级标准也可能不同。比如为了区分北方的寒潮预警信号,广东省气象局并没有设置寒潮预警信号,而是设置了寒冷预警信号,这个预警信号的等级标准是:
- I 级寒冷红色预警:最低气温达到 0 度以下,或者日平均气温维持在 5 度以下。而这个标准在北方地区可能是不够的,因为北方地区的气温可能会达到零下 20 度甚至更低,寒潮红色预警要求最低气温下降幅度要达到 16 度以上。
- II 级寒冷橙色预警:最低气温达到 5 度以下,或者日平均气温维持在 10 度以下。寒潮橙色预警要求最低气温下降幅度要达到 12 度以上。
- III 级寒冷黄色预警:最低气温急剧下降 10 度以上,或者日平均气温维持在 12 度以下。寒潮黄色预警要求最低气温要小于等于 4 度。
有一些北方都又不是特别北的地方,比如说上海和杭州,就设置了低温预警信号,区分于寒潮和寒冷预警信号,此处不再赘述。