[置顶] 使用Jsoup解析网页

时间:2022-11-01 09:31:42


之前已经发表过一篇使用HtmlParser类来解析视频网站的教程

http://blog.csdn.net/gfd54gd5f46/article/details/54960538


我发现htmlparser类太旧了,而且用起来语法也不清晰。

所以我又找来一个更强大的解析网页的工具类:Jsoup 来帮助我们制作更强大的网络爬虫


下载Jsoup类


      jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。


Jar包地址:

http://jsoup.org/packages/jsoup-1.8.1.jar

构建Maven项目自动下载jar包:

http://blog.csdn.net/gfd54gd5f46/article/details/54973954

Jsoup在线API文档:

http://tool.oschina.net/apidocs/apidoc?api=jsoup-1.6.3

Jsoup开发指南:

http://www.open-open.com/jsoup/attributes-text-html.htm

解析网页


我这里就找一个图片网站来进行测试

http://www.nipic.com/index.html


1、获取单张图片的下载地址

  • 随便点击一张首页的图片

[置顶]        使用Jsoup解析网页



进去之后我们发现这个页面只是图片的列表,我们要获取的是单个图片的地址,所以还需要点击进去查找

[置顶]        使用Jsoup解析网页



点击第一张图片,查看到了单张图片

[置顶]        使用Jsoup解析网页



同样,我们要对这个页面进行分析,找到规律来获取这张图片的地址链接

F12进入调试页面

(调试页地址:http://www.nipic.com/show/16519633.html



观察规律发现:

  • 图片的下载地址在src属性下

  • 图片有个唯一的id属性:J_worksImg

[置顶]        使用Jsoup解析网页



找到规律后,我们就来使用Jsoup来获取一下图片的下载地址

  • 代码实现:
    /**
* 通过子页面链接(图片网页)获取到图片下载地址
* "http://www.nipic.com/show/16519633.html"
* @return downloadPicUrl
*/

public static List<String> getPicDownUrlFromAllPicPage(String url) {
//保存图片的下载地址
List<String> list = new ArrayList<String>();
try {
//通过传入一个url打开一个链接并且获取内容,将内容存到文件中
Document doc = Jsoup.connect(url).get();
//如果文档不为空 && 页面中没有出现 “唔,未找到任何页面!!!” 则认为该页面是个正常页面
if (doc != null && !Jsoup.connect(url).get().html().contains("唔,未找到任何页面!!!")) {
//获取到网页的唯一的id元素
Element element = doc.getElementById("J_worksImg");
//判断元素不为空 && src里面的内容不为空
if (element != null && !element.attr("src").equals("")) {
//将图片地址添加到集合中
list.add(element.attr("src"));
}
}
} catch (IOException e) {
e.printStackTrace();
}
//http://pic120.nipic.com/file/20170114/958400_203916268000_2.jpg
return list;
}



Main方法()

public static void main(String[] args) {
//程序第一个运行的时间(毫秒)
long begin = System.currentTimeMillis();

List<String> list = getPicDownUrlFromAllPicPage("http://www.nipic.com/show/16519633.html");
for (String string : list) {
System.out.println("图片下载地址:" + string);
}


//输出程序最后所花费的时间
System.out.println("\n\n用时:" + (System.currentTimeMillis() - begin)/1000f + "s");
}


这样我们就拿到了图片的下载地址了

[置顶]        使用Jsoup解析网页



对下载地址进行切割


我们可以再写一个方法,将每个图片的下载链接进行切割,拿到图片名

    /**
* 将图片下载地址进行切割,得到文件名
* 根据传入的url地址,获取文件的名称
* @param url
* @return name
*/

public static String getNameFromUrl(String url) {
//找到最后一个 "/" 的位置
int beginIndex = url.lastIndexOf("/");
//截取 "/" 后面的内容
String name = url.substring(beginIndex + 1);
return name;
}
将刚刚的图片下载地址放进去

System.out.println(getNameFromUrl("http://pic120.nipic.com/file/20170114/958400_203916268000_2.jpg"));


这样就拿到了图片名,方便后续保存工作

[置顶]        使用Jsoup解析网页


2、获取单个列表里面所有的图片介绍页面


既然我们能通过图片介绍页面来获取到图片的下载地址,那我们能不能把整一个图片列表的所有图片介绍页面都获取到呢?


我们分析一下图片列表的网页

http://www.nipic.com/topic/show_27036_1.html?ll



定位到第一张图片发现 这个介绍页面有一个class属性 ,并且有个值:block works-detail hover-none

[置顶]        使用Jsoup解析网页



查找一下这个值发现 有40条数据,而且都是我们所关注的内容

[置顶]        使用Jsoup解析网页



既然知道了规律之后,那我们就来获取一下这个列表下的所有图片介绍页面

  • 代码实现:
/**
* 获取分页里的所有的子页面地址
* @param OnePage 传入一个图片列表页面
* "http://www.nipic.com/topic/show_27036_1.html"
*/

public static List<String> getAllPicPageFromOnePage(String OnePage) {
List<String> list = new ArrayList<String>();
try {
Document doc = Jsoup.connect(OnePage).get();
//获取所有包括该class属性的元素
Elements elements = doc.getElementsByClass("block works-detail hover-none");
System.out.println("当前页面有:" + elements.size() + " 子页面\n");
for (Element element : elements) {
//将获取到的元素添加到集合
list.add(element.attr("href"));
}
} catch (IOException e) {
e.printStackTrace();
}
return list;
}


Main方法

public static void main(String[] args) {
//程序第一个运行的时间(毫秒)
long begin = System.currentTimeMillis();

List<String> list = getAllPicPageFromOnePage("http://www.nipic.com/topic/show_27036_1.html");
for (String string : list) {
System.out.println(string);
}

//输出程序最后所花费的时间
System.out.println("\n\n用时:" + (System.currentTimeMillis() - begin)/1000f + "s");
}


确实获取到了我们想要的这40个页面

[置顶]        使用Jsoup解析网页




3、获取所有的分页列表页面


既然我们能通过一个列表页面来获取所有的图片介绍页面,那么我们能不能获取到所有的列表页面的呢?


我们继续来分析页面

http://www.nipic.com/topic/show_27036_1.html?ll



从网页源码中可以发现,每个列表页面链接都有一个class属性,并且属性里面都包涵有
“ eo-page-num“ 的内容

[置顶]        使用Jsoup解析网页



查找一下整个页面有多少包涵“eo-page-num”内容的数据

  • 发现只有3个地方有这个页面(也就是说只有3个列表)

[置顶]        使用Jsoup解析网页



知道规律之后,我们就来获取一下这个页面的所有分页列表

  • 代码实现
/**
* 获取所有的图片列表页面
* "http://www.nipic.com/topic/show_27036_1.html?ll"
*/

public static List<String> getAllPicPage(String url) {
List<String> list = new ArrayList<String>();
try {

Document doc = Jsoup.connect(url).get();
//获取所有包括该class属性的元素
Elements elements = doc.getElementsByClass("seo-page-num");
System.out.println("共有:" + elements.size() + " 个分页");
for (Element element : elements) {
//将元素中的href值添加到集合中
list.add(element.attr("href"));
System.out.println(element.attr("href"));
}

} catch (IOException e) {
e.printStackTrace();
}




return list;
}


Main方法()

public static void main(String[] args) {
//程序第一个运行的时间(毫秒)
long begin = System.currentTimeMillis();

List<String> list = getAllPicPage("http://www.nipic.com/topic/show_27036_1.html");
for (String string : list) {
System.out.println(string);
}

//输出程序最后所花费的时间
System.out.println("\n\n用时:" + (System.currentTimeMillis() - begin)/1000f + "s");
}


确实获取到了所有的列表页面

http://www.nipic.com/topic/show_27036_1.html
http://www.nipic.com/topic/show_27036_2.html
http://www.nipic.com/topic/show_27036_3.html

[置顶]        使用Jsoup解析网页


实战


下载所有列表的图片:

  • 1、 获取所有的列表页面

  • 2、 获取每个列表页面的所有图片介绍页面

  • 3、 通过介绍页面获取下载地址

  • 4、 对下载地址进行切割拿到图片名

  • 5、 通过下载链接跟图片名,将所有的图片下载到images目录



在项目下创建一个images目录用来保存图片

  • 代码实现
package com.lingdu.jsoup;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

/**
* 下载图片Demo
* 2017-2-10
* LingDu
*/

public class GetPicDemo {

/**
* 5、下载图片
* 到nipic网站下载图片
* 传入图片下载地址即可下载到images目录下
*/

public static void downloadPic(String myUrl) {
if (!myUrl.equals("")) {
try {
URL url = new URL(myUrl);
BufferedInputStream bis = new BufferedInputStream(url.openConnection().getInputStream());
byte myArray[] = new byte[1024*1024];
int len = 0;
String fileName = getNameFromUrl(myUrl);
//System.out.println(fileName);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("images/" + fileName));
while((len = bis.read(myArray)) != -1){
bos.write(myArray, 0, len);
}
bos.flush();
bos.close();
bis.close();
System.out.println("图片:" + fileName +" ------>下载成功!");
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}


/**
* 4、将图片下载地址进行切割,得到文件名
* 根据传入的url地址,获取文件的名称
* @param url
* @return name
*/

public static String getNameFromUrl(String url) {
//找到最后一个 "/" 的位置
int beginIndex = url.lastIndexOf("/");
//截取 "/" 后面的内容
String name = url.substring(beginIndex + 1);
return name;
}



/**
* 3、通过子页面链接(图片网页)获取到图片下载地址
* "http://www.nipic.com/show/16519633.html"
* @return downloadPicUrl
*/

public static List<String> getPicDownUrlFromAllPicPage(String url) {
//保存图片的下载地址
List<String> list = new ArrayList<String>();
try {
//通过传入一个url打开一个链接并且获取内容,将内容存到文件中
Document doc = Jsoup.connect(url).get();
//如果文档不为空 && 页面中没有出现 “唔,未找到任何页面!!!” 则认为该页面是个正常页面
if (doc != null && !Jsoup.connect(url).get().html().contains("唔,未找到任何页面!!!")) {
//获取到网页的唯一的id元素
Element element = doc.getElementById("J_worksImg");
//判断元素不为空 && src里面的内容不为空
if (element != null && !element.attr("src").equals("")) {
//将图片地址添加到集合中
list.add(element.attr("src"));
}
}
} catch (IOException e) {
e.printStackTrace();
}
//http://pic120.nipic.com/file/20170114/958400_203916268000_2.jpg
return list;
}


/**
* 2、获取分页里的所有的子页面地址
* @param OnePage 传入一个图片列表页面
* "http://www.nipic.com/topic/show_27036_1.html"
*/

public static List<String> getAllPicPageFromOnePage(String OnePage) {
List<String> list = new ArrayList<String>();
try {
Document doc = Jsoup.connect(OnePage).get();
//获取所有包括该class属性的元素
Elements elements = doc.getElementsByClass("block works-detail hover-none");
System.out.println("当前页面有:" + elements.size() + " 子页面\n");
for (Element element : elements) {
//将获取到的元素添加到集合
list.add(element.attr("href"));
}
} catch (IOException e) {
e.printStackTrace();
}
return list;
}


/**
* 1、获取所有的图片列表页面
* "http://www.nipic.com/topic/show_27036_1.html?ll"
*/

public static List<String> getAllPicPage(String url) {
List<String> list = new ArrayList<String>();
try {

Document doc = Jsoup.connect(url).get();
//获取所有包括该class属性的元素
Elements elements = doc.getElementsByClass("seo-page-num");
System.out.println("共有:" + elements.size() + " 个分页");
for (Element element : elements) {
//http://www.nipic.com/topic/show_27036_1.html
//http://www.nipic.com/topic/show_27036_2.html
//http://www.nipic.com/topic/show_27036_3.html
//将元素中的href值添加到集合中
list.add(element.attr("href"));
}

} catch (IOException e) {
e.printStackTrace();
}
return list;
}


/**
* 这个方法处理所有逻辑
*/

public static void downloadAll() {
//拿到图片列表页面
List<String> picPagelist = new ArrayList<String>();
//拿到所有图片下载页面
List<String> allPicPageList = new ArrayList<String>();
//拿到图片的下载地址
List<String> picDownUrlList = new ArrayList<String>();
picPagelist = getAllPicPage("http://www.nipic.com/topic/show_27036_1.html?ll");
for (String str : picPagelist) {
System.out.println("\n页面:----------------->" + str);
allPicPageList = getAllPicPageFromOnePage(str);
for (String str1 : allPicPageList) {
try {
picDownUrlList = getPicDownUrlFromAllPicPage(str1);
for (String str2 : picDownUrlList) {
downloadPic(str2);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}


public static void main(String[] args) {
//程序第一个运行的时间(毫秒)
long begin = System.currentTimeMillis();

//调用所有方法的整合体
downloadAll();

//输出程序最后所花费的时间
System.out.println("\n\n用时:" + (System.currentTimeMillis() - begin)/1000f + "s");
}
}


这样就下载到了所有的图片了

[置顶]        使用Jsoup解析网页



查看一下images目录 ,确实把所有列表的图片都下载下来了,总共有92张图片

[置顶]        使用Jsoup解析网页


实现原理

  • 分析网页找到规律

  • 依次往下嵌套循环即可获取到下载地址

  • 最终完成下载