在上一篇随笔《Java爬虫系列二:使用HttpClient抓取页面HTML》中介绍了怎么使用HttpClient进行爬虫的第一步--抓取页面html,今天接着来看下爬虫的第二步--解析抓取到的html。html
有请第二步的主角:Jsoup粉墨登场。下面咱们把舞台交给Jsoup,让他完成本文剩下的内容。java
============华丽的分割线=============node
1、Jsoup自我介绍jquery
你们好,我是Jsoup。程序员
我是一款Java 的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套很是省力的API,可经过DOM,CSS以及相似于jQuery的操做方法来取出和操做数据,用Java写爬虫的同行们十之八九用过我。为何呢?由于我在这个方面功能强大、使用方便。不信的话,能够继续往下看,代码是不会骗人的。apache
2、Jsoup解析html浏览器
上一篇中,HttpClient大哥已经抓取到了博客园首页的html,可是一堆的代码,不是程序员的人们怎么能看懂呢?这个就须要我这个html解析专家出场了。安全
下面经过案例展现如何使用Jsoup进行解析,案例中将获取博客园首页的标题和第一页的博客文章列表dom
请看代码(在上一篇代码的基础上进行操做,若是还不知道如何使用httpclient的朋友请跳转页面进行阅读):ide
<dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.12.1</version> </dependency>
接下来就能够开始代码了,Jsoup核心代码以下(总体源码会在文章末尾给出):
/** * 下面是Jsoup展示自个人平台 */ //6.Jsoup解析html Document document = Jsoup.parse(html); //像js同样,经过标签获取title System.out.println(document.getElementsByTag("title").first()); //像js同样,经过id 获取文章列表元素对象 Element postList = document.getElementById("post_list"); //像js同样,经过class 获取列表下的全部博客 Elements postItems = postList.getElementsByClass("post_item"); //循环处理每篇博客 for (Element postItem : postItems) { //像jquery选择器同样,获取文章标题元素 Elements titleEle = postItem.select(".post_item_body a[class='titlelnk']"); System.out.println("文章标题:" + titleEle.text());; System.out.println("文章地址:" + titleEle.attr("href")); //像jquery选择器同样,获取文章做者元素 Elements footEle = postItem.select(".post_item_foot a[class='lightblue']"); System.out.println("文章做者:" + footEle.text());; System.out.println("做者主页:" + footEle.attr("href")); System.out.println("*********************************"); }
根据以上代码你会发现,我经过Jsoup.parse(String html)方法对httpclient获取到的html内容进行解析获取到Document,而后document能够有两种方式获取其子元素:像js同样 能够经过getElementXXXX的方式 和 像jquery 选择器同样经过select()方法。 不管哪一种方法均可以,我我的推荐用select方法处理。对于元素中的属性,好比超连接地址,可使用element.attr(String)方法获取, 对于元素的文本内容经过element.text()方法获取。
因为新文章发布的太快了,致使上面的截图和这里的输出有些不同。
3、Jsoup的其余用法
我,Jsoup,除了能够在httpclient大哥的工做成果上发挥做用,我还能本身独立干活,本身抓取页面,而后本身分析。分析的本领已经在上面展现过了,下面来展现本身抓取页面,其实很简单,所不一样的是我直接获取到的是document,不用再经过Jsoup.parse()方法进行解析了。
除了能直接访问网上的资源,我还能解析本地资源:
代码:
public static void main(String[] args) { try { Document document = Jsoup.parse(new File("d://1.html"), "utf-8"); System.out.println(document); } catch (IOException e) { e.printStackTrace(); } }
4、Jsoup另外一个值得一提的功能
你确定有过这种经历,在你的页面文本框中,若是输入html元素的话,保存后再查看很大几率会致使页面排版乱七八糟,若是能对这些内容进行过滤的话,就完美了。
恰好我Jsoup就能作到。
public static void main(String[] args) { String unsafe = "<p><a href='网址' onclick='stealCookies()'>博客园</a></p>"; System.out.println("unsafe: " + unsafe); String safe = Jsoup.clean(unsafe, Whitelist.basic()); System.out.println("safe: " + safe); }
经过Jsoup.clean方法,用一个白名单进行过滤。执行结果:
unsafe: <p><a href='网址' onclick='stealCookies()'>博客园</a></p>
safe: <p><a rel="nofollow">博客园</a></p>
5、结束语
经过以上你们相信我很强大了吧,不只能够解析HttpClient抓取到的html元素,我本身也能抓取页面dom,我还能load并解析本地保存的html文件。
此外,我还能经过一个白名单对字符串进行过滤,筛掉一些不安全的字符。
最最重要的,上面全部功能的API的调用都比较简单。
============华丽的分割线=============
码字不易,点个赞再走呗~~
最后,附上案例中 解析博客园首页文章列表的完整源码:
package httpclient_learn; import java.io.IOException; import org.apache.http.HttpEntity; import org.apache.http.HttpStatus; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.utils.HttpClientUtils; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; public class HttpClientTest { public static void main(String[] args) { //1.生成httpclient,至关于该打开一个浏览器 CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpResponse response = null; //2.建立get请求,至关于在浏览器地址栏输入 网址 HttpGet request = new HttpGet("https://www.cnblogs.com/"); //设置请求头,将爬虫假装成浏览器 request.setHeader("User-Agent","Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36"); // HttpHost proxy = new HttpHost("60.13.42.232", 9999); // RequestConfig config = RequestConfig.custom().setProxy(proxy).build(); // request.setConfig(config); try { //3.执行get请求,至关于在输入地址栏后敲回车键 response = httpClient.execute(request); //4.判断响应状态为200,进行处理 if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { //5.获取响应内容 HttpEntity httpEntity = response.getEntity(); String html = EntityUtils.toString(httpEntity, "utf-8"); System.out.println(html); /** * 下面是Jsoup展示自个人平台 */ //6.Jsoup解析html Document document = Jsoup.parse(html); //像js同样,经过标签获取title System.out.println(document.getElementsByTag("title").first()); //像js同样,经过id 获取文章列表元素对象 Element postList = document.getElementById("post_list"); //像js同样,经过class 获取列表下的全部博客 Elements postItems = postList.getElementsByClass("post_item"); //循环处理每篇博客 for (Element postItem : postItems) { //像jquery选择器同样,获取文章标题元素 Elements titleEle = postItem.select(".post_item_body a[class='titlelnk']"); System.out.println("文章标题:" + titleEle.text());; System.out.println("文章地址:" + titleEle.attr("href")); //像jquery选择器同样,获取文章做者元素 Elements footEle = postItem.select(".post_item_foot a[class='lightblue']"); System.out.println("文章做者:" + footEle.text());; System.out.println("做者主页:" + footEle.attr("href")); System.out.println("*********************************"); } } else { //若是返回状态不是200,好比404(页面不存在)等,根据状况作处理,这里略 System.out.println("返回状态不是200"); System.out.println(EntityUtils.toString(response.getEntity(), "utf-8")); } } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { //6.关闭 HttpClientUtils.closeQuietly(response); HttpClientUtils.closeQuietly(httpClient); } } }