当我们在用Java做爬虫的时候,当使用HttpClient获取到网页源码后,需要从源码中找到我们所需要的信息时,Jsoup就派上用场了,Jsoup是一款Java 的HTML解析器,可以对HTML进行解析。
虽然Jsoup支持直接根据地址爬源码,但由于jsoup只支持HTTP和HTTPS协议,不够丰富,所以不建议这样做。因此还是老老实实拿到源码之后将其作为一个解析工具而不是爬源码的工具。
如果用maven的话可以可以导入依赖
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.7.3</version>
</dependency>
作为一个工具类,我们可以直接调用Jsoup类中的静态方法(Jsoup类中所有方法都是静态的)
Jsoup会把输入的HTML转化成Document对象,org.jsoup.nodes.Element,Element又继承了org.jsoup.nodes.Node类。里面提供了丰富的方法来获取HTML的元素。
1.通过Jsoup直接爬网页源码(要慎重)
Document doc = Jsoup.connect("http://www.baidu.com/").get();
String title = doc.title();
System.out.println(title);
//输出
百度一下,你就知道
当然也可以从本地文件中获取一个Document对象
File f = new File("F:\\java\\Project01\\Crawler\\src\\main\\webapp\\WEB-INF\\baidu.html");
Document document = Jsoup.parse(f, "utf-8", "");
System.out.println(document.title());
//输出
百度一下,你就知道
2.当获得Document对象后,就可以通过DOM的方式获得指定的元素
getElementById(String id):通过id来获取
getElementsByTag(String tagName):通过标签名字来获取
getElementsByClass(String className):通过类名来获取
getElementsByAttribute(String key):通过属性名字来获取
getElementsByAttributeValue(String key, String value):通过指定的属性名字,属性值来获取
getAllElements():获取所有元素
3.获取到元素后就可以通过下面的方法获取到真正的内容了
Element.text()
这个方法用来取得一个元素中的文本。
Element.html()或Node.outerHtml()
这个方法用来取得一个元素中的html内容
Node.attr(String key)
获得一个属性的值,例如取得超链接<a href="">中href的值
案例:爬王者荣耀所有英雄的图片
注意点:
1.如果没有文件路径首先要创建路径
2.通过abs:src可以获得资源的绝对路径
3.当你访问一个页面时有一些图片,然后点更多又出现了一些图片,这时你发现你爬那个网页爬不下点更多时的图片,这是因为,点更多相当于转发,地址不变,但资源路径变了,所以就爬不到了
4.由于中文以及空格等非法字符在传输时会乱码,所以在传输前必须进行url编码,ASCII中的空格在URL编码中为%20,注意中文的问题
package crawler;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
/**
* 使用Jsoup包来爬取王者荣耀阵容
*/
public class HttpClientDemo04 {
/**
* 下载图片到指定目录
*
* @param filePath 文件路径
* @param imgUrl 图片地址
*/
public static void download(String filePath, String imgUrl) {
//判断文件是否存在,如果不存在创建目录
File file = new File(filePath);
if (!file.exists()) {
file.mkdirs();
}
//导出文件名称
String fileName = imgUrl.substring(imgUrl.lastIndexOf('/') + 1, imgUrl.length());
try {
//将文件名转化为指定格式,html5之前字符集格式不统一,需要转化成UTF-8
String urlTail = URLEncoder.encode(fileName, "UTF-8");
//因此需要将加号转化为UTF-8中的20%
imgUrl = imgUrl.substring(0, imgUrl.lastIndexOf('/') + 1) + urlTail.replaceAll("\\+", "\\%20");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
//File.separator的作用是加入文件分隔符
File file1 = new File(filePath + File.separator + fileName);
try {
//获取图片URL
URL url = new URL(imgUrl);
//获取连接
URLConnection urlConnection = url.openConnection();
//设置连接时间
urlConnection.setConnectTimeout(10 * 1000);
//设置输入流
InputStream in = urlConnection.getInputStream();
//设置输出流
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file1));
byte[] buf = new byte[1024];
int len;
while (-1 != (len = in.read(buf))) {
out.write(buf, 0, len);
}
out.close();
in.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
//创建链接
Connection connection = Jsoup.connect("https://pvp.qq.com/web201605/herolist.shtml");
//获取document对象
Document document = connection.get();
// System.out.println(document);
//获取对应元素
Elements imgs = document.getElementsByTag("img");
System.out.println("检测到图片");
System.out.println("开始下载。。。。");
for (Element img : imgs) {
//获取绝对路径
String imgStr = img.attr("abs:src");
System.out.println(imgStr);
download("F:/img", imgStr);
}
System.out.println("下载完成");
}
}