Java爬虫Get校花网所有美女图片

前言

作为一个宅男,每天看看美女图是必修课。那么——作为一个程序猿加宅男,如何收藏更多的美女图片呢?这就要用到爬虫了,哈哈,我仿佛看到了无穷无尽的美女在向我招手——怎么感觉写下这段话的时候自己略有一丝猥琐呢?啊呸,相当之猥琐!

我们的重点是学习写爬虫,嗯!

网络爬虫是做什么的?

他的主要工作就是 跟据指定的url地址 去发送请求,获得响应, 然后解析响应 , 一方面从响应中查找出想要查找的数据,另一方面从响应中解析出新的URL路径。

然后继续访问,继续解析;继续查找需要的数据和继续解析出新的URL路径

这就是网络爬虫主要干的工作. 下面是流程图:

通过上面的流程图 能大概了解到 网络爬虫 干了哪些活 ,根据这些 也就能设计出一个简单的网络爬虫出来。

一个简单的爬虫 必需的功能:

  1. 发送请求和获取响应的功能
  2. 解析响应的功能
  3. 过滤出的数据进行存储的功能
  4. 对解析出来的URL路径处理的功能

先看看运行效果

下面是包结构

核心代码

RequestAndResponseTool 类: 主要方法: 发送请求 返回响应 并把 响应 封装成 page 类

public class RequestAndResponseTool {


    public static Page sendRequstAndGetResponse(String url) {
        Page page = null;
        // 1.生成 HttpClinet 对象并设置参数
        HttpClient httpClient = new HttpClient();
        // 设置 HTTP 连接超时 5s
        httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(5000);
        // 2.生成 GetMethod 对象并设置参数
        GetMethod getMethod = new GetMethod(url);
        // 设置 get 请求超时 5s
        getMethod.getParams().setParameter(HttpMethodParams.SO_TIMEOUT, 5000);
        // 设置请求重试处理
        getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler());
        // 3.执行 HTTP GET 请求
        try {
            int statusCode = httpClient.executeMethod(getMethod);
            // 判断访问的状态码
            if (statusCode != HttpStatus.SC_OK) {
                System.err.println("Method failed: " + getMethod.getStatusLine());
            }
            // 4.处理 HTTP 响应内容
            byte[] responseBody = getMethod.getResponseBody();// 读取为字节 数组
            String contentType = getMethod.getResponseHeader("Content-Type").getValue(); // 得到当前返回类型
            page = new Page(responseBody, url, contentType); //封装成为页面
        } catch (HttpException e) {
            // 发生致命的异常,可能是协议不对或者返回的内容有问题
            System.out.println("Please check your provided http address!");
            e.printStackTrace();
        } catch (IOException e) {
            // 发生网络异常
            e.printStackTrace();
        } finally {
            // 释放连接
            getMethod.releaseConnection();
        }
        return page;
    }
}

page 类: 主要作用: 保存响应的相关内容 对外提供访问方法

/*
* 保存获取到的响应的相关内容;
*/
public class Page {

    private byte[] content;
    private String html;  //网页源码字符串
    private Document doc;//网页Dom文档
    private String charset;//字符编码
    private String url;//url路径
    private String contentType;// 内容类型


    public Page(byte[] content, String url, String contentType) {
        this.content = content;
        this.url = url;
        this.contentType = contentType;
    }

    public String getCharset() {
        return charset;
    }

    public String getUrl() {
        return url;
    }

    public String getContentType() {
        return contentType;
    }

    public byte[] getContent() {
        return content;
    }

    /**
     * 返回网页的源码字符串
     *
     * @return 网页的源码字符串
     */
    public String getHtml() {
        if (html != null) {
            return html;
        }
        if (content == null) {
            return null;
        }
        if (charset == null) {
            charset = CharsetDetector.guessEncoding(content); // 根据内容来猜测 字符编码
        }
        try {
            this.html = new String(content, charset);
            return html;
        } catch (UnsupportedEncodingException ex) {
            ex.printStackTrace();
            return null;
        }
    }

    /*
    *  得到文档
    * */
    public Document getDoc() {
        if (doc != null) {
            return doc;
        }
        try {
            this.doc = Jsoup.parse(getHtml(), url);
            return doc;
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }


}

PageParserTool: 类 主要作用 提供了 根据选择器来选取元素 属性 等方法

public class PageParserTool {

    /* 通过选择器来选取页面的 */
    public static Elements select(Page page, String cssSelector) {
        return page.getDoc().select(cssSelector);
    }

    /*
     *  通过css选择器来得到指定元素;
     *
     *  */
    public static Element select(Page page, String cssSelector, int index) {
        Elements eles = select(page, cssSelector);
        int realIndex = index;
        if (index < 0) {
            realIndex = eles.size() + index;
        }
        return eles.get(realIndex);
    }

    /**
     * 获取满足选择器的元素中的链接 选择器cssSelector必须定位到具体的超链接
     * 例如我们想抽取id为content的div中的所有超链接,这里
     * 就要将cssSelector定义为div[id=content] a
     * 放入set 中 防止重复;
     *
     * @param cssSelector
     * @return
     */
    public static Set<String> getLinks(Page page, String cssSelector) {
        Set<String> links = new HashSet<String>();
        Elements es = select(page, cssSelector);
        Iterator iterator = es.iterator();
        while (iterator.hasNext()) {
            Element element = (Element) iterator.next();
            if (element.hasAttr("href")) {
                links.add(element.attr("abs:href"));
            } else if (element.hasAttr("src")) {
                links.add(element.attr("abs:src"));
            }
        }
        return links;
    }

    /**
     * 获取网页中满足指定css选择器的所有元素的指定属性的集合
     * 例如通过getAttrs("img[src]","abs:src")可获取网页中所有图片的链接
     *
     * @param cssSelector
     * @param attrName
     * @return
     */
    public static ArrayList<String> getAttrs(Page page, String cssSelector, String attrName) {
        ArrayList<String> result = new ArrayList<String>();
        Elements eles = select(page, cssSelector);
        for (Element ele : eles) {
            if (ele.hasAttr(attrName)) {
                result.add(ele.attr(attrName));
            }
        }
        return result;
    }
}

Links 类: 两个属性: 一个是存放 已经访问的url集合的set ; 一个是存放待访问url集合的 queue

/*
*  Link主要功能;
*  存储已经访问过的URL路径 和 待访问的URL 路径;
*/
public class Links {

    //已访问的 url 集合  已经访问过的 主要考虑 不能再重复了 使用set来保证不重复;
    private static Set visitedUrlSet = new HashSet();

    //待访问的 url 集合  待访问的主要考虑 1:规定访问顺序;2:保证不提供重复的带访问地址;
    private static LinkedList unVisitedUrlQueue = new LinkedList();

    //获得已经访问的 URL 数目
    public static int getVisitedUrlNum() {
        return visitedUrlSet.size();
    }

    //添加到访问过的 URL
    public static void addVisitedUrlSet(String url) {
        visitedUrlSet.add(url);
    }

    //移除访问过的 URL
    public static void removeVisitedUrlSet(String url) {
        visitedUrlSet.remove(url);
    }


    //获得 待访问的 url 集合
    public static LinkedList getUnVisitedUrlQueue() {
        return unVisitedUrlQueue;
    }

    // 添加到待访问的集合中  保证每个 URL 只被访问一次
    public static void addUnvisitedUrlQueue(String url) {
        if (url != null && !url.trim().equals("") && !visitedUrlSet.contains(url) && !unVisitedUrlQueue.contains(url)) {
            unVisitedUrlQueue.add(url);
        }
    }

    //删除 待访问的url
    public static Object removeHeadOfUnVisitedUrlQueue() {
        return unVisitedUrlQueue.removeFirst();
    }

    //判断未访问的 URL 队列中是否为空
    public static boolean unVisitedUrlQueueIsEmpty() {
        return unVisitedUrlQueue.isEmpty();
    }


}

LinkFilter 接口: 可以起过滤作用

public interface LinkFilter {
    public boolean accept(String url);
}

原文发布于微信公众号 - java工会(javagonghui)

原文发表时间:2018-06-07

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏joycl

c#面试题汇总

下面的参考解答只是帮助大家理解,不用背,面试题、笔试题千变万化,不要梦想着把题覆盖了,下面的题是供大家查漏补缺用的,真正的把这些题搞懂了,才能“以不变应万变”。...

3161
来自专栏逆向技术

PE格式第六讲,导出表

                PE格式第六讲,导出表 请注意,下方字数比较多,其实结构挺简单,但是你如果把博客内容弄明白了,对你受益匪浅,千万不要看到字...

1876
来自专栏生信宝典

Linux学习-文件排序和FASTA文件操作

环境变量的补充 PATH只是众多环境变量中的一个变量,用于存储可执行文件所在的目录,以便在用户输入命令时可以查询的到。尤其是自己写的脚本或安装的程序,系统不会知...

22710
来自专栏Python攻城狮

Django教程(三)- Django表单Form1.Form 基本使用2.Form中字段及插件3.通过Django表单Form来完成需求4.自定义验证验证规则

创建Form类时,主要涉及到 【字段】 和 【插件】,字段用于对用户请求数据的验证,插件用于自动生成HTML;

1444
来自专栏老马说编程

(64) 常见文件类型处理: 属性文件/CSV/EXCEL/HTML/压缩文件 / 计算机程序的思维逻辑

查看历史文章,请点击上方链接关注公众号。 对于处理文件,我们介绍了流的方式,57节介绍了字节流,58节介绍了字符流,同时,也介绍了比较底层的操作文件的方式,60...

3808
来自专栏IT杂记

通过Java程序提交通用Mapreduce无法回收类的问题

问题描述 上次发布的博客 通过Java程序提交通用Mapreduce,在实施过程中发现,每次提交一次Mapreduce任务,JVM无法回收过程中产生的MapRe...

2996
来自专栏hotqin888的专栏

tealeg/xlsx遇到读取空表格错误

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hotqin888/article/det...

1182
来自专栏比原链

剥开比原看代码13:比原是如何通过/list-balances显示帐户余额的?

Gitee地址:https://gitee.com/BytomBlockchain/bytom

691
来自专栏大内老A

ASP.NET MVC以ModelValidator为核心的Model验证体系: ModelValidatorProviders

前面篇文章我们分别介绍用真正用于实施Model验证的ModelValidator(《ASP.NET MVC以ModelValidator为核心的Model验证体...

1725
来自专栏Android自学

【转】jQuery验证控件jquery.validate.js使用说明+中文API

2194

扫码关注云+社区