定制自己的免费天气预报短信

摘要:这篇博客介绍了一种在 Linux 下使用飞信(libfetion 库)来定时发送天气预报短信的方法。本文的主要贡献是:一、提供了一个 Linux 下发送飞信的命令行程序;二、提供了一个到中国气象网抓取、过滤天气信息并发送短信的脚本。

Libfetion修改了调用接口,而且中国移动现在换IP登录就需要使用验证码。除非我哪天闲得蛋疼,搞一个验证码识别模块出来,否则本项目将不再维护,很抱歉!

天气预报短信一直是移动通信公司提供的一种收费服务,Google 免费天气预报服务打破了这个僵局。但是Google 的服务很不稳定,经常收不到短信,而且天气预报内容的定制性差。我家 xixi 一直有看天气预报的习惯,我就告诉她说我能写个程序每天给你发天气预报消息,她不相信,然后我就写了下面的程序。

首先感谢一下 mirth@bbs.nju.edu.cn,本文的主要内容是基于他在小百合 BBS 上发表的如何用飞信定时给自己发免费天气预报一文做的少许改进。

1. 发送飞信的命令行程序[1, 2, 3, 4, 5]

这个程序主要基于邓东东开发的 libfetion 库。这个库不是开源的,但是作者提供了头文件和库文件(在GUI源代码中),所以我们可以使用它的 API 来写一些自己的程序。下面的程序内容很简单,注释也不少,我就只贴源码,不再解释了(注意,编译时需要 curl 的 dev 库)。你可以在这里下载到我的 sendsms 小程序的源代码

sendsms
|-- Makefile
|-- include
|   |-- common.h
|   |-- datastruct.h
|   |-- event.h
|   |-- fxconfig.h
|   `-- libfetion.h
|-- lib
|   |-- libfetion_32.a
|   `-- libfetion_64.a
|-- sendsms
`-- sendsms.cpp

2. 到中国气象网抓取、过滤天气信息并发送短信的 bash 脚本

你可以从这里下载到下面的 bash 脚本,或者到这里下载几乎同样功能的 python 脚本。脚本就不多做解释了,没几行代码,相信稍微研究一下就能看懂。

天气网经常更新,新的脚本我就不再贴到博客里了。如果您发现天气预报脚本不好用了,就请关注脚本下载的地址,我一般会尽快更新的。

$ more weatherman.sh
#!/bin/bash
# This script fetch user specified citys' weather forecast from
# http://weather.com.cn, and send them using a CLI SMS sender "sendsms"
# which you can get from http://share.solrex.org/dcount/click.php?id=5.
#
# You can look for new or bug fix version
# @ http://share.solrex.org/scripts/weatherman.sh.
# Copyright (C) Solrex Yang <http://solrex.org> with GPL license.
#
# Usage: You should add it to crontab by "crontab -e", and then add a line
# such as:
# 00 20 * * * /usr/bin/weatherman.sh >> ~/bin/log/weatherman.log 2>&1
# which will send weather forecast to your fetion friends at every 8pm.

3. 将脚本设置为定时执行

安装好 sendsms 到 /usr/bin 之后,将上面脚本放到 YOURPATH 下,然后在命令行执行:crontab -e,将下面一行添加进去:

50 19 * * * /YOURPATH/weatherman.sh 1> /tmp/weatherman.out 2> /tmp/weatherman.err

就设置为每天下午 7 点 50 发送天气预报短信。

[1] 应大家要求,在程序中加入了读取 http_proxy 代理服务器环境变量的部分,其它类型的代理服务器可以自行添加(毕竟源代码给你了,随便改),增加了重试登录和发送的代码。

[2] 2008 年 11 月 30 日:增加了群发短信功能(多个接收者用','分隔)。

[3] 2009 年 01 月 11 日:增加从标准输入读入信息支持,可使用管道和输入重定向。这篇博客中的代码就不更新了,请到给出的链接去下载新版本。

[4] 2009 年 4 月 17 日:添加了"-l"选项,支持长短信发送,最长可到 1024 字节。解决了一个从标准输入读取短信的 bug。

[5] 2009 年 12 月 08 日:根据中国天气网的改版,更新抓取页面的脚本。

《定制自己的免费天气预报短信》上有68条评论

  1. 具体怎么弄呢?想试试今天下午能不能收到天气短信……

  2. 不错,百合上还是有高人啊。谢谢!

    建议在 login 之前设置登录状态为 OFFLINE。另外有人用代理的话还可以加入代理支持。(我没需求,就懒得弄了。)

    fprintf(stderr, "Failed to init.\n");
    return 1;
    }
    + fx_set_login_status(FX_STATUS_OFFLINE);
    ret = fs_login(args.from, args.passwd); /* Login with id and passwd. */
    if (!ret) {
    fprintf(stderr, "Failed to login.\n");

  3. 百合上的好东西还真不少阿~
    我定的google每天都来阿
    不过时间不好,都是早上九点,应该晚上比较理想

  4. 请问如果将该脚本放在网内,如何设置使用代理呀?

  5. [Comment ID #275331 Will Be Quoted Here]
    已经 update 到支持代理了,不过没有测试(没有测试环境 ^_^)
    谁要是发现代理功能不可用,就来评论一下吧。

  6. 赞!
    这才是干正事啊
    我都是用libfetion干坏事的
    经常用libfetion把一本小说发给同学,让他手机响一下午
    :)

  7. 我又重新下载试了一下,在使用代理环境下测试,对于“MY_CITIES”里,我也放入了两个城市,只有第一个城市可以,在发送第二个城市的时候就提示说“Failed to login.”现截取Terminal输出:
    get the ssic is ... (评论过长,讨论结束后部分内容被删除)

  8. @nettest:
    这个飞信库有时候登录会失败的,这是很正常的现象,通常情况下你可以选择重试(即加一个 while loop,每当返回值不是成功的时候就重新尝试登录或者发送)。
    只是我没有将重试写在代码中,因为我不喜欢这种在程序中强力循环的方式,万一网络有问题,程序就一直在那 loop。为避免这个问题你可以加一个重试次数的上限。

  9. 而后我又一再试了一下,好不容易,脚本全部发送成功!是的,确实是如你所说的飞信库的登录问题。
    在此甚为感谢博主的分享,这东西太实用了,谢谢!
    现在就是担心飞信这免费的功能能走多远!

  10. 最近也想好好利用下飞信 :-)
    貌似从这周一开始调用别人php实现的飞信,给朋友每天自动发点东西

    又在学python所以想把openfetion用python实现下...

  11. 再给点建议改进一下:
    能不能将脚本中的循环移进主程序中,这样只登录一次,就可以把所有的信息发送完。不用每发一条短信,又重新登录一次。

  12. 这样会引起程序太复杂,还是模块化一点比较好。您如果需要这个特性,完全可以自己添加。

  13. hi,你好
    我用下面这个函数发送消息给指定手机号码,这个号码非好友。
    fs_send_sms_by_mobile_no(args.to, args.message);
    可是总是不成功。有什么问题吗?

  14. 你确信仔细读了代码吗?我在代码上方已经用 FIXME 写出了这可能是一个 BUG。
    另外我想飞信应该是无法发送给非好友的手机号,不然这就是一个垃圾短信发送机了。

  15. 我发现一个问题,weather.com.cn 更新天气信息的速度非常慢,本来应该 18 点发布天气预报,他们先更新天气情况,再更新日期,而且是一个城市一个城市的更新,所以建议最后在 19 点半以后再发送天气消息可能才比较准确。

  16. 各位大大都是在自己的机子上跑这个吗?
    万一哪天晚上7:30时没开电脑,mm岂不是要生气?

  17. g++ -Iinclude -O2 -c sendsms.cpp
    g++ sendsms.o -Ilib/libfetion_64.a -L/home/cocobear/opt/lib/ -lcurl -pthread -o sendsms
    sendsms.o(.text+0x1d1): In function `main':
    : undefined reference to `fx_init' ... (评论过长,讨论结束后部分内容被删除)
    collect2: ld returned 1 exit status
    make: *** [sendsms] Error 1

    编译出错了。我的curl安装在/home/cocobear/opt/下

  18. 没发出去吗:
    g++ sendsms.o lib/libfetion_32.a -L/home/cocobear/opt/lib/ -lcurl -pthread -o sendsms
    /usr/lib/libc_nonshared.a(elf-init.oS)(.gnu.linkonce.t.__i686.get_pc_thunk.bx+0x0): In function `__i686.get_pc_thunk.bx':
    : multiple definition of `__i686.get_pc_thunk.bx' ... (评论过长,讨论结束后部分内容被删除)
    collect2: ld returned 1 exit status
    make: *** [sendsms] Error 1
    [crystallight]$ uname -an
    Linux crystallight 2.6.24.2-grsec-p4-peon-1.1.2-grsec #1 SMP Wed Feb 20 15:30:29 PST 2008 i686 GNU/Linux

  19. g++ sendsms.o lib/libfetion_32.a -lcurl -pthread -o sendsms
    lib/libfetion_32.a(timer.o)(.text+0x576): In function `fetion_timer_init':
    : undefined reference to `__stack_chk_fail_local' ... (评论过长,讨论结束后部分内容被删除)
    collect2: ld returned 1 exit status
    make: *** [sendsms] Error 1

    我的同样报错

  20. $ g++ sendsms.o lib.bak/libfetion_64.a -lcurl -pthread -o sendsms
    lib.bak/libfetion_64.a(dmd5.o): In function `d_MD5':
    dmd5.c:(.text+0x32): undefined reference to `MD5_Init' ... (评论过长,讨论结束后部分内容被删除)
    这样的错误如何解决呢?

  21. 我也弄了一个,用shell下载wap.weather.com.cn的数据,用cpp作的程序发送.现在用linux服务器的crontab每日定时发送.感觉是挺有意思的.有兴趣尝试我的程序的朋友可以点这里:http://tinyurl.com/czqtnh

  22. @Solrex Yang
    unix-center的ubuntu是64位的,我本机(32位)编的无法运行。但在上面编找不到curl:
    g++ -Iinclude -O2 -Wall -c sendsms.cpp
    sendsms.cpp: In function 'int main(int, char**)':
    g++ sendsms.o lib/libfetion_64.a -lcurl -pthread -o sendsms
    /usr/bin/ld: cannot find -lcurl
    collect2: ld returned 1 exit status
    make: *** [sendsms] Error 1
    后来登到上面的fedora,可以编,但编出来的程序无法登录飞信,5次尝试login失败return。fs_login只有一个bool的返回值,看不到具体的失败原因,郁闷
    不知道是不是端口有限制,我试过http和https的网页都可以访问。

  23. 根据DDD的说法,现在改过协议以后不能通过fs_send_sms_by_mobile_no函数来发送短信了...

  24. 博主你好
    用了你的程序和脚本 编译正常 脚本中get天气部分正常 但是总是收不到天气的短信 放上脚本 麻烦博主帮忙看看

    ... (评论过长,讨论结束后部分内容被删除)

    get_html
    parse_html
    #send_forcast
    #clear_html

    只是修改地区 和号码而已 但是执行 weatherman.sh 后没有收到短信 手工操作
    sendsms -vlf 13xxxxxxxxx -p **** -t 137********,135******** < 北京.txt
    是正常的

  25. 今天(Sep 10 )运行发现出了错误,是不是中国天气网站改了啊?怎么不能用了呢?

  26. 今天(Sep 10)运行出现了错误,天气信息为空,在处理过程中,内容被清空了!
    是不是中国天气网站的网页结构做了改动啊?

  27. 我(thinktech2009@gmail.com)给你发了邮件,不知道你收没收到,我都搞不清你的邮箱地址,汗~
    gmail名字里面好像不让出现+号的吧

  28. 现在这个版本的命令行的sendsms好像只能给 “飞信好友”发送短信息吧
    能否增加个给“手机好友”也能发送短信的功能呢?实现起来会不会太困难?

  29. @Purplebee
    unix center 可以用来跑这个服务吗?
    你的ubuntu定时开机,关闭计算机后中间断过电,还会定时启动吗?
    我的是不行,试验了,如果中间断过电,似乎定时开机就失效了

  30. @rabbit
    不知道什么原因,编译可以成功,但是消息是发不出去的。
    定时开机的功能只和 CMOS 有关,如果你的 CMOS 电池没问题,断电是不影响定时开机设置的。

  31. @Solrex Yang
    这个,我听说别人也又遇到这种情况的,所以也搞不清楚我的问题在哪里
    比如:我定时在每天早晨7:30开机,但是由于前一天晚上11点多会断电,结果早晨就不能自己启动了
    我也做过试验,比如我在12:00设置在今天13:30开机,12:30我正常关闭计算机,如果什么都不动,
    那么可以成功;如果我在13:00(这个时候系统仍处于关闭状态)将插线板上的按钮按一下(模拟中间断电过程)
    等待一分钟再按一下(模拟开始供电),这样子在13:30就起不来了!但我的bios设置确实是可以保存的,因为再次查看的时候和我设置的一样。

    你确定这个是电池问题?这么说如果我换一块电池就可以解决?

  32. @rabbit
    事实上我不了解为什么你会出现这个问题,照理说不应该这样的。定时开关机只与主板有关,与系统软件什么的没什么关系。如果你的主板确实不能这样做,那就没办法了。

  33. sendsms.cpp文件中strdup函数返回的字符串所申请的空间需要自己手动释放!否则会内存泄漏!

  34. 其实除了利用 Google 的服务外,还可以利用 139.com 邮箱的邮件到达短信提醒的功能
    实现免费的天气短信,我们只要找到一个接口,能定时向指定 139.com 邮箱发送天气邮件就可以了,
    这里就有一个自己开发的接口,有兴趣的朋友可以试试:http://api.liqwei.com/weather/subscription.asp
    只要输入 139.com 邮箱地址,选择订阅的城市就可以,而且支持订阅多个城市的天气,
    自我感觉用起来还行,当然别的邮箱也可以,就是无法收到天气短信,哈哈

    @Iron_Feet

  35. to:Solrex Yang
    ms天气网有局部地区改版,能否更新bash,同时时候可以考虑更换一下“天气源”

  36. @hata19
    我已经更新过了,你可以到脚本的地址去下载。我也想换一个更人性化适合手机消息的源,奈何没有找到合适的。

  37. @Solrex Yang
    其实,飞信的段错误问题一直没有解决.在群发短信的时候经常出现断错误,所以我现在基本放弃使用了.希望有一天段错误这个问题能解决.

  38. @khb_gl
    这个我也是无能为力,因为段错误是发生在libfetion的库里,但是ddd不愿意公开源代码,所以想调试都不好调试。而且那个错误不是每次都出现,也增加了找bug的难度。我平时使用来讲,还好吧,虽然不是很稳定,但是总得来说成功率还是很高的。只不过这两天飞信又升级了服务器,看来又得等libfetion升级了。

  39. 博主 新浪网推出了天气预报 看过源码 和天气网的很相似

  40. 用包里编译好的那个 sendsms 只能给自己发,给飞信好友就发不出去
    自己编译又出错,郁闷
    $ g++ sendsms.o lib/libfetion_32.a -lcurl -pthread -o sendsms
    collect2: ld 以信号 11 [段错误] 退出。
    /usr/bin/ld: i386:x86-64 architecture of input file `sendsms.o' is incompatible with i386 output

    还有那个验证码,真TMD烦人,看了几十次也写不出来,真想骂人!

  41. rabbit :
    @Purplebee
    unix center 可以用来跑这个服务吗?
    你的ubuntu定时开机,关闭计算机后中间断过电,还会定时启动吗?
    我的是不行,试验了,如果中间断过电,似乎定时开机就失效了

    我是用一个01年的815ept机器跑这个的,也有你这个问题。如果是用shutdown关机,就能够自己开机;如果直接断电,或者关机后拔了电源,就没办法自己开机。
    我也在怀疑是不是CMOS电池没电了,但手头没有满电电池,没法验证。
    PS1: 之前这个机器开机后会不定时的重启,不论是Windows还是Linux,后来我换了一个CMOS电池就好了(从体重秤上拔下来,非满电)
    PS2: 昨天没成功发出短信,忘了看错误log了,不知道是不是和飞信停止低版本支持有关

  42. 这回是真的不能发了,2010年9月7号开始的~~博主,救救偶们吧~

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注