7

使用HttpClient+Jsoup实现网络爬虫抓取京东商品数据信息

 1 year ago
source link: https://blog.51cto.com/chencoding/5681899
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

HttpClient+Jsoup实现网络爬虫抓取京东商品数据信息

        <!--SpringMVC-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--SpringData Jpa-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!--MySQL连接包-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>
        <!-- HttpClient -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
        </dependency>
        <!--Jsoup-->
        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
             <version>1.15.2</version>
        </dependency>
         <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

配置application.properties

# MySQL配置
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=123456


# JPA配置
spring.jpa.database=MySQL
spring.jpa.show-sql=true
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.ImprovedNamingStrategy

@Entity
@Table(name = "item")
@Data
public class Item {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    //标准产品单位
    private Long spu;
    //库存量单位
    private Long sku;
    //商品标题
    private String title;
    //商品价格
    private Double price;
    //商品图片
    private String pic;
    //商品详情地址
    private String url;
    //店铺;
    private String shop;
    //创建时间
    private Date created;
    //更新时间
    private Date updated;
}
public interface ItemDao extends JpaRepository<Item,Long> {
}

Service

public interface ItemService {

    /**
     * 保存商品
     *
     * @param item
     */
    void save(Item item);

    /**
     * 删除所有商品
     */
    void deleteAll();
}


@Service
public class ItemServiceImpl implements ItemService {

    @Autowired
    private ItemDao itemDao;

    @Override
    @Transactional
    public void save(Item item) {
        this.itemDao.save(item);
    }

    @Override
    public void deleteAll() {
        this.itemDao.deleteAll();
    }
}

封装HttpClient

@Component
public class HttpUtils {

    private static final String FILEPATH = "D:\\demo\\";

    private PoolingHttpClientConnectionManager cm;

    public HttpUtils() {
        this.cm = new PoolingHttpClientConnectionManager();
        //设置最大连接数
        this.cm.setMaxTotal(100);
        //设置每个主机的最大连接数
        this.cm.setDefaultMaxPerRoute(10);
    }

    /**
     * 根据请求地址下载页面数据
     *
     * @param url
     * @return 页面数据
     */
    public String doGetHtml(String url) {
        //获取HttpClient对象
        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(this.cm).build();
        //创建httpGet请求对象,设置url地址
        HttpGet httpGet = new HttpGet(url);
        httpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36");
        //设置请求信息
        httpGet.setConfig(this.getConfig());
        CloseableHttpResponse response = null;
        try {
            //使用HttpClient发起请求,获取响应
            response = httpClient.execute(httpGet);
            //解析响应,返回结果
            if (response.getStatusLine().getStatusCode() == 200) {
                //判断响应体Entity是否不为空,如果不为空就可以使用EntityUtils
                if (response.getEntity() != null) {
                    String content = EntityUtils.toString(response.getEntity(), "utf8");
                    return content;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭response
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        //返回空串
        return "";
    }


    /**
     * 下载图片
     *
     * @param url
     * @return 图片名称
     */
    public String doGetImage(String url) {
        //获取HttpClient对象
        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(this.cm).build();
        //创建httpGet请求对象,设置url地址
        HttpGet httpGet = new HttpGet(url);
        //设置请求信息
        httpGet.setConfig(this.getConfig());
        CloseableHttpResponse response = null;
        try {
            //使用HttpClient发起请求,获取响应
            response = httpClient.execute(httpGet);
            //解析响应,返回结果
            if (response.getStatusLine().getStatusCode() == 200) {
                //判断响应体Entity是否不为空
                if (response.getEntity() != null) {
                    //获取图片的后缀
                    String extName = url.substring(url.lastIndexOf("."));
                    //创建图片名,重命名图片
                    String picName = UUID.randomUUID() + extName;
                    //声明OutPutStream
                    OutputStream outputStream = new FileOutputStream(new File(FILEPATH + picName));
                    response.getEntity().writeTo(outputStream);
                    //返回图片名称
                    return picName;
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭response
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        //如果下载失败,返回空串
        return "";
    }

    /**
     * 设置请求信息
     *
     * @return
     */
    private RequestConfig getConfig() {
        RequestConfig config = RequestConfig.custom()
                //创建连接的最长时间
                .setConnectTimeout(1000)
                // 获取连接的最长时间
                .setConnectionRequestTimeout(500)
                //数据传输的最长时间
                .setSocketTimeout(10000)
                .build();

        return config;
    }
}

SPU与SKU

SPU

SPU是商品信息聚合的最小单位,是一组可复用、易检索的标准化信息的集合,该集合描述了一个产品的特性。

属性值、特性相同的商品就可以称为一个SPU。

如:某型号某配置某颜色的笔记本电脑就对应一个SPU,它有多种配置,或者多种颜色

SKU

SKU即库存进出计量的单位, 可以是以件、盒、托盘等为单位。SKU是物理上不可分割的最小存货单元。在使用时要根据不同业态,不同管理模式来处理。

如:某型号的笔记本电脑有多种配置,8G+512G笔记本电脑就是一个SKU。

爬取笔记本电脑搜索页面。进行分页操作,得到分页请求地址:https://search.jd.com/search?keyword=%E7%94%B5%E8%84%91&wq=%E7%94%B5%E8%84%91&pvid=56a110735c6c491c91416c194aed4c5b&cid3=672&cid2=671&s=56&click=0&page=

使用HttpClient+Jsoup实现网络爬虫抓取京东商品数据信息_Jsoup

所有商品由一个class=J_goodsList的div包裹。div中则是由ul标签包裹的li标签,每一个li标签对应一个商品信息。

使用HttpClient+Jsoup实现网络爬虫抓取京东商品数据信息_Jsoup_02

li标签包含的需要的商品信息

使用HttpClient+Jsoup实现网络爬虫抓取京东商品数据信息_Jsoup_03
@Component
public class ItemTask {

    @Autowired
    private HttpUtils httpUtils;
    @Autowired
    private ItemService itemService;

    /**
     * 使用定时任务抓取最新数据
     *
     * @throws Exception
     */
    @Scheduled(fixedDelay = 50 * 1000)
    public void itemTask() throws Exception {
    	// 每次执行前请客数据
        itemService.deleteAll();
        
        //声明需要解析的初始地址
        String url = "https://search.jd.com/search?keyword=%E7%94%B5%E8%84%91&wq=%E7%94%B5%E8%84%91&pvid=56a110735c6c491c91416c194aed4c5b&cid3=672&cid2=671&s=56&click=0&page=";

        // 按照页面对搜索结果进行遍历解析,注意页面是奇数
        for (int i = 1; i < 10; i = i + 2) {
            String html = httpUtils.doGetHtml(url + i);
            // 解析页面,获取商品数据并存储
            this.parse(html);
        }
        System.out.println("商品数据抓取完成!");
    }

    /**
     * 解析页面,获取商品数据并存储
     *
     * @param html
     * @throws Exception
     */
    private void parse(String html) {
        // 解析html获取Document
        Document doc = Jsoup.parse(html);
        // 获取spu信息
        Elements spuEles = doc.select("div#J_goodsList > ul > li");

        // 循环列表中的SPU信息
        for (int i = 0; i < spuEles.size(); i++) {
            Element element = spuEles.get(i);
            //获取spu
            String strSpu = element.attr("data-spu");
            if (strSpu == null || strSpu.equals("")) {
                continue;
            }
            long spu = Long.parseLong(strSpu);
            //获取sku
            long sku = Long.parseLong(element.attr("data-sku"));

            Item item = new Item();
            //设置商品的spu
            item.setSpu(spu);
            //设置商品的sku
            item.setSku(sku);
            //获取商品的详情的url
            String itemUrl = "https://item.jd.com/" + sku + ".html";
            item.setUrl(itemUrl);

            // 获取商品的图片
            String picUrl = "https:" + element.select("div.p-img").select("a").select("img").attr("data-lazy-img");
            String picName = this.httpUtils.doGetImage(picUrl);
            item.setPic(picName);

            //获取商品的价格
            String strPrice = element.select("div.p-price").select("i").text();
            item.setPrice(Double.parseDouble(strPrice));

            //获取商品的标题
            String title = element.select("div.p-name").select("a").attr("title");
            item.setTitle(title);

            // 店铺名称
            String shopName = element.select("div.p-shop a").text();
            item.setShop(shopName);

            item.setCreated(new Date());
            item.setUpdated(item.getCreated());

            //保存商品数据到数据库中
            this.itemService.save(item);
        }
    }
}

配置启动类

@SpringBootApplication
// 开启定时任务
@EnableScheduling
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

启动项目,执行测试。查看数据库与本地下载照片。

使用HttpClient+Jsoup实现网络爬虫抓取京东商品数据信息_java_04
使用HttpClient+Jsoup实现网络爬虫抓取京东商品数据信息_Jsoup_05

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK