爬虫学习的一个综合案例——访问网站

1.一些回顾知识和补充

URL基础讲解_說書人的博客-CSDN博客

详解HttpURLConnection_清箫的博客-CSDN博客_httpurlconnection

一个是URL,一个是HeepURLConnection:

任何网络连接都需要经过socket才能连接,HttpURLConnection不需要设置socket,所以,HttpURLConnection并不是底层的连接,而是在底层连接上的一个请求。这就是为什么HttpURLConneciton只是一个抽象类,自身不能被实例化的原因。HttpURLConnection只能通过URL.openConnection()方法创建具体的实例。
 

这里请求头的话有Get 、Post,

GET请求和POST请求详述_bear*6的博客-CSDN博客_get请求和post的用法

GET 请求和 POST 请求的区别与使用示例 - 隔壁汪书 - 博客园

爬虫在setRequestProperty传入的:

User-Agent(用户代理)是什么_睿科知识云的博客-CSDN博客_user-agent

正则:

正则表达式中关于 \ 的用法,例如\. \(_懶好人vest的博客-CSDN博客_正则表达式\

正则 ?= 用法_风神修罗使的博客-CSDN博客_?= 正则

正则表达式中?=和?:和?!的理解_这个昵称没有被占用吧的博客-CSDN博客_正则表达式?!

接口和实现类

接口 对象 = new 实现类 与 实现类 对象= new 实现类_代码敲上天.的博客-CSDN博客_new 实现类

接口如何实现多态_晓晓小仙儿的博客-CSDN博客_接口多态

实现多态的方式——接口 - 走看看

Set set=new HashSet();的意义是什么呢_谜的博客的博客-CSDN博客

Collection<? extends E>解释:
1.实现了Collection接口
2.类型一定是E的子类

?是“任意类”的意思,extends继承不多说,E是指定类型,是泛型;
通常出现在将一个集合赋值给另一个集合的情景中,

如:public LinkedList(Collection<? extends E> c )、addAll(Collection<? extends E> c);

addAll方法——向Set集合添加另一个集合的所有内容_xk_一步一步来的博客-CSDN博客_addall方法

2.究极详细的代码分析

public class UrlCrawBoke {

    static String userId = "";

    public static void main(String urlstr[]) throws IOException, InterruptedException {

        //set是接口,hashset是它的实现类
        //接口 对象 = new 实现类,见笔记,主要是为了实现多态,虽然这里不需要多态,但是这是良好的代码习惯
        Set urls = new HashSet();

        // ----------------------------------------------遍历每一页 获取文章链接----------------------------------------------
        //该引用为常量,该值无法修改
        final String homeUrl = "https://blog.csdn.net/" + userId + "/article/list/";// 后面加pageNum即可
        //统计页数
        int totalPage = 0;
        //接受从网页爬取的内容
        InputStream is;
        //把网页内容转为string
        String pageStr;
        //网站地址索引
        StringBuilder curUrl = null;

        for (int i = 1; i < 50; i++) {
            //暂停1秒
            Thread.sleep(1000);
            //找页数,如果写的文章多,那就有两页三页......
            System.out.println("finding page " + i);
            //初始化网站地址索引
            curUrl = new StringBuilder(homeUrl);
            //完善地址,加上页码
            curUrl.append(i);
            System.out.println(curUrl);
            //爬取网站内容
            is = doGet(curUrl.toString());
            //转成string
            pageStr = inputStreamToString(is, "UTF-8");// 一整页的html源码
            //正则表达式,这里是来获取每一篇博客的网址,按照规律来,detaiLs后面会跟8-9个数字,
            //又因为在博客目录下,要访问具体博客,我们鼠标点的是图标文字,但是实际上点的是超链接,也就是这个网页的静态资源里面html文本中必然是有href
            //所以(?<=href=\")表示匹配以href="开头的字符串,并且捕获(存储)到分组中,\"写在正则里面就是表示",\是引用符
            //而最后面的(?=\")表示匹配以"结尾的字符串,并且捕获(存储)到分组中,这样就把具体博客的网址拿下来了
            List list = getMatherSubstrs(pageStr, "(?<=href=\")https://blog.csdn.net/" + userId + "/article/details/[0-9]{8,9}(?=\")");
            //把网址加进去
            /*这里的addall,有点东西的
            首先首先,集合collection是最上层滴接口
            然后set是collection的子接口
            再然后Hashset是set其中一个实现类
            然后按道理应该addall方法要在hashset中实现
            但是呢,hashset不仅实现set还继承了abstractset这个抽象类
            然后abstractset这个抽象类继承AbstractCollection(当然也实现了set)
            所以最后最后呢,addall这个玩意是在AbstractCollection这个抽象类里面实现的,这也是为什么我们查找实现查到AbstractCollection去了
            */
            //addall就是把list的内容全部添加到urls里去
            urls.addAll(list);
            //总页数
            totalPage = i;
            //如果pagestr里面没有空空如也这四个字,那就返回-1,至于空空如也是因为csdn里面如果没有博客那就会出现这里空空如也
            //但是这网页有时候也脑抽的,不一定每次都吃
            if (pageStr.lastIndexOf("空空如也") != -1) {
                System.out.println("已经到最后一页!");
                break;
            } else {
                System.out.println("Success~");
            }

        }
        System.out.println("总页数为: " + totalPage);

        // ---------------------------------------------------打印每个链接---------------------------------------------------
        System.out.println("打印每个链接");
        for (Object s:urls) {
            System.out.println(s);
        }
        System.out.println("打印每个链接完毕");

        // ---------------------------------------------------访问每个链接---------------------------------------------------
        int i=0;
        for (Object s:urls) {
            //传入网址进行访问
            doGet(s.toString());
            System.out.println("成功访问第" + (++i) + "个链接,共" + urls.size() + "个:" + s);
        }

        // ---------------------------------------------------程序结束---------------------------------------------------
        System.out.println("运行完毕,成功增加访问数:" + urls.size());
    }

    public static InputStream doGet(String urlstr) throws IOException {
        //初始化URL
        URL url = new URL(urlstr);
        //打开URL链接,获得HttpURLConnection对象,下面的括号转化是有原理的,看看笔记
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        //对链接进行设置(设置请求头或响应头)
        //setRequestProperty(key,value),后面只能跟一个value
        //setRequestProperty会覆盖已经存在的key的所有values,有清零重新赋值的作用
        //User-Agent(用户代理),详情看笔记
        conn.setRequestProperty("User-Agent",
                "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36");
        //建立HttpURLConnection链接
        conn.connect();
        //读取网页内容(字符串流)(请求)(实际上也会隐式调用connect())
        InputStream inputStream = conn.getInputStream();
        //返回
        return inputStream;
    }

    //charset代表的是编码
    public static String inputStreamToString(InputStream is, String charset) throws IOException {
        //缓冲区
        byte[] bytes = new byte[1024];
        //长度
        int byteLength = 0;
        StringBuffer sb = new StringBuffer();
        //常见的读取操作
        while ((byteLength = is.read(bytes)) != -1) {
            //函数里面长度可以不写
            //这个string()源码很有意思,虽然看起来吃力,但是值得一看
            sb.append(new String(bytes, 0, byteLength, charset));
        }
        return sb.toString();
    }

    // 正则匹配
    public static List getMatherSubstrs(String str, String regex) {
        //获取链表
        List list = new ArrayList();
        //获取正则表达式对象
        Pattern p = Pattern.compile(regex);
        //获取文本匹配器m,拿着m,按p的规则去匹配str
        Matcher m = p.matcher(str);
        while (m.find()) {
            //循环获取
            list.add(m.group());
        }
        return list;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值