最近做的一个项目中,其中有这样一个需求:用户要求我们实时在地图上显示某些指定景点的人数,但是却没有给我们数据的接口。不过可以从网页上获取到最新的数据,每小时更新一次。所以经理安排我做一个实时从网页上抓取数据的功能。
既然是网页,那么无用的数据肯定是非常多的,所以就需要用正则表达式来过滤出自己所需要的数据。
不得不说,正则表达式比substring好用多了,而且效率也很不错。下面来分享一下我的这段代码吧:
/** * 从网站获取日期信息 * * @Title: getDate * @Date : 2014-8-12 上午09:42:26 * @return */ private String getDate() { // 从网站抓取数据 String table = catchData(); String date = ""; // 使用正则表达式,获取对应的数据 Pattern places = Pattern.compile("(<p align=\"center\">)([^\\s]*)"); Matcher matcher = places.matcher(table); while (matcher.find()) { System.out.println(matcher.group(2)); date = matcher.group(2); } return date; } /** * 从网站抓取数据(未经处理) * * @Title: getData * @Date : 2014-8-12 上午09:34:30 * @return */ @SuppressWarnings("unchecked") private String catchData() { String table = ""; try { Map map = new HashMap(); map.put("a", "1");// 莫删,否则报错 table = AsyncRequestUtil.getJsonResult(map, "http://s.visitbeijing.com.cn/flow.php"); } catch (Exception e) { e.printStackTrace(); } return table; }
【AsyncRequestUtil.java】
package com.zhjy.zydc.util; import java.util.Map; /** * 异步请求数据 * @author : Cuichenglong * @group : tgb * @Version : 1.00 * @Date : 2014-5-28 上午09:54:20 */ public class AsyncRequestUtil { /** * 异步请求数据 * @Title: getJsonResult * @param map * @param strURL * @return */ public static String getJsonResult(Map<String, Object> map, String strURL)throws Exception { /** 跨域登录,获取返回结果 **/ String result = null; result = UrlUtil.getDataFromURL(strURL, map); if (result!=null && result.startsWith("null{")) { result = result.substring("null".length()); } return result; } }【 UrlUtil .java 】
package com.zhjy.zydc.util; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.net.URL; import java.net.URLConnection; import java.net.URLDecoder; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; /** * url跨域获取数据 * @author : Cuichenglong * @group : Zhong Hai Ji Yuan * @Version : 1.00 * @Date : 2014-5-27 下午04:14:26 */ public final class UrlUtil { /** * 根据URL跨域获取输出结果 * @Title: getDataFromURL * @param strURL 要访问的URL地址 * @param param 参数 * @return 结果字符串 * @throws Exception */ public static String getDataFromURL(String strURL, Map<String, Object> param) throws Exception{ URL url = new URL(strURL); URLConnection conn = url.openConnection(); conn.setDoOutput(true); conn.setConnectTimeout(5000); //允许5秒钟的延迟:连接主机的超时时间(单位:毫秒) conn.setReadTimeout(5000); //允许5秒钟的延迟 :从主机读取数据的超时时间(单位:毫秒) OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream()); final StringBuilder sb = new StringBuilder(param.size() << 4); // 4次方 final Set<String> keys = param.keySet(); for (final String key : keys) { Object value = param.get(key); sb.append(key); // 不能包含特殊字符 sb.append('='); //如果格式为String类型,则进行2次解码、2次编码操作 if (value instanceof String) // String { // value = (URLDecoder.decode(URLDecoder.decode((String)value, "utf-8"), // "utf-8")); // value = (Object)(URLEncoder.encode(URLEncoder.encode((String)value, "utf-8"), // "utf-8")); value = URLEncoder.encode((String)value, "utf-8"); } sb.append(value); sb.append('&'); } // 将最后的 '&' 去掉 sb.deleteCharAt(sb.length() - 1); // writer.write("email=pk3589@163.com&password=123"); writer.write(sb.toString()); writer.flush(); writer.close(); InputStreamReader reder = new InputStreamReader(conn.getInputStream(), "utf-8"); BufferedReader breader = new BufferedReader(reder); // BufferedWriter w = new BufferedWriter(new FileWriter("d:/1.txt")); String content = null; String result = null; while ((content = breader.readLine()) != null) { result += content; } return result; } }这是一段很简单的代码。是从http://s.visitbeijing.com.cn/flow.php网址中抓取日期的代码。
其实只有2步,第一步是通过java.net.URL后台访问指定网址,并且拿到页面的html源码。第二步从html源码中通过正则表达式,获取日期。这里说一下正则表达式:
Pattern places = Pattern.compile("(<p align=\"center\">)([^\\s]*)");
其中^表示屏蔽,\s表示空格,所以^\\s表示屏蔽空格,这里第一个\是转移字符。*表示匹配多个字符。
通过matcher,获取匹配的值。在一次matcher.find()获取每一次匹配的数据,一个括号对应一个group。如果取matcher.group(1),则会取到<p align="center">。matcher.group(2)可以取到匹配的值。
了解了这些,我们就可以随意的从某些网址上抓取数据了。有了数据,还有什么可以挡住我们前进的脚步!!!