您的位置:首页 > 编程语言 > Java开发

java爬取网页内容 简单例子

2015-08-19 11:26 751 查看


java爬取网页内容 简单例子(1)——使用正则表达式

【本文介绍】  
爬取别人网页上的内容,听上似乎很有趣的样子,只要几步,就可以获取到力所不能及的东西,例如呢?例如天气预报,总不能自己拿着仪器去测吧!当然,要获取天气预报还是用webService好。这里只是举个例子。话不多说了,上看看效果吧。
【效果】
我们随便找个天气预报的网站来试试:http://www.weather.com.cn/html/weather/101280101.shtml
从图中可用看出,今天(6日)的天气。我们就以这个为例,获取今天的天气吧!



最终后台打印出:

今天:6日
天气:雷阵雨
温度:26°~34°
风力:微风


【思路】

1、通过url获取输入流————2、获取网页html代码————3、用正则表达式抽取有用的信息————4、拼装成想要的格式


其实最难的一点事第3点,如果正则表示式不熟,基本上在这一步就会挂掉了——例如我T_T。下面为了抽取到正确的数据,我匹配了多次,如果能一次匹配的话,那代码量就少多了!
【代码】



1 package com.zjm.www.test;
2
3 import java.io.BufferedReader;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.io.InputStreamReader;
7 import java.net.HttpURLConnection;
8 import java.net.URL;
9 import java.util.regex.Matcher;
10 import java.util.regex.Pattern;
11
12 /**
13  * 描述:趴取网页上的今天的天气
14  * @author     zjm
15  * @time     2014/8/6
16  */
17 public class TodayTemperatureService {
18
19      /**
20      * 发起http get请求获取网页源代码
21      * @param requestUrl     String    请求地址
22      * @return                 String    该地址返回的html字符串
23      */
24     private static String httpRequest(String requestUrl) {
25
26         StringBuffer buffer = null;
27         BufferedReader bufferedReader = null;
28         InputStreamReader inputStreamReader = null;
29         InputStream inputStream = null;
30         HttpURLConnection httpUrlConn = null;
31
32         try {
33             // 建立get请求
34             URL url = new URL(requestUrl);
35             httpUrlConn = (HttpURLConnection) url.openConnection();
36             httpUrlConn.setDoInput(true);
37             httpUrlConn.setRequestMethod("GET");
38
39             // 获取输入流
40             inputStream = httpUrlConn.getInputStream();
41             inputStreamReader = new InputStreamReader(inputStream, "utf-8");
42             bufferedReader = new BufferedReader(inputStreamReader);
43
44             // 从输入流读取结果
45             buffer = new StringBuffer();
46             String str = null;
47             while ((str = bufferedReader.readLine()) != null) {
48                 buffer.append(str);
49             }
50
51         } catch (Exception e) {
52             e.printStackTrace();
53         }  finally {
54             // 释放资源
55             if(bufferedReader != null) {
56                 try {
57                     bufferedReader.close();
58                 } catch (IOException e) {
59                     e.printStackTrace();
60                 }
61             }
62             if(inputStreamReader != null){
63                 try {
64                     inputStreamReader.close();
65                 } catch (IOException e) {
66                     e.printStackTrace();
67                 }
68             }
69             if(inputStream != null){
70                 try {
71                     inputStream.close();
72                 } catch (IOException e) {
73                     e.printStackTrace();
74                 }
75             }
76             if(httpUrlConn != null){
77                 httpUrlConn.disconnect();
78             }
79         }
80         return buffer.toString();
81     }
82
83     /**
84      * 过滤掉html字符串中无用的信息
85      * @param html    String    html字符串
86      * @return         String    有用的数据
87      */
88     private static String htmlFiter(String html) {
89
90         StringBuffer buffer = new StringBuffer();
91         String str1 = "";
92         String str2 = "";
93         buffer.append("今天:");
94
95         // 取出有用的范围
96         Pattern p = Pattern.compile("(.*)(<li class=\'dn on\' data-dn=\'7d1\'>)(.*?)(</li>)(.*)");
97         Matcher m = p.matcher(html);
98         if (m.matches()) {
99             str1 = m.group(3);
100             // 匹配日期,注:日期被包含在<h2> 和 </h2>中
101             p = Pattern.compile("(.*)(<h2>)(.*?)(</h2>)(.*)");
102             m = p.matcher(str1);
103             if(m.matches()){
104                 str2 = m.group(3);
105                 buffer.append(str2);
106                 buffer.append("\n天气:");
107             }
108             // 匹配天气,注:天气被包含在<p class="wea" title="..."> 和 </p>中
109             p = Pattern.compile("(.*)(<p class=\"wea\" title=)(.*?)(>)(.*?)(</p>)(.*)");
110             m = p.matcher(str1);
111             if(m.matches()){
112                 str2 = m.group(5);
113                 buffer.append(str2);
114                 buffer.append("\n温度:");
115             }
116             // 匹配温度,注:温度被包含在<p class=\"tem tem2\"> <span> 和 </span><i>中
117             p = Pattern.compile("(.*)(<p class=\"tem tem2\"> <span>)(.*?)(</span><i>)(.*)");
118             m = p.matcher(str1);
119             if(m.matches()){
120                 str2 = m.group(3);
121                 buffer.append(str2);
122                 buffer.append("°~");
123             }
124             p = Pattern.compile("(.*)(<p class=\"tem tem1\"> <span>)(.*?)(</span><i>)(.*)");
125             m = p.matcher(str1);
126             if(m.matches()){
127                 str2 = m.group(3);
128                 buffer.append(str2);
129                 buffer.append("°\n风力:");
130             }
131             // 匹配风,注:<i> 和 </i> 中
132             p = Pattern.compile("(.*)(<i>)(.*?)(</i>)(.*)");
133             m = p.matcher(str1);
134             if(m.matches()){
135                 str2 = m.group(3);
136                 buffer.append(str2);
137             }
138         }
139         return buffer.toString();
140     }
141
142     /**
143      *  对以上两个方法进行封装。
144      * @return
145      */
146     public static String getTodayTemperatureInfo() {
147         // 调用第一个方法,获取html字符串
148         String html = httpRequest("http://www.weather.com.cn/html/weather/101280101.shtml");
149         // 调用第二个方法,过滤掉无用的信息
150         String result = htmlFiter(html);
151
152         return result;
153     }
154
155     /**
156      * 测试
157      * @param args
158      */
159     public static void main(String[] args) {
160         String info = getTodayTemperatureInfo();
161         System.out.println(info);
162     }
163 }


【详解】
34-49行:通过url获取网页的源码,没什么好说的。
96行:在网页上按F12,查看"今天"的html代码,发现如下图,所以我们第一步就是要过滤掉除这一段html代码外的东西。
  (.*)(<li class=\'dn on\' data-dn=\'7d1\'>)(.*?)(</li>)(.*) 这个正则表达式,很容易看出可以分为下面5组:
  (.*)                        :匹配除换行符外任意东西0-N次
  (<li class=\'dn on\' data-dn=\'7d1\'>)    :匹配中间那段heml代码一次
  (.*?)                        : .*?为匹配的懒惰模式,意思是匹配除换行符外任意东西尽可能少次
  (</li>)                       :匹配中间那段html代码一次
  (.*)                       :匹配除换行符外任意东西0-N次
  这样,我们就可用m.group(3)拿到匹配中间(.*?)的那一串代码了。即我们需要的“今天”的天气的代码。



101行:中间那一段代码拿出来后如下图所示、还有很多无用的标签。我们要想办法继续除去。方法同上。



106行:手动拼接上我们需要的字符串。

经过以上的处理,就完成了一个简单的爬取啦。
中间正则表达式部分最不满意,各路网友如果有好的建议麻烦留下宝贵的评论,感激不尽~

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


java爬取网页内容 简单例子(2)——附jsoup的select用法详解

【背景】
  在上一篇博文 java爬取网页内容 简单例子(1)——使用正则表达式 里面,介绍了如何使用正则表达式去解析网页的内容,虽然该正则表达式比较通用,但繁琐,代码量多,现实中想要想出一条简单的正则表达式
对于没有很好正则表达式基础的人——比如说我T_T——是一件蛮困难的事。这一篇,我们改用jsoup,一个强大的解析html工具,去解析html,你会发现,一切都变得很容易。

【准备工作】
下载:jsoup-1.6.1.jar

【先看效果】
目标网站:中国天气
目的:获取今天的天气
目标HTML代码:



<li class="dn on" data-dn="7d1">
<h1>今天</h1>
<h2>8日</h2>
<big class="jpg50 d04"></big>
<big class="jpg50 n04"></big>
<p class="wea" title="雷阵雨">雷阵雨</p>
<p class="tem tem1"> <span>33</span><i>°C</i> </p>
<p class="tem tem2"> <span>25</span><i>°C</i> </p>
<p class="win">
<em>
<span title="无持续风向" class=""></span>
<span title="无持续风向" class=""></span>
</em>
<i>微风</i>
</p>
<div class="slid"></div>
</li>


解析的java代码:
(1)审查网页元素后发现,我们要的内容在上面的目标HTML代码中,在整个网页中是在 class="dn on" data-dn="7d1" 的<li>中
(2)“今天” 两字在<h1></h1>中
(3)“8日” 两字在<h2></h2>中
(4)“雷阵雨” 三字在 class="wea" 中
(5)“33” 在第一个<span>中
(6)“25” 在第二个<span>中
(7)“微风” 两字在 第三个<i> 中
有了上面的分析,要获取到这些天气内容就易如反掌了。如下java代码:



1 package com.zjm.www.test;
2
3 import java.io.IOException;
4
5 import org.jsoup.Jsoup;
6 import org.jsoup.nodes.Document;
7 import org.jsoup.select.Elements;
8
9 public class TestJsoup {
10
11     public  Document getDocument (String url){
12         try {
13             return Jsoup.connect(url).get();
14         } catch (IOException e) {
15             e.printStackTrace();
16         }
17         return null;
18     }
19
20     public static void main(String[] args) {
21         TestJsoup t = new TestJsoup();
22         Document doc = t.getDocument("http://www.weather.com.cn/html/weather/101280101.shtml");
23         // 获取目标HTML代码
24         Elements elements1 = doc.select("[class=dn on][data-dn=7d1]");
25         // 今天
26         Elements elements2 = elements1.select("h1");
27         String today = elements2.get(0).text();
28         System.out.println(today);
29         // 几号
30         Elements elements3 = elements1.select("h2");
31         String number = elements3.get(0).text();
32         System.out.println(number);
33         // 是否有雨
34         Elements elements4 = elements1.select("[class=wea]");
35         String rain = elements4.get(0).text();
36         System.out.println(rain);
37         // 高的温度
38         Elements elements5 = elements1.select("span");
39         String highTemperature = elements5.get(0).text()+"°C";
40         System.out.println(highTemperature);
41         // 低的温度
42         String lowTemperature = elements5.get(1).text()+"°C";
43         System.out.println(lowTemperature);
44         // 风力
45         Elements elements6 = elements1.select("i");
46         String wind = elements6.get(2).text();
47         System.out.println(wind);
48     }
49 }


结果打印出:

1 今天
2 8日
3 雷阵雨
4 33°C
5 25°C
6 微风


【详解】
附:

jsoup的官方中文文档为:http://www.open-open.com/
API为:http://jsoup.org/apidocs/

java代码第13行:
  从文档中我们可用看出,获取数据源的方法有三:
(1)从一段html代码字符串获取:  
Document doc = Jsoup.parse(html);

(2)从一个url获取:        
Document doc = Jsoup.connect("http://example.com/").get();

(3)从一个html文件获取      
File input = new File("/tmp/input.html");
Document
doc = Jsoup.parse(input, "UTF-8", "http://example.com/");

这里,我们采取了第二种方法,从url中获取。
java代码第24、26、30、34、38行:
  Document 继承自 Element 类, 而Element类有一个很好的方法,叫select , 这个选择器几乎无所不能。快速从一堆html代码中获取我们想要的一段,我觉得使用select最方便。下面我们来看怎么使用select方法来查找。
注:以下表格的结果都是使用以下语句打印出来的

for(Element e : elements) {
System.out.println(e.text());
}


select详解
描述测试的HTML代码select写法结果
通过
标签名
来查找
<span>33</span>
<span>25</span>


Elements elements = doc.select("span");


注:通过标签来查找,直接写 "标签名" 就好,不需要尖括号。
33
25


通过
id
来查找
<span  id=\"mySpan\">36</span>

<span>20</span>


Elements elements = doc.select("#mySpan");


注:通过id来查找,使用方法跟css指定元素一样,用#
36


通过
class名
来查找
<span class=\"myClass\">36</span>
<span>20</span>


Elements elements = doc.select(".myClass");


注:通过id来查找,使用方法跟css指定元素一样,用 .
36


利用标签内
属性名
查找元素
<span class=\"class1\" id=\"id1\">36</span>
<span class=\"class2\" id=\"id2\">36</span>


Elements elements = doc.select("span[class=class1]span[id=id1]");


注:规则为 标签名【属性名=属性值】,标签名可写可不写,多个属性即多个【】,如上。
36


利用标签内
属性名前缀
查找元素
<span class=\"class1\" >36</span>
<span class=\"class2\" >22</span>


Elements elements = doc.select("span[^cl]");


注:规则为 标签名【^属性名前缀】,标签名可写可不写,多个属性即多个【】。
36
22


利用标签内
属性名+正则表达式
查找元素
<span class=\"ABC\" >36</span>
<span class=\"ADE\" >22</span>


Elements elements = doc.select("span[class~=^AB]");


注:规则为 标签名【属性名~=正则表达式】,以上的正则表达式的意思是查找以class值以AB为开头的标签,标签名可写可不写,多个属性即多个【】
36


利用标签
文本包含某些内容
来查找
<span>36</span>
<span>22</span>


Elements elements = doc.select("span:contains(3)");


注:规则为 标签名:contains(文本值)
36


利用标签
文本包含某些内容+正则表达式
来查找
<span>36</span>
<span>22</span>


Elements elements = doc.select("span:matchesOwn(^3)");


注:规则为 标签名:matchesOwn(正则表达式),以上的正则表式的意思是以文本值以3为开头的标签
36


关于select,还有一些其他的查找方法,以上只列出个人觉得比较好用、常用的语法。
select方法返回的是一个Elements 对象,里面包含着找到的所有节点。遍历Elements ,通过get(index),就可以拿出具体的 节点了。通过节点的text()方法,就可用拿出文本值。
而想得到节点的其他属性,可以看API的介绍。

【结语】
jsoup还有其他强大的功能,在此只介绍其在获取网页特定内容的写法。希望对刚接触jsoup的人有帮助。
如果本文有哪里写得不好或写错,欢迎各位提出来,感激不尽~

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: