13-网络爬虫

网络爬虫

简介

  • 什么是爬虫

    • 概述:
      • 爬虫又称为 网络爬虫(Spider), 即: 通过代码的方式, 从互联网中获取相关的数据.
        是一种按照一定规则,自动抓取或下载网络信息的计算机程序或自动化脚本.
      • 指的就是通过代码获取网络中数据的一种技术
      • 网络爬虫实际上是通过模拟浏览器的方式获取服务器数据
  • 爬虫有什么作用?

    • 作用:
      • 爬虫的主要目的 就是从互联网中获取数据
    • 数据有什么作用?
      • 比如说: 获取到大量的用户数据(用户的基本信息, 用户的购物信息)
        能够做什么呢? 做用户分析, 用户的推荐 用户画像构建
      • 比如说: 获取到大量的商品信息数据
        能够做什么呢: 做比价网 分析商品信息 …
        //比价网: www.manmanbuy.com

爬虫的分类

  • 通用网络爬虫:

    • 爬取互联网中所有的信息, 这些信息不局限于网站, 分类 , 主题, 对互联网中所有的数据都感兴趣
    • 那些公司开发这种通用爬虫呢?
      百度 Google 搜索引擎的网站
  • 聚焦网络爬虫 :

    • 又被称为主题爬虫, 主要是用于爬取某一个主题的数据
      目前大多数爬取属于这种聚焦网络爬虫范畴.
  • 增量网络爬虫:

    • 指的爬取那些之前没有爬取的过数据, 随着时间推移, 不断爬取新的数据.
    • 例如:
      • 论坛帖子评论数据的采集(假如评论贴包含400多页,每次启动爬虫时, 只需爬取最近几天用户所发的帖子)
        天气数据的采集;
        新闻数据的采集;
        股票数据的采集等。
  • Deep Web 爬虫: (深度)

    • 这种爬取主要是用于爬取动态网站数据, 或者需要传递参数, 才能获取到数据的爬虫
  • 结论:

    • 在实际开发中, 一般编写爬虫 都是属于聚焦网络爬虫 , 或者是 聚焦网络爬虫 + 增量网络爬虫 + Deep Web 爬虫 的组合体.

爬虫_爬取数据的爬取策略

图解:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QecTWFOd-1669362907817)(F:\BigData\java\图片\day18图片\02-爬虫爬取的策略说明.png)]

爬虫程序的核心步骤:

  1. 明确首页URL.
  2. 发送请求, 获取数据.即:String形式的html页面
    方式1: 原生态JDK的方式, get请求. //了解
    方式2: 原生态JDK的方式, post请求. //了解
    方式3: 模拟浏览器方式, 即: HttpClient对象, get请求. //掌握
    方式4: 模拟浏览器方式, 即: HttpClient对象, post请求. //掌握
  3. 解析数据.
    思路:String形式的HTML页面 -> DOM对象 -> 从DOM对象中解析数据
    Jsoup方式解析, 有4种方式, 掌握第二种. 即: Document dom = Jsoup.parse(String html);
  4. 保存数据.

结论:

“发送请求,获取数据” 这步骤我们一般用 HttpClient方式, 而很少用到原生态的JDK方式, 这是因为:

  1. 原生态的JDK方式 不能设置浏览器请求头, 这样会导致被拦截的几率增大.
  2. 原生态的JDK方式比较偏向底层, 即: 会涉及到大量IO流的读写操作, 相对比较繁琐.

HTTP协议

  • 概述:

    • 超文本传输协议,负责浏览器服务器端 通信的规则(规范).
  • 组成:

    • 请求请求行,请求头,请求体(get方式没有请求体).
    • 响应响应行,响应头,响应体.
get请求方式各部分详解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z3o0rVB5-1669362907818)(F:\BigData\java\图片\day19图片\随堂图片\get方式01.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gvbpP1ZB-1669362907819)(F:\BigData\java\图片\day19图片\随堂图片\get方式02.png)]

post请求方式各部分详解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-raU8ngF4-1669362907819)(F:\BigData\java\图片\day19图片\随堂图片\post方式01.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6APdHMIZ-1669362907819)(F:\BigData\java\图片\day19图片\随堂图片\post方式02.png)]

原生JDK的方式_get请求(了解)
package com.itheima.demo_jdk;

import java.io.BufferedInputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class Demo01 {
    public static void main(String[] args) throws Exception {
        //方式1:原生JDK的方式,get请求            了解
        //1. 明确首页URL.
        String indexUrl = "https://www.jd.com";
        //2. 发送请求, 获取数据.即:String形式的html页面
        //2.1 将URL地址封装成URL对象
        URL url = new URL(indexUrl);

        //2.2 获取连接对象,我们Java代码 和 指定页面的连接对象
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();

        //2.3 设置请求方式,因为默认是get方法,所以可以不用设置
        conn.setRequestMethod("GET");       //请求方式必须大写,否则报错

        //2.4 获取可以读取页面数据的IO流
        InputStream is = conn.getInputStream();
        //BufferedInputStream bis = new BufferedInputStream(is);      //把基本流封装成高效流

        //2.5 具体的IO读写操作,读取页面数据,并打印
        int len;
        byte[] bys = new byte[8192];
        while ((len = is.read(bys)) != -1) {
            String s = new String(bys, 0, len);
            System.out.println(s);
        }

        //2.6 释放资源
        is.close();

        //3. 解析数据.

        //4. 保存数据.
    }
}
原生JDK的方式_post请求(了解)
package com.itheima.demo_jdk;

import java.io.BufferedInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class Demo01 {
    public static void main(String[] args) throws Exception {
        //方式1:原生JDK的方式,get请求            了解
        //1. 明确首页URL.
        String indexUrl = "https://www.jd.com";
        //2. 发送请求, 获取数据.即:String形式的html页面
        //2.1 将URL地址封装成URL对象
        URL url = new URL(indexUrl);

        //2.2 获取连接对象,我们Java代码 和 指定页面的连接对象
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();

        //2.3 设置请求方式,因为默认是get方法,所以可以不用设置
        conn.setRequestMethod("POST");       //请求方式必须大写,否则报错

        //2.4 核心细节:URL默认是禁用输出流的,必须手动开启
        conn.setDoOutput(true);

        //2.5 获取可以往页面写数据的流
        OutputStream os = conn.getOutputStream();

        //2.6 给页面写数据
        os.write("username=admin01&password=pw111".getBytes());

        //2.7 获取可以读取页面数据的IO流
        InputStream is = conn.getInputStream();
        //BufferedInputStream bis = new BufferedInputStream(is);      //把基本流封装成高效流

        //2.8 具体的IO读写操作,读取页面数据,并打印
        int len;
        byte[] bys = new byte[8192];
        while ((len = is.read(bys)) != -1) {
            String s = new String(bys, 0, len);
            System.out.println(s);
        }

        //2.9 释放资源
        is.close();

        //3. 解析数据.

        //4. 保存数据.
    }
}
HttpClient方式_get请求
  • 细节:
    • 因为要使用的HttpClient属于第三方jar包,用之前需要先导包
package com.itheima.demo_jdk;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.InputStream;

public class Demo02 {
    public static void main(String[] args) throws Exception {
        //方式1:模拟浏览器方式, 即: HttpClient对象, get请求
        //1. 明确首页URL.
        //String indexUrl = "https://www.jd.com";     //无请求参数
        String indexUrl = "https://www.jd.com?username=admin01&password=pw123";     //有请求参数

        //2. 发送请求, 获取数据.    即:String形式的html页面
        //2.1 获取HttpClient对象,即:相当于创建了一个浏览器
        CloseableHttpClient httpClient = HttpClients.createDefault();

        //2.2 创建请求方式对象,这里我们先用:HttpGet
        HttpGet httpGet = new HttpGet(indexUrl);

        //2.3 设置请求头,即:模拟何种浏览器
        httpGet.setHeader("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36");

        //2.4 具体的发送请求,获取数据的动作,获取的是响应对象(即:封装的响应行,响应头,响应体数据)
        CloseableHttpResponse response = httpClient.execute(httpGet);

        //2.5 从响应行中获取响应状态码,并判断是否是200,如果是,则表示:响应成功
        if (response.getStatusLine().getStatusCode() == 200) {
            //2.6 获取响应头信息,并打印,注意:实际开发中是按需获取的,一般不获取,这里我写它的目的是,让大家看看代码怎么做
            //2.6.1 获取所有的响应头信息,并打印
            /*Header[] Headers = response.getAllHeaders();
            for (Header header : Headers) {
                System.out.println(header);
            }*/

            //2.6.2 获取指定的响应头信息,并打印
            Header[] headers = response.getHeaders("init-worker-page-maxAge");
            for (Header header : headers) {
                System.out.println(header);
            }
            //2.7 获取具体的响应体对象
            HttpEntity entity = response.getEntity();       //entity才是我们具体要的响应体对象

            //2.8 从响应体中获取具体的数据
            //如果响应体是图片,音频,视频,则要用IO流方式获取
            //InputStream is = entity.getContent();

            //如果响应体是纯字符,可以用 EntityUtils#toString() 工具类方式直接获取
            String html = EntityUtils.toString(entity, "utf-8");

            //2.9 打印获取到的结果,即:字符串形式的HTML页面
            System.out.println(html);
        }


        //2.10 释放资源,即:关闭浏览器对象
        httpClient.close();
        //3. 解析数据.

        //4. 保存数据.
    }
}
HttpClient方式_post请求
package com.itheima.demo_jdk;

import org.apache.http.HttpEntity;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

public class Demo03 {
    public static void main(String[] args) throws Exception {
        //方式1:模拟浏览器方式, 即: HttpClient对象, post请求
        //1. 明确首页URL.
        String indexUrl = "https://www.jd.com";     //无请求参数

        //2. 发送请求, 获取数据.    即:String形式的html页面
        //2.1 获取HttpClient对象,即:相当于创建了一个浏览器
        CloseableHttpClient httpClient = HttpClients.createDefault();

        //2.2 创建请求方式对象,这里我们先用:HttpPost
        HttpPost httpPost = new HttpPost(indexUrl);

        //2.3 设置请求头,即:模拟何种浏览器
        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");

        //2.4 设置请求体
        //2.4.1 创建ArrayList集合,泛型是:请求参数类型
        ArrayList<BasicNameValuePair> list = new ArrayList<>();
        //2.4.2 往集合中添加元素,具体的请求参数对象

        list.add(new BasicNameValuePair("username","admin01"));
        list.add(new BasicNameValuePair("password","pw111"));

        //2.4.3 根据集合元素,将其作为参数,创建具体的请求体对象
        UrlEncodedFormEntity requestEntity = new UrlEncodedFormEntity(list);

        //2.4.4 将获取到的请求体对象,设置到 httpPost请求方式对象中
        httpPost.setEntity(requestEntity);

        //2.5 具体的发送请求,获取数据的动作,获取的是响应对象(即:封装的响应行,响应头,响应体数据)
        CloseableHttpResponse response = httpClient.execute(httpPost);

        //2.6 从响应行中获取响应状态码,并判断是否是200,如果是,则表示:响应成功
        if (response.getStatusLine().getStatusCode() == 200) {
            //2.7 获取响应头信息,并打印,注意:实际开发中是按需获取的,一般不获取,这里我写它的目的是,让大家看看代码怎么做
            //略

            //2.8 获取具体的响应体对象
            HttpEntity entity = response.getEntity();       //entity才是我们具体要的响应体对象

            //2.9 从响应体中获取具体的数据
            //如果响应体是图片,音频,视频,则要用IO流方式获取
            //InputStream is = entity.getContent();

            //如果响应体是纯字符,可以用 EntityUtils#toString() 工具类方式直接获取
            String html = EntityUtils.toString(entity, "utf-8");

            //2.10 打印获取到的结果,即:字符串形式的HTML页面
            System.out.println(html);
        }


        //2.11 释放资源,即:关闭浏览器对象
        httpClient.close();

        //3. 解析数据.

        //4. 保存数据.
    }
}
Jsoup解析数据的四种方式详解
  • 细节:

    1. 我们用Java写爬虫, 如果是页面, 一般的套路是: String形式的HTML页面 -> DOM对象 -> 从DOM对象中解析数据
      2. Jsoup技术:它是专门用来解析HTML页面, 将其封装成对应的 DOM对象的.
      3. Jsoup的作用如下:
      3.1 从一个URL 文件或字符串解析HTML
      3.2 使用DOMCSS选择器 来查找、取出数据;
      3.3 可操作HTML元素、属性、文本
package com.itheima.jsoup;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

import java.io.File;

public class Demo01 {
    public static void main(String[] args) throws Exception{
        //1. 明确首页URL.
        String indexUrl = "https://www.jd.com";
        //2. 发送请求, 获取数据.即:String形式的html页面

        //3. 解析数据.
        //方式1:Jsoup#connect()方式,这种方式可以根据URL直接获取其对应的html页面数据(响应体),并直接封装成dom对象,但是一般只在测试环境中用。
        //它不能设置请求头,即:不能模拟浏览器
        /*Document dom = Jsoup.connect(indexUrl).get();
        System.out.println(dom);*/

        //方式2:通过Jsoup#parse()方式,把String形式的html -> DOM对象
        String html = " <html lang=\"en\">\n" +
                "<head>\n" +
                "    <meta charset=\"UTF-8\">\n" +
                "    <title>首页</title>\n" +
                "</head>\n" +
                "<body>\n" +
                "    <font color=\"red\" size=\"7\" face=\"楷体\">我是字体</font>\n" +
                "    <a href=\"http://www.itcast.cn\">点我有惊喜</a>\n" +
                "</body>\n" +
                "</html>";
        Document dom2 = Jsoup.parse(html);
        System.out.println(dom2.select("font").text());
        //System.out.println(dom2);

        System.out.println("-------------------------");

        //方式3:Jsoup#parse(File对象),解析本地页面,了解
        //Document dom3 = Jsoup.parse(new File("本地页面的路径"), "码表");

        //方式4:Jsoup#parseBodyFragment(String html); 该方式可以被方式2替代,所以也基本没人用
        //Document dom4 = Jsoup.parseBodyFragment("<a href=\"http://www/itcast.cn\">点我有惊喜</a>");
        Document dom4 = Jsoup.parse("<a href=\"http://www/itcast.cn\">点我有惊喜</a>");
        System.out.println(dom4);

        //4. 保存数据.
    }
}
案例:爬取开设的课程名称
package com.itheima.demo_jdk;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class Demo04 {
    public static void main(String[] args) throws Exception{
        //1. 明确首页URL.
        String indexUrl = "http://www.itcast.cn/";
        //2. 发送请求, 获取数据.即:String形式的html页面

        //3. 解析数据.
        //3.1 根据爬取到的页面,将其转成DOM对象
        Document dom = Jsoup.connect(indexUrl).get();

        //3.2 从DOM中匹配到指定的元素
        Elements aEles = dom.select(".ulon>li>a");

        //3.3 遍历,获取到每一个元素对象
        for (Element aEle : aEles) {
            //aEle:就是我们爬取到的每一个a 标签对象,我们只要获取它的文本信息即可
            //System.out.println(aEle.html());    //获取该变迁内的所有信息,包括子标签
            //System.out.println();
            System.out.println(aEle.text());    //获取该变迁内的文本信息
        }
        //4. 保存数据.
    }
}
案例_爬取网易新闻
package com.itheima.demo_jdk;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class Demo04 {
    public static void main(String[] args) throws Exception {
        //1. 明确首页URL.
        String indexUrl = "https://www.163.com/news/article/HMRUBNTP000189FH.html?clickfrom=w_yw";
        //2. 发送请求, 获取数据

        //3. 解析数据.
        //3.1 根据URL,将其转成DOM对象
        Document dom = Jsoup.connect(indexUrl).get();

        //3.2 解析 文章标题 并打印
        String title = dom.select(".post_title").text();
        System.out.println("文章标题: " + title);

        //3.3 解析 文章发布时间 并打印
        String dateAndResource = dom.select(".post_info").text();
        String[] arr = dateAndResource.split(" ");
        System.out.println("文章发布时间: " + arr[0]);

        //3.4 解析 文章来源 并打印
        System.out.println(arr[1].substring(0, arr[1].length() - 3));

        //3.5 解析 文章正文 并打印
        Elements pEles = dom.select(".post_body>p");
        for (Element pEle : pEles) {
            System.out.println(pEle.text());
        }

        //3.6 解析 作者 并打印
        String authorAndSource = dom.select(".post_author").text();
        //本文来源:央视网 责任编辑: 汪丽_NB26155
        //System.out.println(authorAndSource);

        String author = authorAndSource.substring(authorAndSource.indexOf(" ") + 1);
        System.out.println(author);
        //4. 保存数据.
    }
}

爬虫_京东案例

准备动作:

1.建库建表

2.创建Maven工程

3.配置 插件、依赖

4.导入C3P0配置文件

5.导入C3P0Utils工具类

6.导入JavaBean item类

建库建表

CREATE DATABASE `day19_jdspider`;
USE  `day04_jdspider`;
CREATE TABLE `jd_item` (
  `id` BIGINT(10) NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `spu` BIGINT(15) DEFAULT NULL COMMENT '商品集合id',
  `sku` BIGINT(15) DEFAULT NULL COMMENT '商品最小品类单元id',
  `title` VARCHAR(1000) DEFAULT NULL COMMENT '商品标题',
  `price` DOUBLE(10,0) DEFAULT NULL COMMENT '商品价格',
  `pic` VARCHAR(200) DEFAULT NULL COMMENT '商品图片',
  `url` VARCHAR(1500) DEFAULT NULL COMMENT '商品详情地址',
  `created` VARCHAR(100) DEFAULT NULL COMMENT '创建时间',
  `updated` VARCHAR(100) DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`),
  KEY `sku` (`sku`) USING BTREE
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='京东商品';

day19_JDSpider pom.xml 配置 插件、依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <!--Maven的版本模型-->
    <modelVersion>4.0.0</modelVersion>

    <!--当前工程的坐标-->
    <groupId>com.itheima</groupId>
    <artifactId>day19_JDSpider</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!--配置依赖-->
    <dependencies>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.4</version>
        </dependency>
        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.10.3</version>
        </dependency>
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.2</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
            <scope>provided</scope>
        </dependency>

    </dependencies>


    <build>
        <plugins>
            <!--JDK插件,1.8版本-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.2</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>

        </plugins>

    </build>

</project>

导入C3P0配置文件

<c3p0-config>
    <!-- 使用默认的配置读取连接池对象 -->
    <default-config>
        <!--  连接参数 -->
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/day19_jdspider</property>
        <property name="user">root</property>
        <property name="password">root</property>

        <!-- 连接池参数 -->
        <property name="initialPoolSize">5</property>
        <property name="maxPoolSize">10</property>
        <property name="checkoutTimeout">3000</property>
    </default-config>
</c3p0-config>

导入C3P0Utils工具类

package com.itheima.Utils;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class C3P0Utils {

    private static ComboPooledDataSource dataSource = new ComboPooledDataSource();

    private C3P0Utils() {
    }

    public static Connection getConnection() {


        Connection connection = null;
        try {
            connection = dataSource.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }


    @SuppressWarnings("all")
    public static void closeAll(ResultSet resultSet, Statement statement, Connection connection) {
        try {
            if (resultSet != null) {
                resultSet.close();
            }

            if (statement != null) {
                statement.close();
            }

            if (connection != null) {
                connection.close();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}

导入JavaBean item类

package com.itheima.Pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.sql.Date;


@Data
@AllArgsConstructor
@NoArgsConstructor
public class Item {
    //主键
    private Long id;
    //标准产品单位(商品集合)
    private Long spu;
    //库存量单位(最小品类单元)
    private Long sku;
    //商品标题
    private String title;
    //商品价格
    private Double price;
    //商品图片
    private String pic;
    //商品详情地址
    private String url;
    //创建时间
    private String created;
    //更新时间
    private String updated;

}

SELECT UUID(); #随机序列,可以用作订单号,商品编号…

案例:演示随机序列
package com.itheima.demo01_reflect;

import java.util.UUID;

/*
*   案例:演示随机序列
* */
public class Demo01 {
    public static void main(String[] args) {
        //数据源图片的路径
        String pic = "https://img10.360buyimg.com/n7/jfs/t1/62113/8/21801/25588/63293430E6c2f573f/4b90428b88320241.jpg";

        //目的地图片的名词
        //System.out.println(UUID.randomUUID().toString().replace("-",""));      //根据时间的毫秒值等内容生成的一个随机序列,不会重复。
        String desc = UUID.randomUUID().toString().replace("-", "") + pic.substring(pic.lastIndexOf("."));
        System.out.println(desc);
        System.out.println(desc.length());
    }
}
自定义的dao层,负责和数据库交互的
package com.itheima.dao;

import com.itheima.Pojo.Item;
import com.itheima.Utils.C3P0Utils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;

//自定义的dao层,负责和数据库交互的
public class JdDao {

    //目的:把爬取到的每页的手机信息(即:list集合),存储到数据表中
    public void saveItems(ArrayList<Item> list) {
        Connection conn = null;
        PreparedStatement ps = null;
        try {
            //1.获取连接对象
            conn = C3P0Utils.getConnection();
            //2.定义SQL语句
            String sql = "insert into jd_item values(null,?,?,?,?,?,?,?,?);";
            //3.获取可以执行SQL语句的对象
            ps = conn.prepareStatement(sql);
            //4.遍历集合,获取每一个手机对象
            for (Item item : list) {
                //item: 记录的就是每一个手机的信息
                //5.给占位符填充值
                ps.setLong(1, item.getSpu());
                ps.setLong(2, item.getSku());
                ps.setString(3, item.getTitle());
                ps.setDouble(4, item.getPrice());
                ps.setString(5, item.getPic());
                ps.setString(6, item.getUrl());
                ps.setString(7, item.getCreated());
                ps.setString(8, item.getUpdated());
                //6.执行SQL语句,获取结果,但是数据都是我们爬到的,所以这里的结果集不处理也行
                int i = ps.executeUpdate();
                //System.out.println(i > 0 ? "添加成功" : "添加失败");
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            //7.释放资源
            C3P0Utils.closeAll(null, ps, conn);
        }
    }
}
爬取一页数据完毕
package com.itheima.service;

import com.itheima.Pojo.Item;
import com.itheima.dao.JdDao;
import org.apache.http.HttpEntity;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.UUID;

/*
 * 京东商城案例:爬取一页数据
 * */
public class OnePage {
    public static void main(String[] args) throws Exception {
        //1. 明确首页URL.
        String indexUrl = "https://search.jd.com/Search?keyword=%E6%89%8B%E6%9C%BA&wq=%E6%89%8B%E6%9C%BA&pvid=baea0aa59db043589a7537fc92e0a258&page=1&s=1&click=0";

        //2. 发送请求, 获取数据
        //2.1 获取HttpClient对象,即:浏览器对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        //2.2 创建请求方式对象,HttpGet对象
        HttpGet httpGet = new HttpGet(indexUrl);
        //2.3 设置请求头,即:模拟何种浏览器
        httpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Core/1.94.186.400 QQBrowser/11.3.5195.400");
        //2.4 发送请求,获取数据,获取的是具体的响应对象(包含 响应行,响应头,响应体数据)
        CloseableHttpResponse response = httpClient.execute(httpGet);
        //2.5 判断响应状态码是否是200,如果是,表示获取数据成功
        if (response.getStatusLine().getStatusCode() == 200) {
            //2.6 获取响应头信息,并打印,注意:实际开发中是按需获取的,一般不获取,这里我写它的目的是,让大家看看代码怎么做
            HttpEntity entity = response.getEntity();
            //2.7 从响应体对象中,获取具体的数据(String形式的html页面)
            String html = EntityUtils.toString(entity, "utf-8");
            //System.out.println(html);

            //3. 解析数据.
            //3.1 将字符串形式的HTML页面转成其对应的DOM对象
            //3.1.1 将字符串形式的HTML页面转成其对应的DOM对象
            Document dom = Jsoup.parse(html);

            //3.1.2 从DOM对象中获取记录所有手机信息的标签
            //如下两种方式,都可以获取到 30个<li>标签的对象,一个<li>标签 = 一个手机的信息
            Elements liEles = dom.select("ul[class='gl-warp clearfix']>li");
            //Elements liEles = dom.select("#J_goodsList>ul>li");
            //System.out.println(liEles.size());

            //4.1 定义ArrayList<Item>,用来记录爬取到的本页的所有手机(对象)信息
            ArrayList<Item> list = new ArrayList<>();

            //3.1.3 遍历liEles,获取到每一个 liEle对象,即:每一个<li>标签
            for (Element liEle : liEles) {
                //liEle:即一个<li>标签。里边记录的就是 一个手机的全部信息,我们解析它即可
                //3.2 解析 spu 标准产品单位(商品集合)
                String spu = liEle.attr("data-spu");
                //3.3 解析 sku 库存量单位(最小品类单元)
                String sku = liEle.attr("data-sku");
                //细节:保证sku和spu一致
                if (spu == "" || spu == null) {
                    spu = sku;
                }
                /*System.out.println("spu: " + spu);
                System.out.println("sku: " + sku);*/

                //3.4 解析 title 商品标题
                String title = liEle.select("div[class='p-name p-name-type-2'] em").text();
                //System.out.println(title);

                //3.5 解析 price 商品价格
                String price = liEle.select(".p-price i").text();
                //System.out.println(price);

                //3.6 解析 pic 商品图片
                //pic结果:https://img10.360buyimg.com/n7/jfs/t1/62113/8/21801/25588/63293430E6c2f573f/4b90428b88320241.jpg
                String pic = "http:" + liEle.select(".p-img img").attr("data-lazy-img");
                //System.out.println(pic);

                //新需求:下载图片到本地
                //3.6.1 创建请求对象,即:HttpGet对象
                HttpGet pigGet = new HttpGet(pic);
                //3.6.2 发出请求,获取数据,即:响应对象(响应行,头,体)
                //设置请求头
                pigGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Core/1.94.186.400 QQBrowser/11.3.5195.400");
                //发出请求,获取数据
                CloseableHttpResponse picResponse = httpClient.execute(pigGet);
                //3.6.3 判断响应状态码,如果是200,表示响应成功
                if (picResponse.getStatusLine().getStatusCode() == 200) {
                    //3.6.4 从响应对应中获取具体的响应体对象
                    HttpEntity picEntity = picResponse.getEntity();
                    //3.6.5 从响应体对象中,获取具体的数据,因为响应体对象是图片,所以我们获取:输入流,可以读取图片的信息
                    InputStream is = picEntity.getContent();
                    //3.6.6 生成:本地图片文件的名称
                    String desc = UUID.randomUUID().toString().replace("-", "") + pic.substring(pic.lastIndexOf("."));
                    //3.6.7 获取输出流,关联本地路径,即:把图片保存到哪里
                    FileOutputStream fos = new FileOutputStream("D:\\IdeaProjects\\javaSE\\day19_JDSpider\\src\\main\\java\\com\\itheima\\JDimage/" + desc);
                    //3.6.8 具体的IO流读写操作
                    byte[] bys = new byte[8192];
                    int len;
                    while ((len = is.read(bys)) != -1) {
                        fos.write(bys, 0, len);
                    }
                    //3.6.9 释放资源
                    fos.close();
                    is.close();
                }


                //3.7 解析 url 商品详情地址
                //方式1:自己爬
                //String url = "http:" + liEle.select("div[class='p-name p-name-type-2'] a").attr("href");

                //方式2:拼接
                String url = "https://item.jd.com/" + sku + ".html";
                //System.out.println(url);

                //3.8 解析 created 创建时间
                String created = new Date().toLocaleString();

                //3.9 解析 updated 更新时间
                String updated = new Date().toLocaleString();

                //3.10 将上述解析到的所有对象封装成JavaBean对象,一个JavaBean对象 = 一个手机
                Item item = new Item(
                        null,
                        Long.parseLong(spu),
                        Long.parseLong(sku),
                        title,
                        Double.parseDouble(price),
                        pic,
                        url,
                        created,
                        updated

                );
                /*System.out.println(item);
                System.out.println();*/

                //4.2 把本业爬取到的每一个手机对象添加到集合中
                list.add(item);

            }   //本页的每一个手机信息爬取完毕

            //4.3 调用dao层的 JdDao#saveItems(ArrayList<Item> list)方法,存储集合数据到 Mysql数据库中
            //System.out.println(list.size());
            new JdDao().saveItems(list);


        }   //本页所有的数据操作完毕

        //2.8 释放资源
        httpClient.close();

        //4. 保存数据.

    }
}
爬取多页数据
package com.itheima.service;

import com.itheima.Pojo.Item;
import com.itheima.dao.JdDao;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.UUID;

/*
 * 京东商城案例:爬取一页数据
 * */
public class MorePage {
    public static void main(String[] args) throws Exception {
        //5.把目前的代码改造成:爬取多页的数据
        //5.1 定义变量,记录当前的页数
        int page = 1;


        //2. 发送请求, 获取数据
        //2.1 获取HttpClient对象,即:浏览器对象
        CloseableHttpClient httpClient = HttpClients.createDefault();


        String indexUrl = null;
        //5.2 循环爬取多页的数据,用while循环
        while (page <= 50) {
            Thread.sleep(50);
            //爬取一页数据从这里开始
            //1. 明确首页URL. 需要修改它的格式
            indexUrl = "https://search.jd.com/Search?keyword=%E6%89%8B%E6%9C%BA&wq=%E6%89%8B%E6%9C%BA&pvid=baea0aa59db043589a7537fc92e0a258&page=" + (2 * page - 1) + "&s=1&click=0";

            //5.4 为了看清楚执行到哪里了,我们加入一些提示信息,这里是提示:当前页的URL路径
            System.out.println("********** 当前正在爬取第 " + page + "页的数据 **********");
            System.out.println("路径是: " + indexUrl);

            //2.2 创建请求方式对象,HttpGet对象
            HttpGet httpGet = new HttpGet(indexUrl);
            //2.3 设置请求头,即:模拟何种浏览器
            httpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Core/1.94.186.400 QQBrowser/11.3.5195.400");
            //2.4 发送请求,获取数据,获取的是具体的响应对象(包含 响应行,响应头,响应体数据)
            CloseableHttpResponse response = httpClient.execute(httpGet);
            //2.5 判断响应状态码是否是200,如果是,表示获取数据成功
            if (response.getStatusLine().getStatusCode() == 200) {
                //2.6 获取响应头信息,并打印,注意:实际开发中是按需获取的,一般不获取,这里我写它的目的是,让大家看看代码怎么做
                HttpEntity entity = response.getEntity();
                //2.7 从响应体对象中,获取具体的数据(String形式的html页面)
                String html = EntityUtils.toString(entity, "utf-8");
                //System.out.println(html);

                //3. 解析数据.
                //3.1 将字符串形式的HTML页面转成其对应的DOM对象
                //3.1.1 将字符串形式的HTML页面转成其对应的DOM对象
                Document dom = Jsoup.parse(html);

                //3.1.2 从DOM对象中获取记录所有手机信息的标签
                //如下两种方式,都可以获取到 30个<li>标签的对象,一个<li>标签 = 一个手机的信息
                Elements liEles = dom.select("ul[class='gl-warp clearfix']>li");
                //Elements liEles = dom.select("#J_goodsList>ul>li");
                //System.out.println(liEles.size());

                //4.1 定义ArrayList<Item>,用来记录爬取到的本页的所有手机(对象)信息
                ArrayList<Item> list = new ArrayList<>();

                //3.1.3 遍历liEles,获取到每一个 liEle对象,即:每一个<li>标签
                for (Element liEle : liEles) {
                    //liEle:即一个<li>标签。里边记录的就是 一个手机的全部信息,我们解析它即可
                    //3.2 解析 spu 标准产品单位(商品集合)
                    String spu = liEle.attr("data-spu");
                    //3.3 解析 sku 库存量单位(最小品类单元)
                    String sku = liEle.attr("data-sku");
                    //细节:保证sku和spu一致
                    if (spu == "" || spu == null) {
                        spu = sku;
                    }
                /*System.out.println("spu: " + spu);
                System.out.println("sku: " + sku);*/

                    //3.4 解析 title 商品标题
                    String title = liEle.select("div[class='p-name p-name-type-2'] em").text();
                    //System.out.println(title);

                    //3.5 解析 price 商品价格
                    String price = liEle.select(".p-price i").text();
                    //System.out.println(price);

                    //3.6 解析 pic 商品图片
                    //pic结果:https://img10.360buyimg.com/n7/jfs/t1/62113/8/21801/25588/63293430E6c2f573f/4b90428b88320241.jpg
                    String pic = "http:" + liEle.select(".p-img img").attr("data-lazy-img");
                    //System.out.println(pic);

                    //新需求:下载图片到本地
                    //3.6.1 创建请求对象,即:HttpGet对象
                    HttpGet pigGet = new HttpGet(pic);
                    //3.6.2 发出请求,获取数据,即:响应对象(响应行,头,体)
                    //设置请求头
                    pigGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Core/1.94.186.400 QQBrowser/11.3.5195.400");
                    //发出请求,获取数据
                    CloseableHttpResponse picResponse = httpClient.execute(pigGet);
                    //3.6.3 判断响应状态码,如果是200,表示响应成功
                    if (picResponse.getStatusLine().getStatusCode() == 200) {
                        //3.6.4 从响应对应中获取具体的响应体对象
                        HttpEntity picEntity = picResponse.getEntity();
                        //3.6.5 从响应体对象中,获取具体的数据,因为响应体对象是图片,所以我们获取:输入流,可以读取图片的信息
                        InputStream is = picEntity.getContent();
                        //3.6.6 生成:本地图片文件的名称
                        String desc = UUID.randomUUID().toString().replace("-", "") + pic.substring(pic.lastIndexOf("."));
                        //3.6.7 获取输出流,关联本地路径,即:把图片保存到哪里
                        FileOutputStream fos = new FileOutputStream("D:\\IdeaProjects\\javaSE\\day19_JDSpider\\src\\main\\java\\com\\itheima\\JDimage/" + desc);
                        //3.6.8 具体的IO流读写操作
                        byte[] bys = new byte[8192];
                        int len;
                        while ((len = is.read(bys)) != -1) {
                            fos.write(bys, 0, len);
                        }
                        //3.6.9 释放资源
                        fos.close();
                        is.close();
                    }


                    //3.7 解析 url 商品详情地址
                    //方式1:自己爬
                    //String url = "http:" + liEle.select("div[class='p-name p-name-type-2'] a").attr("href");

                    //方式2:拼接
                    String url = "https://item.jd.com/" + sku + ".html";
                    //System.out.println(url);

                    //3.8 解析 created 创建时间
                    String created = new Date().toLocaleString();

                    //3.9 解析 updated 更新时间
                    String updated = new Date().toLocaleString();

                    //3.10 将上述解析到的所有对象封装成JavaBean对象,一个JavaBean对象 = 一个手机
                    Item item = new Item(
                            null,
                            Long.parseLong(spu),
                            Long.parseLong(sku),
                            title,
                            Double.parseDouble(price),
                            pic,
                            url,
                            created,
                            updated

                    );
                /*System.out.println(item);
                System.out.println();*/

                    //4.2 把本业爬取到的每一个手机对象添加到集合中
                    list.add(item);

                }   //本页的每一个手机信息爬取完毕

                //5.4 为了看清楚执行到哪里了,我们加入一些提示信息,这里是提示:当前页爬取到的数据条数
                System.out.println("本页爬取到的数据条数是:" + list.size());

                //4. 保存数据.
                //4.3 调用dao层的 JdDao#saveItems(ArrayList<Item> list)方法,存储集合数据到 Mysql数据库中
                //System.out.println(list.size());
                new JdDao().saveItems(list);


            }   //本页所有的数据操作完毕,即:爬取一页数据从这里结束

            //5.4 为了看清楚执行到哪里了,我们加入一些提示信息,这里是提示:当前页爬取到的数据条数
            System.out.println("*****************本页数据爬取完毕*****************\r\n");

            //5.3 修改url链接,改为下一页的数据,因为循环第一行是:获取每页的URL路径的,所以我们只要让页码++即可
            page++;

        }//所有页的数据全部爬取完毕

        //2.8 释放资源
        httpClient.close();

    }
}
抽取方法
package com.itheima.service;

import com.itheima.Pojo.Item;
import com.itheima.dao.JdDao;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.UUID;

/*
 * 京东商城案例:爬取一页数据
 * */
public class MorePage_Method {
    public static void main(String[] args) throws Exception {
        //5.把目前的代码改造成:爬取多页的数据
        //5.1 定义变量,记录当前的页数
        int page = 1;


        //2. 发送请求, 获取数据
        //2.1 获取HttpClient对象,即:浏览器对象
        CloseableHttpClient httpClient = HttpClients.createDefault();


        String indexUrl = null;
        //5.2 循环爬取多页的数据,用while循环
        while (page <= 50) {
            //Thread.sleep(50);

            //1. 明确首页URL. 需要修改它的格式
            indexUrl = "https://search.jd.com/Search?keyword=%E6%89%8B%E6%9C%BA&wq=%E6%89%8B%E6%9C%BA&pvid=baea0aa59db043589a7537fc92e0a258&page=" + (2 * page - 1) + "&s=1&click=0";

            //5.4 为了看清楚执行到哪里了,我们加入一些提示信息,这里是提示:当前页的URL路径
            System.out.println("********** 当前正在爬取第 " + page + "页的数据 **********");
            System.out.println("路径是: " + indexUrl);


            //爬取一页数据从这里开始
            getOnePage(httpClient, indexUrl);

            //5.4 为了看清楚执行到哪里了,我们加入一些提示信息,这里是提示:当前页爬取到的数据条数
            System.out.println("*****************本页数据爬取完毕*****************\r\n");

            //5.3 修改url链接,改为下一页的数据,因为循环第一行是:获取每页的URL路径的,所以我们只要让页码++即可
            page++;

        }//所有页的数据全部爬取完毕

        //2.8 释放资源
        httpClient.close();

    }

    //具体的爬取一页数据的操作
    private static void getOnePage(CloseableHttpClient httpClient, String indexUrl) throws IOException {
        //2.2 创建请求方式对象,HttpGet对象
        HttpGet httpGet = new HttpGet(indexUrl);
        //2.3 设置请求头,即:模拟何种浏览器
        httpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Core/1.94.186.400 QQBrowser/11.3.5195.400");
        //2.4 发送请求,获取数据,获取的是具体的响应对象(包含 响应行,响应头,响应体数据)
        CloseableHttpResponse response = httpClient.execute(httpGet);
        //2.5 判断响应状态码是否是200,如果是,表示获取数据成功
        if (response.getStatusLine().getStatusCode() == 200) {
            //2.6 获取响应头信息,并打印,注意:实际开发中是按需获取的,一般不获取,这里我写它的目的是,让大家看看代码怎么做
            HttpEntity entity = response.getEntity();
            //2.7 从响应体对象中,获取具体的数据(String形式的html页面)
            String html = EntityUtils.toString(entity, "utf-8");
            //System.out.println(html);

            //3. 解析数据.
            //3.1 将字符串形式的HTML页面转成其对应的DOM对象
            //3.1.1 将字符串形式的HTML页面转成其对应的DOM对象
            Document dom = Jsoup.parse(html);

            //3.1.2 从DOM对象中获取记录所有手机信息的标签
            //如下两种方式,都可以获取到 30个<li>标签的对象,一个<li>标签 = 一个手机的信息
            Elements liEles = dom.select("ul[class='gl-warp clearfix']>li");
            //Elements liEles = dom.select("#J_goodsList>ul>li");
            //System.out.println(liEles.size());

            //4.1 定义ArrayList<Item>,用来记录爬取到的本页的所有手机(对象)信息
            ArrayList<Item> list = new ArrayList<>();

            //3.1.3 遍历liEles,获取到每一个 liEle对象,即:每一个<li>标签
            for (Element liEle : liEles) {
                //liEle:即一个<li>标签。里边记录的就是 一个手机的全部信息,我们解析它即可


                Item item = getItem(httpClient, liEle);
            /*System.out.println(item);
            System.out.println();*/

                //4.2 把本业爬取到的每一个手机对象添加到集合中
                list.add(item);

            }   //本页的每一个手机信息爬取完毕

            //5.4 为了看清楚执行到哪里了,我们加入一些提示信息,这里是提示:当前页爬取到的数据条数
            System.out.println("本页爬取到的数据条数是:" + list.size());

            //4. 保存数据.
            //4.3 调用dao层的 JdDao#saveItems(ArrayList<Item> list)方法,存储集合数据到 Mysql数据库中
            //System.out.println(list.size());
            new JdDao().saveItems(list);


        }   //本页所有的数据操作完毕,即:爬取一页数据从这里结束
    }

    //具体的解析一个手机信息的逻辑
    private static Item getItem(CloseableHttpClient httpClient, Element liEle) throws IOException {
        //3.2 解析 spu 标准产品单位(商品集合)
        String spu = liEle.attr("data-spu");
        //3.3 解析 sku 库存量单位(最小品类单元)
        String sku = liEle.attr("data-sku");
        //细节:保证sku和spu一致
        if (spu == "" || spu == null) {
            spu = sku;
        }
                /*System.out.println("spu: " + spu);
                System.out.println("sku: " + sku);*/

        //3.4 解析 title 商品标题
        String title = liEle.select("div[class='p-name p-name-type-2'] em").text();
        //System.out.println(title);

        //3.5 解析 price 商品价格
        String price = liEle.select(".p-price i").text();
        //System.out.println(price);

        //3.6 解析 pic 商品图片
        //pic结果:https://img10.360buyimg.com/n7/jfs/t1/62113/8/21801/25588/63293430E6c2f573f/4b90428b88320241.jpg
        String pic = "http:" + liEle.select(".p-img img").attr("data-lazy-img");
        //System.out.println(pic);

        //新需求:下载图片到本地
        downloadPic(httpClient, pic);


        //3.7 解析 url 商品详情地址
        //方式1:自己爬
        //String url = "http:" + liEle.select("div[class='p-name p-name-type-2'] a").attr("href");

        //方式2:拼接
        String url = "https://item.jd.com/" + sku + ".html";
        //System.out.println(url);

        //3.8 解析 created 创建时间
        String created = new Date().toLocaleString();

        //3.9 解析 updated 更新时间
        String updated = new Date().toLocaleString();

        //3.10 将上述解析到的所有对象封装成JavaBean对象,一个JavaBean对象 = 一个手机
        Item item = new Item(
                null,
                Long.parseLong(spu),
                Long.parseLong(sku),
                title,
                Double.parseDouble(price),
                pic,
                url,
                created,
                updated

        );
        return item;
    }

    //下载图片
    private static void downloadPic(CloseableHttpClient httpClient, String pic) throws IOException {
        //3.6.1 创建请求对象,即:HttpGet对象
        HttpGet pigGet = new HttpGet(pic);
        //3.6.2 发出请求,获取数据,即:响应对象(响应行,头,体)
        //设置请求头
        pigGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Core/1.94.186.400 QQBrowser/11.3.5195.400");
        //发出请求,获取数据
        CloseableHttpResponse picResponse = httpClient.execute(pigGet);
        //3.6.3 判断响应状态码,如果是200,表示响应成功
        if (picResponse.getStatusLine().getStatusCode() == 200) {
            //3.6.4 从响应对应中获取具体的响应体对象
            HttpEntity picEntity = picResponse.getEntity();
            //3.6.5 从响应体对象中,获取具体的数据,因为响应体对象是图片,所以我们获取:输入流,可以读取图片的信息
            InputStream is = picEntity.getContent();
            //3.6.6 生成:本地图片文件的名称
            String desc = UUID.randomUUID().toString().replace("-", "") + pic.substring(pic.lastIndexOf("."));
            //3.6.7 获取输出流,关联本地路径,即:把图片保存到哪里
            FileOutputStream fos = new FileOutputStream("D:\\IdeaProjects\\javaSE\\day19_JDSpider\\src\\main\\java\\com\\itheima\\JDimage/" + desc);
            //3.6.8 具体的IO流读写操作
            byte[] bys = new byte[8192];
            int len;
            while ((len = is.read(bys)) != -1) {
                fos.write(bys, 0, len);
            }
            //3.6.9 释放资源
            fos.close();
            is.close();
        }
    }
}

/3.6.1 创建请求对象,即:HttpGet对象
HttpGet pigGet = new HttpGet(pic);
//3.6.2 发出请求,获取数据,即:响应对象(响应行,头,体)
//设置请求头
pigGet.setHeader(“User-Agent”, “Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Core/1.94.186.400 QQBrowser/11.3.5195.400”);
//发出请求,获取数据
CloseableHttpResponse picResponse = httpClient.execute(pigGet);
//3.6.3 判断响应状态码,如果是200,表示响应成功
if (picResponse.getStatusLine().getStatusCode() == 200) {
//3.6.4 从响应对应中获取具体的响应体对象
HttpEntity picEntity = picResponse.getEntity();
//3.6.5 从响应体对象中,获取具体的数据,因为响应体对象是图片,所以我们获取:输入流,可以读取图片的信息
InputStream is = picEntity.getContent();
//3.6.6 生成:本地图片文件的名称
String desc = UUID.randomUUID().toString().replace(“-”, “”) + pic.substring(pic.lastIndexOf(“.”));
//3.6.7 获取输出流,关联本地路径,即:把图片保存到哪里
FileOutputStream fos = new FileOutputStream(“D:\IdeaProjects\javaSE\day19_JDSpider\src\main\java\com\itheima\JDimage/” + desc);
//3.6.8 具体的IO流读写操作
byte[] bys = new byte[8192];
int len;
while ((len = is.read(bys)) != -1) {
fos.write(bys, 0, len);
}
//3.6.9 释放资源
fos.close();
is.close();
}
}
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值