之前写了一个关于抓所以取某个网站用户信息的程序,大量的用到了关于JSoup解析html的知识。并且其中也遇到了一些问题,这类问题在我们以后的开发过程中可能还有机会遇到,所以今天在这里对这块做个总结。
一.Jsoup如何根据url获得对应的网页Document文档
1.常见写法
doc=Jsoup.parse(new URL(url),4000);//参数2是连接超时设置,一旦超时则无法抓取到网页内容。以上是一种常见的写法,关于如何利用Jsoup获得Document文档,详细用法见http://www.jb51.net/article/43485.htm。
2.常见问题
(1)一般这样写获得Document文档是没有问题的,但也会遇到一些特殊情况。有些网站的网页数据必须要通过特定的post、Get请求方式才可以获取,如新华网的某个版块的首页必须要通过get方式才可以获取到数据。
doc=Jsoup.connect("http://forum.home.news.cn/list/50-133-0-1.html").timeout(3000).get();
(2)通过网页查看的源代码与通过程序返回的网页内容不一致,但这个问题是否出现取决于该网站是否设置了手机版和网页版2种代码返回方式,如何你在Document文档解析时发现,你解析语法明明没有任何错误,却依然无法得到解析出来的结果
doc=Jsoup.connect("http://forum.home.news.cn/list/50-133-0-ml")
.timeout(3000) //设置超时时间
.userAgent("Mozilla") //设置用户代理为MOZilla浏览器,强制使用网页版形式返回数据。
.cookie("auth","token") //设置cookie
.get(); //Get方式请求
二.如何解析DOM文档
Jsoup将html代码段变成DOM文档模型(其实就是树模型),再通过DOM模型遍历元素匹配要寻找的数据.下面我们通过具体事例来学习如何解析DOM文档。我们将获取http://forum.home.news.cn/list/50-0-0-1.html页面中的所有帖子链接并输出打印。
1.选择器语法:
DOM文档模型由包含元素、属性、属性值组成。
选择器一般语法形式为元素[属性=属性值]
如根据以下这段html片段解析出其中的图片的src属性值
<div class="n_logo">
<img src="http://baidu.com/logo.png"/>
</div>
语法形式为:
doc.select("div[class=n_logo]").first().select("img").first().attr("src")
其中对于含有class属性则可以简化为如下形式doc.select("div.n_logo").first().select("img").first().attr("src")
对于形如<div class="n_logo a b c">这样层级的div该如何定位呢?正确的语法规则如下:
doc.select("div.n_logo").select("a").select("div.b").select("div.c");
或者也可用doc.select(div[class=n_logo a b c])的形式(推荐使用)。
2.下面我们讲解几个比较常用的提取有用信息的语法:
(1)[attr^=value], [attr$=value], [attr*=value]
这三个语法分别代表,属性以 value 开头、结尾以及包含
(2)[attr~=regex]
使用正则表达式进行属性值的过滤,例如 img[src~=(?i)\.(png|jpe?g)]
以上对于提取特定元素比较有用.
选择器其他详细用法见http://www.cnblogs.com/huangjacky/archive/2011/03/08/1977721.html
3.常见问题:
会出现选择器语法没有问题,却无法正确解析出我们想要的数据.这个问题请参考上面常见问题(2)的解决方案。
4.代码实战:
详细代码如下:
import java.io.IOException; import java.util.ArrayList; import java.util.LinkedList; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.jsoup.Jsoup; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; public class xinhua { public static void main(String []args) throws IOException { parseTopicList("http://forum.home.news.cn/list/50-133-0-1.html"); } //一个版块单个页面的所有主题 public static ArrayList<String> parseTopicList(String url ) { System.out.println("***开始解析一个版块单页的所有主题***"); ArrayList<String>topicList=new ArrayList(); try { doc=Jsoup.connect(url) .userAgent("Mozilla") .cookie("auth", "token") .timeout(3000)</span> <span style="font-size:18px;"> .get(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } int size=doc.select("div.board-list-one").size(); String topicUrl=""; String title=""; String tid=""; Pattern tPattern=Pattern.compile("detail/([0-9]*)"); Matcher sMatcher; int index=0; for(Element ele : doc.select("dl[class=item]")){ if(ele.select("a").size()!=0){ topicUrl= "http://forum.home.news.cn"+ele.select("a").first().attr("href"); sMatcher=tPattern.matcher(topicUrl); if (sMatcher.find()) { tid=sMatcher.group(1); } title = ele.select("a").first().text(); index++; topicList.add(topicUrl); System.out.println("this is the "+index+" "+"--->"+topicUrl); } } System.out.println("***解析一个版块单页的所有主题完成***"); return topicList; } }
程序运行结果部分截图如下:
下面我们来看一下该发展版块该页的所有主题帖子部分截图如下:
对比一下,我们发现.我们可以正确的抓取到我们需要抓取的数据。
三.总结
Jsoup解析html这块知识点在编程场景下并不是经常遇到,所以没有必要深入的学习,用到3分,我们就学习5分就可以了。这点其实是很多初学者经常犯的错,总是想把某一类知识点全部弄清楚,其实完全没必要,只要你能利用文档解决问题就可以了。