JD爬虫综合案例
Posted 保护胖丁
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JD爬虫综合案例相关的知识,希望对你有一定的参考价值。
JD爬虫综合案例
一、需求分析
需求说明:
我们要抓取 多页 京东商品详情页的: 商品的名称、商品价格、商品的id、商品图片、商品的详情的地址
通过点击F12观察: 所需要爬取的数据在一下这几个地方
对于商品的详情页: 通过分析发现 , 请详情页的url地址就是通过spu拼接而来的
spu 和 sku的区别说明
-
SPU = Standard Product Unit (标准产品单位)
- SPU是商品信息聚合的最小单位,是一组可复用、易检索的标准化信息的集合,该集合描述了一个产品的特性。通俗点讲,属性值、特性相同的商品就可以称为一个SPU。
- 例如 iPhone X 可以确定一个产品即为一个SPU
-
SKU=stock keeping unit(库存量单位)
- SKU即库存进出计量的单位, 可以是以件、盒、托盘等为单位。SKU是物理上不可分割的最小存货单元。在使用时要根据不同业态,不同管理模式来处理。在服装、鞋类商品中使用最多最普遍。
- 例如 iPhone X 64G 银色 则是一个SKU。
前端常见选择器
- 标签名选择器 : 通过标签名指定标签
h1{ color:red ; background-color:blue }
h2,h3,h4{ color: pink }
- class选择器 : 通过class属性指定标签
定义 -->
.class名{ css代码 }
.abc{color:green}
使用 -->
<h1 class="abc">
- id选择器: 通过为标签添加id属性来指定标签样式
定义 --> #id值{css代码} #p1{ color:orange }
使用 --> <p id="p1">
注意: id属性主要用来在网页里唯一标识一个标签,其次还可以为这个标签指定css样式
- 后代选择器
语法: 选择器1 选择器2{ css代码 }
定义: p h1{ color:red } #d1 .abc h1{ ...... }
作用: 为所有出现在p里的h1标签定义风格样式(包括儿子,孙子,...)
二、项目的准备工作
表结构的准备工作
CREATE DATABASE `jd_spider`;
USE `jd_spider`;
CREATE TABLE `t_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=1116 DEFAULT CHARSET=utf8 COMMENT='京东商品';
更改pom.xml文件
<dependencies>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.4</version>
</dependency>
<!-- 导入jsoup包 -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.11.3</version>
</dependency>
<!-- 导入c3p0连接池包-->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.5</version>
<scope>compile</scope>
</dependency>
<!-- 导入mysql驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
<scope>compile</scope>
</dependency>
<!-- 导入lombok包 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</dependency>
<!-- 导入jsoup包 -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.11.3</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- java编译插件 -->
<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>
三、开发代码
一:配置文件 c3p0-config.xml
<c3p0-config>
<!-- 使用默认的配置读取连接池对象 -->
<default-config>
<!-- 连接参数 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/jd_spider?serverTimezone=UTC</property>
<property name="user">root</property>
<property name="password">****</property>
<!-- 连接池参数 -->
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">10</property>
<property name="checkoutTimeout">3000</property>
</default-config>
</c3p0-config>
二:实体类(使用lombok插件)
package com.itheima.cn.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@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;
}
三、工具类
import com.mchange.v2.c3p0.ComboPooledDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class C3P0Utils {
//定义C3P0连接池对象
private static DataSource 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();
}
}
}
四、dao层
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;
public class ItemDao {
public void saveData(List<Item> list) throws SQLException {
Connection conn = C3P0Utils.getConnection();
String sql = "insert into t_jd_item values(null,?,?,?,?,?,?,?,?)";
PreparedStatement pstm = conn.prepareStatement(sql);
for (Item item : list) {
pstm.setLong(1, item.getSpu());
pstm.setLong(2, item.getSku());
pstm.setString(3, item.getTitle());
pstm.setDouble(4, item.getPrice());
pstm.setString(5, item.getPic());
pstm.setString(6, item.getUrl());
pstm.setString(7, item.getCreated());
pstm.setString(8, item.getUpdated());
int i = pstm.executeUpdate();
if (i==0){
System.out.println("false");
}
}
C3P0Utils.closeAll(null,pstm,conn);
}
}
五、主代码
import com.sun.deploy.ui.DialogTemplate;
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.BufferedInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.UUID;
/*
1.明确url
2.发送请求,获取对象
3.解析数据
4.解析数据,关闭连接
*/
public class jdSpider {
public static void main(String[] args) throws IOException, SQLException {
//2.发送请求,获取对象 固定用法
//2.1创建httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
// 1.明确url
int count = 1;
while (count < 5) {
String indexUrl = "https://search.jd.com/Search?keyword=%E6%89%8B%E6%9C%BA&page=" + (count * 2 - 1) + "&s=1&click=0";
System.out.println("当前爬的是第" + count + "页,地址是:" + indexUrl);
//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/89.0.4389.82 Safari/537.36");
//2.4发送请求,获取对象(response 响应对象)
CloseableHttpResponse httpResponse = httpClient.execute(httpGet);
//2.5我们要获得状态码,然后判断是否是200
int statusCode = httpResponse.getStatusLine().getStatusCode();
//2.5.1判断是否200
ifSuccessDo(httpClient, httpResponse, statusCode);
count++;
}
httpClient.close();
}
private static void ifSuccessDo(CloseableHttpClient httpClient, CloseableHttpResponse httpResponse, int statusCode) throws IOException, SQLException {
if (statusCode == 200) {
//获取响应体对象
HttpEntity entity = httpResponse.getEntity();
//2.6获得一个字符串型的html页面,即具体的页面响应信息
String html = EntityUtils.toString(entity, "UTF-8");
//2.7释放资源
httpResponse.close();
ArrayList<Item> list = new ArrayList<>();
//3.解析数据
//3.1通过Jsoup,将字符串形式是的html,转成对应的document对象
Document document = Jsoup.parse(html);
//System.out.println("document = " + document);
//3.2获取所有的商品信息 通过选择器选择到最小的商品单位
//id="J_goodsList" class="gl-warp clearfix" li class="gl-item
//System.out.println(document.select("#J_goodsList>ul[class=gl-warp clearfix]>li"));
Elements elements = document.select("#J_goodsList>ul[class='gl-warp clearfix']>li");
getJDItem(httpClient, list, elements);
ItemDao itemDao = new ItemDao();
itemDao.saveData(list);
System.out.println("当前页打印了" + list.size() + "件商品");
}
}
private static void getJDItem(CloseableHttpClient httpClient, ArrayList<Item> list, Elements elements) throws IOException {
for (Element li : elements) {
//3.3解析需求
//3.3.1解析spu sku 用attr可以拿到li标签下大的data-spu data-sku
String spu = li.attr("data-spu");
String sku = li.attr("data-sku");
if (spu == null || "".equals(spu)) {
spu = sku;
} else if (sku == null || "".equals(sku)) {
sku = spu;
}
//3.3.2解析标题title 在<em>中
String title = li.select(".gl-i-wrap>div[class='p-name p-name-type-2'] em").text();
// System.out.println("title = " + title);
//3.3.3解析价格
String price = li.select(".p-price i").text();
//System.out.println("price = " + price);
//3.3.4解析商品详情信息
//String url="https://item.jd.com/"+spu+".html";
Elements elements1 = li.select(".p-img>a");
//因为href没有https请求头,所以要补充请求头
String url = "https:" + elements1.attr("href");
//System.out.println("url = " + url);
String pic = getPicItem(httpClient, li);
searchData(list, spu, sku, title, price, url, pic);
}
}
private static String getPicItem(CloseableHttpClient httpClient, Element li) throws IOException {
//3.3.5图片解析
//3.3.5.1拿到图片url
String pic = "https:" + li.select(".p-img img").attr("data-lazy-img");
// System.out.println("pic = " + pic);
//3.3.5.2图片扩展,下载图片到我的电脑
//图片扩展 创建http请求
HttpGet picGet = new HttpGet(pic);
//通过HTTPclient,发送请求获取response
CloseableHttpResponse responsePic = httpClient.execute(picGet);
//判断状态码
if (responsePic.getStatusLine().getStatusCode() == 200) {
//获取图片response的响应流
InputStream is = responsePic.getEntity().getContent();
//用高效缓冲流
BufferedInputStream bis = new BufferedInputStream(is);
//常见输出流,关联目标文件夹
String deastPicPath = "E:/jdimgs/" + UUID.randomUUID() + pic.substring(pic.lastIndexOf("."));
//System.out.println("deastPicPath = " + deastPicPath);
FileOutputStream fos = new FileOutputStream(deastPicPath);
int len;
byte[] buf = new byte[1024];
while ((len = bis.read(buf)) != -1) {
fos.write(buf, 0, len);
}
fos.close();
fos.close();
responsePic.close();
}
return pic;
}
private static void searchData(ArrayList<Item> list, String spu, String sku, String title, String price, String url, String pic) {
// 4.保存数据,关闭连接
Item item = new Item(
null,
Long.parseLong(spu),
Long.parseLong(sku),
title,
Double.parseDouble(price),
pic,
url,
new Date().toLocaleString(),
new Date().toLocaleString());
list.add(item);
}
}
六、效果图
以上是关于JD爬虫综合案例的主要内容,如果未能解决你的问题,请参考以下文章