Jsoup 爬虫之百度贴吧

最近闲的无聊,就想学一下爬虫玩玩,因为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注意不到,无法处理。

有任何有问题,欢迎指出,留言,评论。

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值