java爬虫

爬虫的基本概念:

​ 什么是爬虫

​ 爬虫的价值

​ 爬虫的分类

​ 通用的爬虫

​ 垂直的爬虫

​ 爬虫的基本原理

爬虫的三大模块:

​ 获取数据

​ 解析数据

​ 保存数据

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

案例二: 使用爬虫程序登录某个网站, 获取此用户下的信息

1. 爬虫的基本概念

1.1 什么是爬虫:

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

1.2 爬虫的价值:

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

1.3 爬虫的分类:

1.3.1 通用的爬虫:

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

1.3.2 垂直爬虫:

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

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

1.4 爬虫的基本原理

爬虫基本原理:

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.httpcomponentsgroupId>
            <artifactId>httpclientartifactId>
            <version>4.5.4version>
        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 list = new ArrayList();
        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的入门:

  • 第一步: 导包
	
            org.jsoup
            jsoup
            1.10.3
        
  • 第二步: 获取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("\n" +
                "\n" +
                "\n" +
                "    \n" +
                "    黑马程序员\n" +
                "\n" +
                "\n" +
                "\n" +
                "\n" +
                "");

       // 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("传智博客");
    }

}

总结: 四种

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

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

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

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

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

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

    元素。

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

    元素。

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

    元素。

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

    元素。

    2
    element+element div+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
    :link a:link 选择所有未被访问的链接。 1
    :visited a:visited 选择所有已被访问的链接。 1
    :active a:active 选择活动链接。 1
    :hover a:hover 选择鼠标指针位于其上的链接。 1
    :focus input:focus 选择获得焦点的 input 元素。 2
    :first-letter p:first-letter 选择每个

    元素的首字母。

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

    元素的首行。

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

    元素。

    2
    :before p:before 在每个

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

    2
    :after p:after 在每个

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

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

    元素。

    2
    element1~element2 p~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-type p:first-of-type 选择属于其父元素的首个

    元素的每个

    元素。

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

    元素的每个

    元素。

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

    元素的每个

    元素。

    3
    :only-child p: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-child p:last-child 选择属于其父元素最后一个子元素每个

    元素。

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

    元素(包括文本节点)。

    3
    :target #news:target 选择当前活动的 #news 元素。 3
    :enabled input:enabled 选择每个启用的 元素。 3
    :disabled input:disabled 选择每个禁用的 元素 3
    :checked input: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. 将案例二写一遍

你可能感兴趣的:(爬虫,爬虫)