- 需求:查找四川大学所有学院的网站的网址中的通知和新闻——以计算机学院为例
- 流程图
3. 具体步骤
(1) 学院的主页为:http://cs.scu.edu.cn/ 获取该页面的所有内容(本文只获取新闻的具体内容,通知的只需要更改下正则表达式)
1 /** 2 * 获取要抓取页面的所有内容 3 * @param url 网页地址 4 * @return 5 */ 6 public static String sendGet(String url) { 7 8 BufferedReader in = null; 9 String result = ""; 10 // 通过HttpClientBuilder创建HttpClient 11 HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(); 12 CloseableHttpClient client = httpClientBuilder.build(); 13 14 HttpGet httpGet = new HttpGet(url); 15 // 设置请求和传输超时时间 16 RequestConfig requestConfig = RequestConfig.custom() 17 .setConnectTimeout(5000).build(); 18 httpGet.setConfig(requestConfig); 19 20 System.out.println(httpGet.getRequestLine()); 21 22 try { 23 HttpResponse httpResponse = client.execute(httpGet); 24 25 int statusCode = httpResponse.getStatusLine().getStatusCode(); 26 27 // 响应状态 28 System.out.println("status:" + statusCode); 29 if (statusCode == HttpStatus.SC_OK) { 30 // 获取响应的消息实体 31 HttpEntity entity = httpResponse.getEntity(); 32 33 // 判断实体是否为空 34 if (entity != null) { 35 System.out.println("contentEncoding:" 36 + entity.getContentLength()); 37 38 in = new BufferedReader(new InputStreamReader( 39 entity.getContent(), "GBK")); 40 41 String line; 42 while ((line = in.readLine()) != null) { 43 // 遍历抓取到的每一行并将其存储到result里面 44 result += line; 45 } 46 } 47 } 48 } catch (Exception e) { 49 50 e.printStackTrace(); 51 } finally { 52 try { 53 client.close(); 54 if (in != null) { 55 in.close(); 56 } 57 } catch (Exception e2) { 58 e2.printStackTrace(); 59 } 60 } 61 return result; 62 }
(2) 使用正则表达式提取通知页面和新闻页面的地址
指向新闻页的地址源码为:<MAP name=Map3><AREA shape=RECT target=_blank coords=498,27,539,37 href="/cs/xyxw/H9501index_1.htm">
所以正则表达式为:coords=498,27,539,37 href="(.+?)">
指向通知页的地址源码为:<MAP name=Map6><AREA shape=RECT target=_blank coords=498,11,538,23 href="/cs/xytz/H9502index_1.htm"></MAP>
所以正则表达式可以为:coords=498,11,538,23 href="(.+?)">
1 /** 2 * 查找主页中的新闻和通知的URL 3 * @param context 主页内容 4 * @param type 查找类型 5 * @return 6 */ 7 public static String getURL(String context, int type) { 8 9 Pattern pattern; 10 Matcher matcher; 11 12 if (type == 0) {// 当type=0时,查找新闻 13 // 创建Pattern对象 14 pattern = Pattern.compile("coords=498,27,539,37 href="(.+?)">"); 15 // 创建Matcher对象,并匹配 16 matcher = pattern.matcher(context); 17 18 if (matcher.find()) {// 查看是否找到,找到返回 19 return "http://cs.scu.edu.cn" + matcher.group(1); 20 } 21 } else if (type == 1) {// 当type=1时,查找通知 22 pattern = Pattern.compile("coords=498,11,538,23 href="(.+?)">"); 23 matcher = pattern.matcher(context); 24 if (matcher.find()) { 25 return "http://cs.scu.edu.cn" + matcher.group(1); 26 } 27 } else { 28 return "输入的type不正确"; 29 } 31 return null; 32 }
得到新闻和通知地址:
a) 新闻页面地址为 http://cs.scu.edu.cn/cs/xyxw/H9501index_1.htm
b) 通知页面地址为 http://cs.scu.edu.cn/cs/xytz/H9502index_1.htm
(3)获取所有新闻的URL:(以新闻为例)
新闻的具体内容的地址在源码中的表示:
<A href=/cs/xyxw/webinfo/2016/06/1466645005004306.htm target=_blank>计算机学院(软件学院)第三届第六次双代会圆满举行</A></TD></TD><TD><DIV align=right><FONT size=2>[2016-06-30]
所以正则匹配表达式为:<A href=/cs/xyxw/webinfo(.+?) target=_blank>
1 /** 2 * 查询具体新闻所在页面的所有URL 3 * @param url 4 * @return 5 */ 6 public static List<String> getRealURL(String url) { 7 8 // 存储URL地址 9 List<String> list = new ArrayList<>(); 10 // 获取的主页内容 11 String context = sendGet(url); 12 System.out.println(context); 13 // 匹配新闻地址的正则表达式 14 Pattern pattern = Pattern 15 .compile("<A href=/cs/xyxw/webinfo(.+?) target=_blank>"); 16 Matcher matcher = pattern.matcher(context); 17 18 // 匹配url中的数字2(2表示页数,可以通过观察地址得出) : 19 // http://cs.scu.edu.cn/cs/xyxw/H9501index_2.htm 20 // http://cs.scu.edu.cn/cs/xyxw/H9501index_3.htm 21 Pattern patternNext = Pattern.compile("index_(.+?).htm"); 22 Matcher matcherNext = patternNext.matcher(url); 23 24 int i = 0; 25 if (matcherNext.find()) { 26 System.out.println(matcherNext.group(1)); 27 // 设置i为当前页数 28 i = Integer.parseInt(matcherNext.group(1)); 29 } 30 31 boolean isFind = matcher.find(); 32 33 while (isFind) { 34 while (isFind) {// 遍历当前页的所有新闻的URL 35 // 将获取的URL存储到list中 36 list.add("http://cs.scu.edu.cn/cs/xyxw/webinfo" 37 + matcher.group(1)); 38 isFind = matcher.find(); 39 } 40 41 i++; 42 // 下一页地址 43 String nextUrl = "http://cs.scu.edu.cn/cs/xyxw/H9501index_" + i + ".htm"; 44 context = sendGet(nextUrl); 45 // 匹配新页面 46 matcher = pattern.matcher(context); 47 isFind = matcher.find(); 48 } 49 return list; 50 }
得到结果:
(4)获取具体新闻页的信息:
a)使用封装类:
1 package com.huang.domain; 2 3 import java.util.Date; 4 5 public class Message { 6 7 private String type; //类型是新闻还是通知 8 9 private String title; //信息标题 10 11 private Date date; //信息发布时间 12 13 private String pic; //相关图片 14 15 private String context; //具体信息内容 16 17 public String getPic() { 18 return pic; 19 } 20 public void setPic(String pic) { 21 this.pic = pic; 22 } 23 24 public String getTitle() { 25 return title; 26 } 27 public void setTitle(String title) { 28 this.title = title; 29 } 30 public String getContext() { 31 return context; 32 } 33 public void setContext(String context) { 34 this.context = context; 35 } 36 public Date getDate() { 37 return date; 38 } 39 public void setDate(Date date) { 40 this.date = date; 41 } 42 public String getType() { 43 return type; 44 } 45 public void setType(String type) { 46 this.type = type; 47 } 48 @Override 49 public String toString() { 50 return "Message [title=" + title + ", date=" + date + ", pic=" + pic 51 + ", context=" + context + "]"; 52 } 56 }
(b)获取新闻具体页的信息:
1 /** 2 * 获取所有新闻页和通知页具体信息 3 * @param listUrl 4 * @return 5 */ 6 public static List<Message> getAllInformation(List<String> listUrl) { 7 8 Pattern pattern; 9 Matcher matcher; 10 // 存储查到的每条新闻 11 List<Message> list = new ArrayList<>(); 12 13 // 根据前面获取的所有页面的url,遍历所有的信息主页,获取相关信息 14 for (String url : listUrl) { 15 16 Message message = new Message(); 17 // 获取当页信息的全部信息 18 String context = sendGet(url); 19 // 获取标题 20 pattern = Pattern.compile("<DIV align=center> (.+?)</DIV>"); 21 matcher = pattern.matcher(context); 22 if (matcher.find()) {// 设置标题 23 message.setTitle(matcher.group(1)); 24 } 25 // 获取日期 26 pattern = Pattern.compile("</SPAN> ([0-9].+?)<SPAN class=hangjc " 27 + "style="LINE-HEIGHT: 30px" valign="bottom">"); 28 matcher = pattern.matcher(context); 29 if (matcher.find()) {// 设置日期 30 SimpleDateFormat format = new SimpleDateFormat( 31 "yyyy-MM-dd HH:mm");//设置日期格式 32 try { 33 //将字符串转换成date类型 34 Date date = format.parse(matcher.group(1)); 35 message.setDate(date); 36 } catch (ParseException e) { 37 System.out.println("日期格式不正确"); 38 e.printStackTrace(); 39 } 40 } 41 //获取图片 42 pattern = Pattern.compile("align=center src="(.+?).jpg""); 43 matcher = pattern.matcher(context); 44 if (matcher.find()) {//设置图片 45 message.setPic("http://cs.scu.edu.cn/" + matcher.group(1) 46 + ".jpg"); 47 } 48 //获取内容 49 pattern = Pattern.compile("<DIV id=BodyLabel>.+?</DIV>"); 50 matcher = pattern.matcher(context); 51 if (matcher.find()) {//设置内容 52 String result = matcher.group(0); 53 //过滤一些内容中的标签 54 result = result.replaceAll(" ", " "); 55 result = result.replaceAll("<br>", " "); 56 result = result.replaceAll("<.*?>", ""); 57 message.setContext(result); 58 } 59 //将查询到的新闻添加到list中 60 list.add(message); 61 } 62 return list; 63 }
(5)测试代码:
1 public static void main(String[] args) { 2 //获取计算机学院主页中的所有信息 3 String context = Spider.sendGet("http://cs.scu.edu.cn/"); 4 System.out.println(context); 5 //获取新闻所在页的地址 6 String newsUrl = Spider.getURL(context, 0); 7 //查找每个新闻的地址 8 List<String> listUrl = Spider.getRealURL(newsUrl); 9 System.out.println(listUrl); 10 //查到出每个新闻的内容 11 List<Message> messages = Spider.getAllInformation(listUrl); 12 13 System.out.println(messages); 14 15 }
(java正则知识可以参考:http://www.runoob.com/java/java-regular-expressions.html)