网络爬虫
简介
-
什么是爬虫:
- 概述:
- 爬虫又称为 网络爬虫(Spider), 即: 通过代码的方式, 从互联网中获取相关的数据.
是一种按照一定规则,自动抓取或下载网络信息的计算机程序或自动化脚本. - 指的就是通过代码获取网络中数据的一种技术
- 网络爬虫实际上是通过模拟浏览器的方式获取服务器数据
- 爬虫又称为 网络爬虫(Spider), 即: 通过代码的方式, 从互联网中获取相关的数据.
- 概述:
-
爬虫有什么作用?
- 作用:
- 爬虫的主要目的 就是从互联网中获取数据
- 数据有什么作用?
- 比如说: 获取到大量的用户数据(用户的基本信息, 用户的购物信息)
能够做什么呢? 做用户分析, 用户的推荐 用户画像构建 - 比如说: 获取到大量的商品信息数据
能够做什么呢: 做比价网 分析商品信息 …
//比价网: www.manmanbuy.com
- 比如说: 获取到大量的用户数据(用户的基本信息, 用户的购物信息)
- 作用:
爬虫的分类
-
通用网络爬虫:
- 爬取互联网中所有的信息, 这些信息不局限于网站, 分类 , 主题, 对互联网中所有的数据都感兴趣
- 那些公司开发这种通用爬虫呢?
百度 Google 搜索引擎的网站
-
聚焦网络爬虫 :
- 又被称为主题爬虫, 主要是用于爬取某一个主题的数据
目前大多数爬取属于这种聚焦网络爬虫范畴.
- 又被称为主题爬虫, 主要是用于爬取某一个主题的数据
-
增量网络爬虫:
- 指的爬取那些之前没有爬取的过数据, 随着时间推移, 不断爬取新的数据.
- 例如:
- 论坛帖子评论数据的采集(假如评论贴包含400多页,每次启动爬虫时, 只需爬取最近几天用户所发的帖子)
天气数据的采集;
新闻数据的采集;
股票数据的采集等。
- 论坛帖子评论数据的采集(假如评论贴包含400多页,每次启动爬虫时, 只需爬取最近几天用户所发的帖子)
-
Deep Web 爬虫: (深度)
- 这种爬取主要是用于爬取动态网站数据, 或者需要传递参数, 才能获取到数据的爬虫
-
结论:
- 在实际开发中, 一般编写爬虫 都是属于聚焦网络爬虫 , 或者是 聚焦网络爬虫 + 增量网络爬虫 + Deep Web 爬虫 的组合体.
爬虫_爬取数据的爬取策略
图解:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QecTWFOd-1669362907817)(F:\BigData\java\图片\day18图片\02-爬虫爬取的策略说明.png)]
爬虫程序的核心步骤:
- 明确首页URL.
- 发送请求, 获取数据.即:String形式的html页面
方式1: 原生态JDK的方式, get请求. //了解
方式2: 原生态JDK的方式, post请求. //了解
方式3: 模拟浏览器方式, 即: HttpClient对象, get请求. //掌握
方式4: 模拟浏览器方式, 即: HttpClient对象, post请求. //掌握 - 解析数据.
思路:String形式的HTML页面 -> DOM对象 -> 从DOM对象中解析数据
Jsoup方式解析, 有4种方式, 掌握第二种. 即: Document dom = Jsoup.parse(String html); - 保存数据.
结论:
“发送请求,获取数据” 这步骤我们一般用 HttpClient方式, 而很少用到原生态的JDK方式, 这是因为:
- 原生态的JDK方式 不能设置浏览器请求头, 这样会导致被拦截的几率增大.
- 原生态的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解析数据的四种方式详解
-
细节:
- 我们用Java写爬虫, 如果是页面, 一般的套路是: String形式的HTML页面 -> DOM对象 -> 从DOM对象中解析数据
2. Jsoup技术:它是专门用来解析HTML页面, 将其封装成对应的 DOM对象的.
3. Jsoup的作用如下:
3.1 从一个URL 文件或字符串中 解析HTML;
3.2 使用DOM或CSS选择器 来查找、取出数据;
3.3 可操作HTML元素、属性、文本;
- 我们用Java写爬虫, 如果是页面, 一般的套路是: String形式的HTML页面 -> DOM对象 -> 从DOM对象中解析数据
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();
}
}
}