`
阿尔萨斯
  • 浏览: 4166886 次
社区版块
存档分类
最新评论

微信公众帐号开发教程第16篇-应用实例之历史上的今天

 
阅读更多

内容概要

本篇文章主要讲解如何在微信公众帐号上实现“历史上的今天”功能。这个例子本身并不复杂,但希望通过对它的学习,读者能够对正则表达式有一个新的认识,能够学会运用现有的网络资源丰富自己的公众账号。


何谓历史上的今天

回顾历史的长河,历史是生活的一面镜子;以史为鉴,可以知兴衰;历史上的每一天,都是喜忧参半;可以了解历史的这一天发生的事件,借古可以鉴今,历史是不能忘记的。查看历史上每天发生的重大事情,增长知识,开拓眼界,提高人文素养。


寻找接口(数据源)

要实现查询“历史上的今天”,首先我们要找到相关数据源。笔者经过搜索发现,网络上几乎没有现成的“历史上的今天”API可以使用,所以我们只能通过爬取、解析网页源代码的方式得到我们需要的数据。笔者发现网站http://www.rijiben.com/上包含“历史上的今天”功能,就用它做数据源了。


开发步骤

为了便于读者理解,我们需要清楚该应用实例的开发步骤,主要如下:

1)发起HTTP GET请求,获取网页源代码。

2)运用正则表达式从网页源代码中抽取我们需要的数据。

3)对抽取得到的数据进行加工(使内容呈现更加美观)。

4)将以上三步进行封装,供外部调用。

5)在公众账号后台调用封装好的“历史上的今天”查询方法。


代码实现

笔者将上述步骤1)、2)、3)中的代码实现封装成了TodayInHistoryService类,并对外提供了getTodayInHistory()方法来获取“历史上的今天”。实现代码如下:

  1. importjava.io.BufferedReader;
  2. importjava.io.InputStream;
  3. importjava.io.InputStreamReader;
  4. importjava.net.HttpURLConnection;
  5. importjava.net.URL;
  6. importjava.text.DateFormat;
  7. importjava.text.SimpleDateFormat;
  8. importjava.util.Calendar;
  9. importjava.util.regex.Matcher;
  10. importjava.util.regex.Pattern;
  11. /**
  12. *历史上的今天查询服务
  13. *
  14. *@authorliufeng
  15. *@date2013-10-16
  16. *
  17. */
  18. publicclassTodayInHistoryService{
  19. /**
  20. *发起httpget请求获取网页源代码
  21. *
  22. *@paramrequestUrl
  23. *@return
  24. */
  25. privatestaticStringhttpRequest(StringrequestUrl){
  26. StringBufferbuffer=null;
  27. try{
  28. //建立连接
  29. URLurl=newURL(requestUrl);
  30. HttpURLConnectionhttpUrlConn=(HttpURLConnection)url.openConnection();
  31. httpUrlConn.setDoInput(true);
  32. httpUrlConn.setRequestMethod("GET");
  33. //获取输入流
  34. InputStreaminputStream=httpUrlConn.getInputStream();
  35. InputStreamReaderinputStreamReader=newInputStreamReader(inputStream,"utf-8");
  36. BufferedReaderbufferedReader=newBufferedReader(inputStreamReader);
  37. //读取返回结果
  38. buffer=newStringBuffer();
  39. Stringstr=null;
  40. while((str=bufferedReader.readLine())!=null){
  41. buffer.append(str);
  42. }
  43. //释放资源
  44. bufferedReader.close();
  45. inputStreamReader.close();
  46. inputStream.close();
  47. httpUrlConn.disconnect();
  48. }catch(Exceptione){
  49. e.printStackTrace();
  50. }
  51. returnbuffer.toString();
  52. }
  53. /**
  54. *从html中抽取出历史上的今天信息
  55. *
  56. *@paramhtml
  57. *@return
  58. */
  59. privatestaticStringextract(Stringhtml){
  60. StringBufferbuffer=null;
  61. //日期标签:区分是昨天还是今天
  62. StringdateTag=getMonthDay(0);
  63. Patternp=Pattern.compile("(.*)(<divclass=\"listren\">)(.*?)(</div>)(.*)");
  64. Matcherm=p.matcher(html);
  65. if(m.matches()){
  66. buffer=newStringBuffer();
  67. if(m.group(3).contains(getMonthDay(-1)))
  68. dateTag=getMonthDay(-1);
  69. //拼装标题
  70. buffer.append("≡≡").append("历史上的").append(dateTag).append("≡≡").append("\n\n");
  71. //抽取需要的数据
  72. for(Stringinfo:m.group(3).split("")){
  73. info=info.replace(dateTag,"").replace("(图)","").replaceAll("</?[^>]+>","").trim();
  74. //在每行末尾追加2个换行符
  75. if(!"".equals(info)){
  76. buffer.append(info).append("\n\n");
  77. }
  78. }
  79. }
  80. //将buffer最后两个换行符移除并返回
  81. return(null==buffer)?null:buffer.substring(0,buffer.lastIndexOf("\n\n"));
  82. }
  83. /**
  84. *获取前/后n天日期(M月d日)
  85. *
  86. *@return
  87. */
  88. privatestaticStringgetMonthDay(intdiff){
  89. DateFormatdf=newSimpleDateFormat("M月d日");
  90. Calendarc=Calendar.getInstance();
  91. c.add(Calendar.DAY_OF_YEAR,diff);
  92. returndf.format(c.getTime());
  93. }
  94. /**
  95. *封装历史上的今天查询方法,供外部调用
  96. *
  97. *@return
  98. */
  99. publicstaticStringgetTodayInHistoryInfo(){
  100. //获取网页源代码
  101. Stringhtml=httpRequest("http://www.rijiben.com/");
  102. //从网页中抽取信息
  103. Stringresult=extract(html);
  104. returnresult;
  105. }
  106. /**
  107. *通过main在本地测试
  108. *
  109. *@paramargs
  110. */
  111. publicstaticvoidmain(String[]args){
  112. Stringinfo=getTodayInHistoryInfo();
  113. System.out.println(info);
  114. }
  115. }
代码解读:

1)27-58行代码是httpRequest()方法,用于发起http get请求,获取指定url的网页源代码。

2)66-92行代码是extract()方法,运用正则表达式从网页源代码中抽取“历史上的今天”数据。

3)111-118行代码是getTodayInHistory()方法,封装给外部调用查询“历史上的今天”。

4)125-128行代码是main方法,用于在本地的开发工具中测试。

5)75-76行代码的作用是判断获取到的“历史上的今天”数据是当天的还是前一天的(因为不能保证www.rijiben.com上的数据一定在凌晨零点准时更新,所以为了保证数据的准确性必须做此判断)。

6)第71行代码是本文的重点,笔者编写的正则表达式规则是“(.*)(<div class=\"listren\">)(.*?)(</div>)(.*)”。正则表达式规则需要根据网页源代码进行编写的,特别是包含“历史上的今天”数据的那部分HTML标签,所以我们先来查看网页源代码。通过httpRequest("http://www.rijiben.com/")方法获取到的网页源代码,与我们通过浏览器访问http://www.rijiben.com/页面再点击右键选择“查看网页源代码”所得到的结果完全一致。我们通过浏览器查看http://www.rijiben.com/的网页源代码,然后找到“历史上的今天”数据所在位置,如下图所示:


从上面的源代码截图中可以看到,我们需要的数据被包含在<div class="listren">标签内,这样就不难理解为什么正则表达式要这样写:

(.*)(<div class=\"listren\">)(.*?)(</div>)(.*)

我们使用括号()将正则表达式规则分成了5组,下面是这些分组的说明:

第1组:(.*)表示网页源代码中<div class="listren">标签之前还有任意多个字符。
第2组:(<div class=\"listren\">)中的反斜杠表示转义,所以该规则就是用于匹配<div class="listren">。
第3组:(.*?)表示在标签<div class="listren">和</div>之间的所有内容,这才是我们真正需要的数据所在。
第4组:(</div>)就是用于匹配<div class="listren">的结束标签。
第5组:(.*)表示在</div>标签之后还有任意多的字符。

掌握了正则表达式规则的含义,就不难理解为什么在extract()方法中全都是在使用m.group(3),因为m.group(3)就表示匹配到数据的第3个分组。m.group(3)的内容如下:

  1. <ul><li><ahref="/news6836/"title="0690年10月16日武则天登上皇位">0690年10月16日武则天登上皇位</a>(图)</li><li><ahref="/news6837/"title="1854年10月16日唯美主义运动的倡导者王尔德诞辰">1854年10月16日唯美主义运动的倡导者王尔德诞辰</a></li><li><ahref="/news6838/"title="1854年10月16日德国社会主义活动家考茨基诞生">1854年10月16日德国社会主义活动家考茨基诞生</a></li><li><ahref="/news6839/"title="1908年10月16日阿尔巴尼亚领导人恩维尔·霍查诞辰">1908年10月16日阿尔巴尼亚领导人恩维尔·霍查诞辰</a>(图)</li><li><ahref="/news6840/"title="1913年10月16日中国“两弹一星”元勋钱三强诞辰">1913年10月16日中国“两弹一星”元勋钱三强诞辰</a>(图)</li><li><ahref="/news6841/"title="1922年10月16日开滦煤矿工人失败">1922年10月16日开滦煤矿工人失败</a>(图)</li><li><ahref="/news6842/"title="1927年10月16日德国诺贝尔文学奖得主格拉斯诞生">1927年10月16日德国诺贝尔文学奖得主格拉斯诞生</a>(图)</li><li><ahref="/news6843/"title="1933年10月16日抗日同盟军失败">1933年10月16日抗日同盟军失败</a>(图)</li><li><ahref="/news6844/"title="1950年10月16日人民解放军进军西藏">1950年10月16日人民解放军进军西藏</a>(图)</li><li><ahref="/news6845/"title="1954年10月16日俞平伯《关于红楼梦研究问题的信》发表">1954年10月16日俞平伯《关于红楼梦研究问题的信》发表</a>(图)</li><li><ahref="/news6846/"title="1959年10月16日美军将领、国务卿马歇尔去世">1959年10月16日美军将领、国务卿马歇尔去世</a>(图)</li><li><ahref="/news6847/"title="1964年10月16日勃列日涅夫取代赫鲁晓夫成为苏共中央第一书记">1964年10月16日勃列日涅夫取代赫鲁晓夫成为苏共中央第一书记</a></li><li><ahref="/news6848/"title="1964年10月16日我国第一颗原子弹爆炸成功">1964年10月16日我国第一颗原子弹爆炸成功</a>(图)</li><li><ahref="/news6849/"title="1973年10月16日震撼世界的石油危机爆发">1973年10月16日震撼世界的石油危机爆发</a>(图)</li><li><ahref="/news6850/"title="1978年10月16日约翰·保罗二世当选新教皇">1978年10月16日约翰·保罗二世当选新教皇</a></li><li><ahref="/news6851/"title="1979年10月16日哈克将军宣布巴基斯坦推迟大选解散政党">1979年10月16日哈克将军宣布巴基斯坦推迟大选解散政党</a></li><li><ahref="/news6852/"title="1984年10月16日图图主教荣获“诺贝尔和平奖”">1984年10月16日图图主教荣获“诺贝尔和平奖”</a></li><li><ahref="/news6853/"title="1988年10月16日北京正负电子对撞机对撞成功">1988年10月16日北京正负电子对撞机对撞成功</a>(图)</li><li><ahref="/news6854/"title="1991年10月16日美国小镇枪杀案22人丧生">1991年10月16日美国小镇枪杀案22人丧生</a></li><li><ahref="/news6855/"title="1991年10月16日莫扎特死因有新说">1991年10月16日莫扎特死因有新说</a></li><li><ahref="/news6856/"title="1991年10月16日钱学森获“国家杰出贡献科学家”殊荣">1991年10月16日钱学森获“国家杰出贡献科学家”殊荣</a>(图)</li><li><ahref="/news6857/"title="1994年10月16日德国总理科尔四连任">1994年10月16日德国总理科尔四连任</a></li><li><ahref="/news6858/"title="1994年10月16日第十二届广岛亚运会闭幕">1994年10月16日第十二届广岛亚运会闭幕</a></li><li><ahref="/news6859/"title="1994年10月16日修秦陵制秦俑工匠墓葬被发现">1994年10月16日修秦陵制秦俑工匠墓葬被发现</a></li><li><ahref="/news6860/"title="1995年10月16日美国百万黑人男子大">1995年10月16日美国百万黑人男子大</a>(图)</li></ul>
可以看到,通过正则表达式抽取得到的m.group(3)中仍然有大量的html标签、空格、换行、无关字符等。我们要想办法把它们全部过滤掉,第83行代码的作用正是如此。


组装文本消息

  1. //组装文本消息(历史上的今天)
  2. TextMessagetextMessage=newTextMessage();
  3. textMessage.setToUserName(fromUserName);
  4. textMessage.setFromUserName(toUserName);
  5. textMessage.setCreateTime(newDate().getTime());
  6. textMessage.setMsgType(WeixinUtil.RESP_MESSAGE_TYPE_TEXT);
  7. textMessage.setFuncFlag(0);
  8. textMessage.setContent(TodayInHistoryService.getTodayInHistoryInfo());

对于公众帐号的消息回复在本系列教程的第5篇已经讲的很详细了,所以在这里笔者只是简单的组装了文本消息。最后,我们来看一下在微信公众帐号上的演示效果:



说明:与其说这是一篇关于公众帐号应用开发的教程,倒不如说这是一篇关于网页数据爬取的教程。本文旨在为读者开辟思路,介绍一种数据获取方式。当然,这种做法也是有弊端的,当网页改版源代码结构发生变化时,就需要重新改写数据抽取代码。没有做不到,只有想不到!


分享到:
评论

相关推荐

    微信公众帐号开发教程

    网络收集整理 ...[040] 微信公众帐号开发教程第16篇-应用实例之历史上的今天 - 柳峰的专栏 - 博客频道 - CSDN.NET [041] 微信公众帐号开发教程第17篇-应用实例之智能翻译 - 柳峰的专栏 - 博客频道 - CSDN.NET

    JAVA微信开发资料

    微信公众帐号开发教程第 16 篇-应用实例之历史上的今天.123 微信公众帐号开发教程第 17 篇-应用实例之智能翻译132 微信公众帐号开发教程第 18 篇-应用实例之音乐搜索140 微信公众平台开发教程第 19 篇-应用实例之...

    微信公众帐号开发教程第3篇-开发模式启用及接口配置

    微信公众帐号开发教程第3篇-开发模式启用及接口配置

    微信公共账号开发教程

    2. 微信公众帐号开发教程第2篇-微信公众帐号的类型(普通和会议) 3. 微信公众帐号开发教程第3篇-开发模式启用及接口配置 . 微信公众帐号开发教程第5篇-各种消息的接收与响应 6. 微信公众帐号开发教程第6篇-文本...

    微信开发实例 微信公众平台开发 之微信接口前期准备

    微信开发实例 微信公众平台开发教程-深入浅出微信公众平台实战开发(微网站、LBS云、Api接口调用、服务号高级接口)1.微信接口前期准备。由北风网提供,微信开发实例微信公众平台基础篇: 1)微信公众平台简介:开发...

    微信小程序开发图解案例教程-源代码

    微信小程序开发图解案例教程-源代码微信小程序开发图解案例教程-源代码微信小程序开发图解案例教程-源代码微信小程序开发图解案例教程-源代码微信小程序开发图解案例教程-源代码微信小程序开发图解案例教程-源代码...

    微信公众平台应用开发实战-完整扫描版 pdf 文档

    微信公众平台应用开发实战-完整扫描版.pdf 全书一共9章,在逻辑上分为四大部分:第一部分(第1章)介绍了微信公众平台的开发模式、数据交互方式,以及开发公众平台应用所需要的各项技术;第二部分(第2~4章)首先...

    java开发微信公众平台

    微信公众帐号开发教程第1 篇-引言 微信公众帐号开发教程第2 篇-微信公众帐号的类型(普通和会议) 微信公众帐号开发教程第3 篇-开发模式启用及接口配置 微信公众帐号开发教程第4 篇-消息及消息处理工具的封装 微信...

    微信公众平台开发入门教程

    微信公众平台开发入门教程

    微信公众账号开发教程

    接触微信公众帐号已经有两个多月的时间了,在这期间,除了陆续完善...所以,就有了写微信公众帐号开发教程的想法,将学习到的技术经验分享出来,帮助更多需要的朋友,也希望借此认识同行的朋友,共同交流,共同进步!

    微信公众平台开发教程,Java

    微信公众平台的开发教程,用Java写的,挺有借鉴的意义

    微信公众平台开发教程Java版

    微信公众平台开发教程Java版 微信公众平台开发教程Java版

    微信公众平台开发实例教程-源代码

    微信公众平台开发实例教程-源代码

    微信公众平台最佳实践-源代码-方倍工作室

    为了推出更好更有价值的作品,我们整合我们已有的教程资源并从2013年的100多个开发案例中挑选出最受欢迎的功能应用,重新编写了这本的微信公众平台开发教程。新教程中全面介绍微信公众平台包括微信支付在内的所有...

    微信公众平台开发教程之新手初级入门攻略 附PHP代码实例

    微信公众平台开发教程之新手初级入门攻略 附PHP代码实例

    微信公众平台开发教程4

    微信公众平台开发教程,适合初学者了解入门,用的是php语言,简单易懂,欢迎下载

    微信公众平台开发教程(含java代码)

    微信开发即微信公众平台开发,将企业信息、服务、活动等内容通过微信网页的方式进行表现,用户通过简单的设置,就能生成微信3G网站。通过微信公众平台将企业品牌展示给微信用户,减少宣传成本,建立企业与消费者、...

    微信公众账号开发教程(java)

    微信公众账号开发教程(java) 程主要是面向有一定Java编程基础的朋友 1)前沿知识:微信公众帐号的分类、两种模式各自的特点和区别、开发模式的配置使用等; 2)API中各类消息的使用(我已经对api进行封装并打成了jar...

Global site tag (gtag.js) - Google Analytics