java爬虫

爬虫 专栏收录该内容
1 篇文章 0 订阅

1. 爬虫的基本概念

1.1 什么是爬虫:

​ 网络爬虫是一个程序, 采用一种特定的解析结构来获取互联网中数据的, 爬虫一般分为三大模块: 获取数据, 解析数据, 保存数据

1.2 爬虫的价值:

网络爬虫的价值其实就是数据的价值, 一切皆为数据, 例如: 用户的信息,分析用户的维度, 商品的信息,竞价的网站

1.3 爬虫的分类:

1.3.1 通用的爬虫:

​ 指的就是爬虫互联网中所有的信息, 例如: 百度 谷歌

1.3.2 垂直爬虫:

​ 指的爬取某个行业或者某个网站或者某个分类下的信息,这样的爬虫程序, 垂直爬虫 例如: 慢慢网, 笔趣阁

在开发过程中, 大部分开发的都是垂直爬虫,

1.4 爬虫的基本原理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s2DZvhH4-1605084008952)(…\图片\01-爬虫的基本原理.png)]

爬虫基本原理:

1. 确定爬虫的url
2. 发起http请求, 获取数据
	1. 原始的jdk的方式: get  post
	2. httpClient  get  post
3. 解析获取到数据
	1. jsoup 
4. 保存数据
	1. JDBC
	2. DButils
	3. JDBCTemplate(Spring)
	4. mybatis

2. 爬虫的三大模块:

2.1第一大模块: 获取数据

获取数据的过程, 其实就是发送一个http请求, 获取其响应的内容

2.1.1回顾: http

  • get请求和post的请求的区别:
      1. 请求方式不同
      1. get没有请求体, post有请求体
      1. get请求数据拼接在url后面 ?username=zs&password=123, post将请求参数放置在请求体中
  • 请求头:
    • user-agent: 指定当前使用的浏览器的版本
    • cookie: 携带当前网站的cookie信息
  • 响应头:
    • Location: 一般和302结合使用, 进行重定向
    • set-cookie: 服务器向浏览器写入cookie的信息
  • 常见的状态码:
    • 200: 请求成功
    • 302: 重定向
    • 304: 缓存浏览器的内容
    • 404: 资源不存在
    • 500: 服务端错误

2.1.2使用jdk的方式发起http请求:

  • 发送get请求:
//演示 jdk 的get请求方式
public class JDKget {


    public static void main(String[] args) throws Exception {
        //1. 创建URL对象
        URL url = new URL("http://www.itcast.cn");

        //2. 打开一个连接
        HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();

        //3. 设置请求方式
        urlConnection.setRequestMethod("GET");//此处必须使用大写, 默认是get请求

        //4. 获取输入流
        InputStream in = urlConnection.getInputStream();

        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));

        //5. 获取数据
        String len = null;
        while((len = bufferedReader.readLine())!=null){

            System.out.println(len);
        }

        //6. 关流
        bufferedReader.close();
        in.close();
    }

}

  • 发生post请求
//演示jdk发送post请求
public class JDKpost {

    public static void main(String[] args) throws Exception {
        //1. 创建url对象
        URL url = new URL("http://www.itcast.cn");

        //2. 建立连接
       HttpURLConnection connection  = (HttpURLConnection) url.openConnection();

       //3. 设置请求方式
       connection.setRequestMethod("POST");
       //如果要有使用jdk的方式发送post请求, 需要设置doOutput为true
       connection.setDoOutput(true);
       //4. 设置参数
        OutputStream out = connection.getOutputStream();
        out.write("username=zs&password=123".getBytes());

        //5. 获取响应体, 获取输入流
        InputStream in = connection.getInputStream();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));
        String len = null;
        while((len = bufferedReader.readLine())!=null){

            System.out.println(len);
        }

        //6. 关流
        bufferedReader.close();
        in.close();

    }

}

总结:

​ 实现的步骤:

  1. 创建url对象, 指定url路径

  2. 打开一个连接, 获取连接对象(HttpURLConnection)

  3. 设置请求方式

    1. 如果是post, 需要设置两个参数:

      设置输出数据, 和 doOutPut设置为true

    2. 获取输入流(获取响应体)

    3. 读取输入流中的数据

    4. 关流

2.1.3 使用 httpClient完成http请求

httpclient是一个专为用来做http请求的工具, 是Apache开发

使用步骤:

第一步: 导包
	  <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.4</version>
        </dependency>
  • get请求
//演示 httpclient的get请求
public class HTTPClientGet {

    public static void main(String[] args) throws IOException {
        //1. 创建httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        //2. 创建get请求对象
        HttpGet httpGet = new HttpGet("http://www.itcast.cn");

        //3. 发送一个请求
        CloseableHttpResponse response = httpClient.execute(httpGet);
  
        //4. 获取状态码
        int statusCode = response.getStatusLine().getStatusCode();
        System.out.println(statusCode);
        if(statusCode==200){
            //获取响应体(数据)
            String html = EntityUtils.toString(response.getEntity(), Charset.forName("utf-8"));
            System.out.println(html);
        }
    }
}
  • post请求
//演示 httpclient 发送post请求
public class HTTPClientPost {

    public static void main(String[] args) throws Exception {
        //1. 创建 httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        //2. 创建post请求对象
        HttpPost httpPost = new HttpPost("http://www.itcast.cn");

        //3. 设置请求参数
        List<BasicNameValuePair> list = new ArrayList<BasicNameValuePair>();
        list.add(new BasicNameValuePair("usernam","zs"));
        list.add(new BasicNameValuePair("password","123"));

        HttpEntity entity = new UrlEncodedFormEntity(list);
        httpPost.setEntity(entity);

        //4. 发送数据
        CloseableHttpResponse response = httpClient.execute(httpPost);
        //5. 获取数据
        Header[] headers = response.getHeaders("Date");
      
        System.out.println(headers[0].getValue());
        System.out.println(EntityUtils.toString(response.getEntity(),"utf-8"));

    }
}

总结:

​ get请求:

  1. 创建httpclient对象:HttpClients.createDefault();

    1. 创建请求对象(httpget)

    2. 发送请求: httpclient.execute(httpGet);

    3. 获取数据:

      1. 1 获取状态码

    1.2 获取响应头

    1.3 获取响应体

post请求:

​ 1.创建httpclient对象: HttpClients.createDefault();

​ 2.创建请求对象(httpPost)

​ 3.设置参数: httpPost.setEntity(entity)

   List<BasicNameValuePair> list = new ArrayList<BasicNameValuePair>();
        list.add(new BasicNameValuePair("usernam","zs"));
        list.add(new BasicNameValuePair("password","123"));

        HttpEntity entity = new UrlEncodedFormEntity(list);

​ 4.发送请求:httpclient.execute(httpPost);

​ 5.获取数据:

​ 1.1获取状态码

​ 1.2获取响应头

​ 1.3 获取响应体

2.2 第二大模块: 解析数据

解析数据, 其实就是解析HTML文档,js中dom操作就是在解析HTML文档

2.2.1 Document 对象集合

集合描述
[all]提供对文档中所有 HTML 元素的访问。
[anchors]返回对文档中所有 Anchor 对象的引用。
applets返回对文档中所有 Applet 对象的引用。
[forms]返回对文档中所有 Form 对象引用。
[images]返回对文档中所有 Image 对象引用。
[links]返回对文档中所有 Area 和 Link 对象引用。

2.2.2 Document 对象属性

属性描述
body提供对 元素的直接访问。 对于定义了框架集的文档,该属性引用最外层的 。
cookie设置或返回与当前文档有关的所有 cookie。
domain返回当前文档的域名。
lastModified返回文档被最后修改的日期和时间。
referrer返回载入当前文档的文档的 URL。
title返回当前文档的标题。
URL返回当前文档的 URL。

2.2.3 Document 对象方法

方法描述
close()关闭用 document.open() 方法打开的输出流,并显示选定的数据。
getElementById()返回对拥有指定 id 的第一个对象的引用。
getElementsByName()返回带有指定名称的对象集合。
getElementsByTagName()返回带有指定标签名的对象集合。
open()打开一个流,以收集来自任何 document.write() 或 document.writeln() 方法的输出。
write()向文档写 HTML 表达式 或 JavaScript 代码。

2.2.4 jsoup概念:

​ jsoup是一个专门为HTML解析而生的工具,提供了丰富解析方案, 一种使用类似于js中原生dom操作的方案 , 一种是类似于jQuery(css选择器)中选择器的方案

2.2.5 jsoup的入门:

  • 第一步: 导包
	<dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.10.3</version>
        </dependency>
  • 第二步: 获取document对象
public class JsoupToDocument {

    public static void main(String[] args) throws IOException {
        //1. 获取document对象:通过url获取document
        //Document document = Jsoup.connect("http://www.itcast.cn").get();
        //1.1. 获取网页的标题
        //String title = document.title();
        //System.out.println(title);

        //2. 获取document: 通过HTML文档获取
       // Document document = Jsoup.parse("<!DOCTYPE html>\n" +
                "<html lang=\"en\">\n" +
                "<head>\n" +
                "    <meta charset=\"UTF-8\">\n" +
                "    <title>黑马程序员</title>\n" +
                "</head>\n" +
                "<body>\n" +
                "\n" +
                "</body>\n" +
                "</html>");

       // String title = document.title();
        //System.out.println(title);
        //3. 通过本地html文件获取document对象
      //  Document document = Jsoup.parse(new File(""), "utf-8");

        //4. 通过html片段获取
       // Document document = Jsoup.parseBodyFragment("<a href='http://www.itcast.cn'>传智博客</a>");
    }

}

总结: 四种

​ 1.通过url路径的方式获取

​ 2.通过HTML文档的形式获取(重点)

​ 3.通过本地HTML文件的形式获取

​ 4.通过HTML片段形式获取

  • 第三步: 解析数据(如何解析document)

    选择器例子例子描述CSS
    .class.intro选择 class=“intro” 的所有元素。1
    #id#firstname选择 id=“firstname” 的所有元素。1
    **选择所有元素。2
    elementp选择所有

    元素。

    1
    element,elementdiv,p选择所有
    元素和所有

    元素。

    1
    element elementdiv p选择
    元素内部的所有

    元素。

    1
    element>elementdiv>p选择父元素为
    元素的所有

    元素。

    2
    element+elementdiv+p选择紧接在
    元素之后的所有

    元素。

    2
    [attribute][target]选择带有 target 属性所有元素。2
    [attribute=value][target=_blank]选择 target="_blank" 的所有元素。2
    [attribute~=value][title~=flower]选择 title 属性包含单词 “flower” 的所有元素。2
    [attribute|=value][lang|=en]选择 lang 属性值以 “en” 开头的所有元素。2
    :linka:link选择所有未被访问的链接。1
    :visiteda:visited选择所有已被访问的链接。1
    :activea:active选择活动链接。1
    :hovera:hover选择鼠标指针位于其上的链接。1
    :focusinput:focus选择获得焦点的 input 元素。2
    :first-letterp:first-letter选择每个

    元素的首字母。

    1
    :first-linep:first-line选择每个

    元素的首行。

    1
    :first-childp:first-child选择属于父元素的第一个子元素的每个

    元素。

    2
    :beforep:before在每个

    元素的内容之前插入内容。

    2
    :afterp:after在每个

    元素的内容之后插入内容。

    2
    :lang(language)p:lang(it)选择带有以 “it” 开头的 lang 属性值的每个

    元素。

    2
    element1~element2p~ul选择前面有

    元素的每个

    • 元素。

    3
    [attribute^=value]a[src^=“https”]选择其 src 属性值以 “https” 开头的每个 元素。3
    [attribute$=value]a[src$=".pdf"]选择其 src 属性以 “.pdf” 结尾的所有 元素。3
    [attribute*=value]a[src*=“abc”]选择其 src 属性中包含 “abc” 子串的每个 元素。3
    :first-of-typep:first-of-type选择属于其父元素的首个

    元素的每个

    元素。

    3
    :last-of-typep:last-of-type选择属于其父元素的最后

    元素的每个

    元素。

    3
    :only-of-typep:only-of-type选择属于其父元素唯一的

    元素的每个

    元素。

    3
    :only-childp:only-child选择属于其父元素的唯一子元素的每个

    元素。

    3
    :nth-child(n)p:nth-child(2)选择属于其父元素的第二个子元素的每个

    元素。

    3
    :nth-last-child(n)p:nth-last-child(2)同上,从最后一个子元素开始计数。3
    :nth-of-type(n)p:nth-of-type(2)选择属于其父元素第二个

    元素的每个

    元素。

    3
    :nth-last-of-type(n)p:nth-last-of-type(2)同上,但是从最后一个子元素开始计数。3
    :last-childp:last-child选择属于其父元素最后一个子元素每个

    元素。

    3
    :root:root选择文档的根元素。3
    :emptyp:empty选择没有子元素的每个

    元素(包括文本节点)。

    3
    :target#news:target选择当前活动的 #news 元素。3
    :enabledinput:enabled选择每个启用的 元素。3
    :disabledinput:disabled选择每个禁用的 元素3
    :checkedinput:checked选择每个被选中的 元素。3
    :not(selector):not§选择非

    元素的每个元素。

    3
    ::selection::selection选择被用户选取的元素部分。3
    • 原生的dom解析(了解)
    public class JsoupToParse {
    
        @Test
        public void jsoupToDomParse() throws IOException {
            //1. 获取document
            Document document = Jsoup.connect("http://www.itcast.cn/subject/cloudzly/index.shtml").get();
    
            //1.1 获取文档的标题
            String title = document.title();
            System.out.println(title);
    
            //1.2
            Elements elements = document.getElementsByClass("head");
            Element element = elements.get(0);
            elements = element.getElementsByClass("inner");
            //System.out.println(elements.size());
            element = elements.get(0);
            Elements lis = element.getElementsByTag("li");
            /*for (Element li : lis) {
                System.out.println(li.);
            }*/
            Elements a = lis.get(0).getElementsByTag("a");
            String text = a.text();
            System.out.println(text);
        }
    }
    
    • 选择器的方案
        //使用jsoup的选择器来解析网页的数据
        @Test
        public void jsoupToSelectParse() throws IOException {
            //1.获取document对象
            Document document = Jsoup.connect("http://www.itcast.cn/subject/cloudzly/index.shtml").get();
    
            //2. 获取标题
            Elements title = document.select("title");
            System.out.println(title.text());
    
            //3. 获取 云计算大数据培训 内容
            //Elements elements = document.select(".head .inner li");
            Elements elements = document.select("body > div.wrap > div.head > div > ul > li:nth-child(1) > a");
            /*Element element = elements.get(0);
            Elements a = element.select("a");*/
            System.out.println(elements.text());
        }
    }
    
        //获取网易新闻的内容
        @Test
        public void jsoupTo163Parse() throws IOException {
            Document document = Jsoup.connect("http://news.163.com/18/0727/08/DNN5HCQU0001875N.html").get();
    
            //1. 解析新闻的标题
            Elements elements = document.select("#epContentLeft");
            Elements h1 = elements.select("h1");
            System.out.println(h1.text());
            //2. 获取新闻的来源
            Elements laiyuan = document.select("#ne_article_source");
    
            System.out.println(laiyuan.text());
            //3. 获取新闻的正文
            Elements ps = document.select("#endText p");
            for (Element p : ps) {
                System.out.println(p.text());
            }
        }
    }
    

2.3 第三大模块: 保存数据

目前采用的保存到mysql数据库中, 以后hadoop, hbase

四种方案:

​ jdbc:

​ dbutils:

​ jdbcTemplate

​ mybatis

3. 案例一:爬起起点中文网的小说

//需求: 爬取起点中文网中任意一个榜单的小说
public class QiDianSprider {

    public static void main(String[] args) throws IOException {
        //1. 确定爬取的url
        String url = "https://www.qidian.com/";

        //2. 发起请求获取数据: httpClient
        //2.1 创建httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        //2.2 创建请求方式: get
        HttpGet httpGet = new HttpGet(url);

        //2.3 发起请求获得响应
        CloseableHttpResponse response = httpClient.execute(httpGet);

        String html = EntityUtils.toString(response.getEntity(), "utf-8");

        //3.解析数据: jsoup
        Document document = Jsoup.parse(html);
        Elements elements = document.select("div[class=rank-list sort-list]");

        Elements lis = elements.select(".book-list ul li");
        //System.out.println(lis.size());
        Elements as = lis.select("a[href^=//book.qidian.com]:not([class=link])");


        for (Element a : as) {
            String href = a.attr("href");
            //   http://book.qidian.com/info/1012284323
            //System.out.println(href);
            //拼接url
            href = "https:" + href;
            //System.out.println(href);
            //重新发起请求, 获取每一个小说页面
            httpClient = HttpClients.createDefault();
            httpGet = new HttpGet(href);
            response = httpClient.execute(httpGet);

            html = EntityUtils.toString(response.getEntity(), "utf-8");

            document = Jsoup.parse(html);

            //解析小说详情页
            elements = document.select("#readBtn");
            href = elements.attr("href");
            //拼接小说内容的url
            href = "https:" + href;
            System.out.println(href);

            while (true) {
                //重新发起请求, 获取每一个小说页面
                httpClient = HttpClients.createDefault();
                httpGet = new HttpGet(href);
                response = httpClient.execute(httpGet);

                html = EntityUtils.toString(response.getEntity(), "utf-8");
                //获取到小说内容页数据
                document = Jsoup.parse(html);

                //获取小说的名称
                elements = document.select(".book-cover-wrap h1");
                System.out.println("小说名称:" + elements.text());
                //获取章节名称
                elements = document.select(".j_chapterName");
                System.out.println("章节名称" + elements.text());
                //获取小说的内容
                elements = document.select("div[class=read-content j_readContent] p");
                for (Element element : elements) {
                    System.out.println(element.text());
                }

                //获取下一章节的url
                elements = document.select("#j_chapterNext");
                href = elements.attr("href");

                if(href==null||href==""||href==" "){
                    System.out.println("跳出本小说内容");
                    break;
                }

                href = "https:" + href;
            }

        }
    }
}

4. 案例二: 模拟登陆

//需求: 模拟登陆, 将登陆后的用户的数据获取到
public class LoginSpider {

    public static void main(String[] args) throws Exception {
        //1.确定url
        String url = "http://www.svn.club/user/login";

        //2. 发起请求, 获取数据
        CloseableHttpClient httpClient = HttpClients.createDefault();
        //3. 创建请求方式: post
        HttpPost httpPost =new HttpPost(url);

        //4. 设置参数
        List<BasicNameValuePair> list = new ArrayList<BasicNameValuePair>();

        list.add(new BasicNameValuePair("uid","itcast"));
        list.add(new BasicNameValuePair("pwd","www.itcast.cn"));
        list.add(new BasicNameValuePair("x","97"));
        list.add(new BasicNameValuePair("y","29"));
        HttpEntity entity = new UrlEncodedFormEntity(list);
        httpPost.setEntity(entity);

        //5. 设置浏览器的类型: 模拟浏览器的
        httpPost.setHeader("User-Agent","Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36");
        //6.发起请求
        CloseableHttpResponse response = httpClient.execute(httpPost);
        
        //7. 获取响应的内容
       // String html = EntityUtils.toString(response.getEntity(), "utf-8");
        //7. 获取状态码
        int statusCode = response.getStatusLine().getStatusCode();
        if(statusCode==302){

            Header[] locations = response.getHeaders("Location");
            Header[] cookies = response.getHeaders("Set-Cookie");

            String reURL = locations[0].getValue();
            String cookie = cookies[0].getValue();
           // System.out.println(reURL);
            //拼接url
            reURL = "http://www.svn.club"+reURL;

            //重新发送请求, 获取登陆后的数据
            httpClient = HttpClients.createDefault();
            HttpGet httpGet = new HttpGet(reURL);

            httpGet.setHeader("Cookie",cookie);
            response = httpClient.execute(httpGet);
            String html = EntityUtils.toString(response.getEntity(), "utf-8");
            Document document = Jsoup.parse(html);
            //System.out.println(document);
            Elements elements = document.select(".tb");
            Element element = elements.get(0);

            Elements trs = element.select("tr");
            Element element1 = trs.get(1);

            String aText = element1.select("td").get(0).select("a").text();
            System.out.println(aText);

        }
    }
}

作业:

1. 演示 jdk发送get和post请求(www.itcast.cn)
2. 演示httpClient发送post请求
3. 寻找一个网页, 进行解析(解析传智博客的科目列表)
4. 将案例一书写(200%)
5. 将案例二写一遍
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

监听员_1379

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值