• 2009-10-10

    飞信免费订阅宣讲会信息 - [工作相关]

    1  发送短信的飞信命令

    这个程序主要基于邓东东开发的 libfetion 库,这个库不是开源的,但是作者提供了头文件和库文件,所以我们可以使用它的 API 来写一些自己的程序。 本篇博客是基于Solrex Shuffling的"定制自己的免费天气预报短信".

    发送信息的源程序以及库文件在Solrex的blog中有下载。需要的可以向我索要khb.hnu@gmail.com

    不过发现 Solrex 的源程序sendsms.cpp文件有一个地方存在内存泄漏;strdup函数的返回值是一个新字符串,该串由malloc申请,所以必须要程序员手动去free掉这个空间;否则会导致内存泄漏;为什么会存在这么危险的函数存在呢?

    strdup
    The strdup() function returns a pointer to a new string which is a duplicate of the strings. Memory for the new string is obtained with malloc(3), and can be freed with free(3).
    strdup() conforms to SVr4, 4.3BSD, POSIX.1-2001.

    同时,为了安全,我把飞信登录帐号和密码隐藏到源程序中。编译成可执行程序后是无法查看到的。

    2  使用SHELL抓包

      #!/bin/bash -x
    
      SMS_USER="15874082100,158xxxxxxxx,138xxxxxxx"
      URL="http://my.yingjiesheng.com/xuanjianghui_province_18.html"
      FILENAME="yjs-xjh.txt"
    
      get_html()
      {
      wget -nv -O $FILENAME $URL 2> /dev/null
      }
    
      parse_html()
      {
      #删除不必要的信息行
      grep  -v  "查看" $FILENAME >temp
      grep  -v  "暂未开通" temp >$FILENAME
      grep  -v  "GA_googleFillSlot" $FILENAME >temp
      grep  -v  "加入手机提醒" temp >$FILENAME
      grep  -v  "最近更新" $FILENAME >temp
      mv  temp $FILENAME
    
      #delete \n
      sed -nr -i  ' H; $ { x; s/\n//g; p }' $FILENAME
      #每一天的记录从新行开始
      sed -i  -e 's$\(<img[^<]\+clock.gif" />\)$\n\1$g' $FILENAME
      #去除html中的标记符
      sed -i  -e 's/<[^<>]\+>//g' $FILENAME
      #删除html中的换行符&nbsp
      sed -i -e 's/&nbsp;//g' $FILENAME
      #把每一条招聘记录从新行开始
      sed -i -e 's/长沙\s/\n长沙/g' $FILENAME
    
      #为节省字符数,连续多个tab转换成单个tab
      sed -i -e 's/\t\+/\t/g' $FILENAME
    
      #为节省字符数,删除行首和行尾的多余空格
      sed -i -e 's/\s\+$//g' $FILENAME
      sed -i -e 's/^\s\+//g' $FILENAME
      #由于第1行与最后一行不是我们所需要的信息,可以删除;
      sed -i -e '1d' $FILENAME
      sed -i -e '$d' $FILENAME
    
      #冗余信息
      sed -i -e 's/长沙\t//g' $FILENAME
    
      #获取当前星期
      week=`env LANG=en_US.UTF-8 date +%A`
      if [[ $week  == "Saturday" ]] ; then
      maxday=7;
      else
      maxday=0;
      fi
    
      for((i=0;i<=30;i++))
      do
      result=`grep -n ":$i 天" $FILENAME`
      if [[ $result != '' ]]; then
      if [ $i -gt $maxday ] ; then
      break;
      fi
      fi
      done
    
      #求取最后的行号
      echo $result >temp
      endno=$((`awk -F: '{print $1}' temp`))
    
      if [ $endno -gt 2 ];then
      #如果是星期天,则发送未来7天的宣讲会时间,并输出倒计时信息;
      #否则,只输出当天的宣讲会时间;
      if [[ $week  == "Saturday" ]] ; then
      sed -i -e       "1i\
      今天是 $week 未来一周的宣讲会安排如下:"  $FILENAME
      sed  -i -ne   "1,$endno"p $FILENAME
      else
      sed -i -e       "1a\
      `date +%Y-%m-%d`($week)的宣讲会安排如下:"  $FILENAME
      sed  -i -ne   "2,$endno"p $FILENAME
      fi
    
      else
      echo "今天没有宣讲会!" >$FILENAME
      fi
      }
    
      send_forcast()
      {
      #字符编码转换后通过飞信发送
      iconv -f GB2312 -t UTF8 $FILENAME | sendsms -vl -t  $SMS_USER
      }
    
      clear_html()
      {
      rm -f $FILENAME
      rm -f temp
      }
    
      get_html
      parse_html
      send_forcast
      #clear_html
      
    

    脚本里面注释很详细就不再唠叨。

    上面的脚本虽然看起来简单,但是我还是花了一下午时间才把所需要的信息包从网页中抓取出来。碰到如下几个问题:

    1. sed命令对"中文字符串"的处理比较弱,很多在vim下可以完成的正则表达式替换工作使用sed就是无法完成;
    2. 字符编码导致乱码问题;GB2312,ISO-8859,UTF8之间转换;最后使用iconv解决;

    3  自动定时运行

    安装好 sendsms 到 /usr/bin 之后,将上面脚本放到 YOURPATH 下,然后在命令行执行:crontab -e,将下面一行添加进去:
    00 09 * * * /YOURPATH/xjh.sh 1> /tmp/xjh.out 2> /tmp/xjh.err
    这样每天上午9:00就会自动执行;

    4  后记

    1. 本打算把所有的程序扔到unix center上运行;后面发现unix center的ubuntu的主机是x84_64,所需要的libcurl需要自己重新编译安装,没权限; 所以只能用自己的机子跑。设置定时开机,处理完了后定时关机。
    2. 上面的脚本只是针对于特定的网页进行抓包;其他的应用需要重新修改脚本;
    3. 使用飞信主要是考虑到定时发送宣讲会信息到手机,便于身边没有电脑时查看;
    4. 使用脚本抓包目的是提取信息自动化,不用人工干预;
    5. 定时运行可以每天自动获取信息,以免因为忘记而错过一场宣讲会;
    6. 最大的优点是可以群发,实现信息共享,当然必须对方是我的飞信好友;
    7. 飞信本身还是有些问题,我碰到好几次段错误导致程序崩溃;




    Post Addr: