最近闲的无聊,就想学一下爬虫玩玩,因为python还没有学过,索性先找一下Java的爬虫,百度之后发现还是Jsoup用的多一点,而且更简单一点。
因为我比较喜欢古风,所以这次的目标就是古风吧,爬里面的图片。
https://tieba.baidu.com/f/good?kw=%E5%8F%A4%E9%A3%8E&ie=utf-8&cid=3
然后就是分析一下他的网页结构
发现他的a标签是有class名字的,那么接下来的话可以:
Elements a = doc.select("a.j_th_tit");
来获取里面的a标签
public void all(String url, String index) {
try {
Document doc = Jsoup.connect(url)
.userAgent("Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.15)")
.timeout(3000)
.get();
Elements a = doc.select("a.j_th_tit");
for (Element n : a) {
HomePage(n.attr("abs:href"), index);
}
} catch (Exception e) {
e.printStackTrace();
}
}
这样来获取这个页面所有的a标签。
这里有一个细节就是在获取链接的时候伪装成浏览器去访问,如果你直接
Document doc = Jsoup.connect(url).get();这样去写的话,是获取不到的!
要注意!
然后就是第一个页面
然后打开查看他的图片
这就很舒服,他也有class名,不会和其他图片搞混了
那么接下来就是获取这个页面所有图片的链接了
private void WriteThis(String url, String index) {
try {
Document doc = Jsoup.connect(url).get();
Elements pics = doc.select("img[class=BDE_Image]");
for (Element pic : pics) {
savePic(pic.attr("src"), index);
}
} catch (Exception e) {
e.printStackTrace();
}
}
这样就可以轻松获取第一页所有的图片链接,
但是不是每个帖子都只有一页,所还要获取下一页的链接
这样的标签是比较烦的,不过他还是有文字的,我们可以通过获取他的文字去判断是不是下一页的链接
private String getNext(String url) {
try {
Document doc = Jsoup.connect(url).get();
Elements next = doc.getElementsByTag("a");
for (Element a : next) {
if (a.text().equals("下一页")) {
return a.attr("abs:href");
}
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
abs:href是获取它的绝对链接的方式,因为有些时候他是相对链接,为了避免重复检查,所以直接去获取绝对链接,然后返回他的url。
这样每页每个帖子每个图片的链接就都可以获取到了,那么接下来就是如何通过图片的链接吧图片存储到本地了。
private void savePic(String src, String index) {
try {
String filename = "Reptile" + String.valueOf(((new Date()).getTime()) % 1000000) + ".jpg";
String FinalIndex = index + "\\" + filename;
Connection.Response res = Jsoup.connect(src).ignoreContentType(true).execute();
byte[] img = res.bodyAsBytes();
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(FinalIndex)));
bos.write(img);
bos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
这个呢也是百度的一种方法,比较简单的一种,应该很容看懂。
然后就需要创建文件夹了,我是比较有强迫症的那种,喜欢每个帖子的图片放到专门的文件夹里面去
private String CreateFile(String url, String index) {
try {
Document doc = Jsoup.connect(url).get();
Elements h3 = doc.select("h3");
System.out.println(h3.text());
File file = new File(index + "\\" + h3.text());
if (!file.exists()) {
file.mkdir();
}
return file.getPath();
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
这样就可以根据你想要放的地方自动创建文件夹,然后返回文件夹的路径了。
接下来就是拼接然后运行了,上面的代码都是我没有添加注释的,下面会给出带有注释全部代码:
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.util.Date;
public class PICget {
//图片写入本地
private void savePic(String src, String index) {
try {
//给图片起个不同的名字,免得重复了(如果想要png,可以吧后面的jpg换成png)
String filename = "Reptile" + String.valueOf(((new Date()).getTime()) % 1000000) + ".jpg";
//整理出图片的路径
String FinalIndex = index + "\\" + filename;
//获取图片的数据
Connection.Response res = Jsoup.connect(src).ignoreContentType(true).execute();
byte[] img = res.bodyAsBytes();
//写入文件,因为这个流如果没有文件会帮你自动创建,所以不需要我们去单独先去创建那个文件
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(FinalIndex)));
bos.write(img);
bos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
//获取所有图片url
private void WriteThis(String url, String index) {
try {
//获取本页的链接
Document doc = Jsoup.connect(url).get();
//获取所有图片的链接
Elements pics = doc.select("img[class=BDE_Image]");
//调用方法把那些全部都保存到本地
for (Element pic : pics) {
savePic(pic.attr("src"), index);
}
} catch (Exception e) {
e.printStackTrace();
}
}
//获取下一页的链接
private String getNext(String url) {
try {
//获取第一页的链接
Document doc = Jsoup.connect(url).get();
//尝试获取下一页的练级
Elements next = doc.getElementsByTag("a");
for (Element a : next) {
//判断是否有下一页的链接
if (a.text().equals("下一页")) {
//有的话返回链接
return a.attr("abs:href");
}
}
//没有返回无
return "";
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
//创建目标文件夹
private String CreateFile(String url, String index) {
try {
Document doc = Jsoup.connect(url).get();
//获取它的标题
Elements h3 = doc.select("h3");
System.out.println(h3.text());
File file = new File(index + "\\" + h3.text());
if (!file.exists()) {
//创建标题文件夹
file.mkdir();
}
//返回文件路径
return file.getPath();
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
//合成,把一个页面所有的图片全部爬完
public void HomePage(String url, String index) {
try {
//1.获取目标文件夹路径
String str = CreateFile(url, index);
//2.爬取首页图片
WriteThis(url, str);
String next = url;
while (true) {
//3.获取下一页的链接
next = getNext(next);
//4.判断下一页是否为空
if (!next.equals("")) {
//4.1为空,已经是最后一页了,可以结束了
break;
} else {
//4.2不为空,那么继续爬取图片
WriteThis(next, str);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void all(String url, String index) {
try {
//伪装成浏览器访问
Document doc = Jsoup.connect(url)
.userAgent("Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.15)")
.timeout(3000)
.get();
//获取本页所有帖子的链接
Elements a = doc.select("a.j_th_tit");
for (Element n : a) {
//调用函数爬取每个帖子的图片
HomePage(n.attr("abs:href"), index);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class demo {
public static void main(String[] args) {
new PICget().all("https://tieba.baidu.com/f?kw=%E5%8F%A4%E9%A3%8E&ie=utf-8&tab=good&cid=3","E:\\img");
}
}
下面是结果
不过我写的有点问题,就是有可能会获取到别人发出来的图片,不喜欢的话,可以详细一点,一步一步去获取某个人发出来的图片。
我爬了大概1个多小时接近2个小时,还好没有去获取所有精品区的东西,效率确实挺低下的,不过本人能力有限,目前并不知道如何改善。而且因为爬虫时间太长,可能会出现一些bug注意不到,无法处理。
有任何有问题,欢迎指出,留言,评论。