• Springboot+JPA下实现简易爬虫--爬取豆瓣电视剧数据


    Springboot+JPA下实现简易爬虫--爬取豆瓣电视剧数据


      前言:今天听到产品那边讨论一些需求,好像其中一点是用户要求我们爬虫,在网页上抓取一些数据然后存到我们公司数据库中,众所周知,爬虫的实现对于python语言可是专家,而对于我们使用的Java语言,我也不确定可不可以,趁着无事,上网参考了下资料,自己也写了些demo,所幸爬取数据成功了,由于我使用的基础demo项目是自己搭建的springboot+jpa的项目,因此也会在这个基础上进行爬虫的实现,文章会贴出具体的步骤以及重要的代码,至于项目的搭建就不介绍了,我的完整代码会同步至gitHub,大家可以参考使用,当然也可以使用自己的springboot项目。

    gitHub地址:https://github.com/Slience-zae/mail-demo.git

    1.材料准备

    1.1首先打开豆瓣的网页,同时F12打开控制台

     

     1.2 在控制台中找到接口url,请求头信息,以及相应数据格式和字段

     

     

     

     

     

     在网页上准备的材料这些就可以了,接下来,该动手撰写代码了。

    2.代码实现步骤

    2.1 数据库创建表格

    CREATE TABLE `subjects` (
      `id` varchar(255) NOT NULL COMMENT 'id',
      `title` varchar(255) DEFAULT NULL COMMENT '标题',
      `rate` decimal(10,2) DEFAULT NULL COMMENT '豆瓣评分',
      `url` varchar(255) DEFAULT NULL COMMENT '观影地址',
      `playable` tinyint(4) DEFAULT NULL COMMENT '是否可以观看:0是 1否',
      `cover` varchar(255) DEFAULT NULL COMMENT '封面图片地址',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    通过相应数据可以得知共有九个字段,但是我们主要保存的是数据主要信息,其中cover_x,cover_y,is_new对于我们来说没有什么意义,可以不保存到数据库,因此略过。

    2.2 hibernate逆向生成实体

    选中右键点击,选择Generate persistence Mapping,再选择By Database Schema,选中数据库的表,再选择生成实体的包位置,最后点击ok就能生成到指定位置了,生成后我们再加以修改一下实体,大体是这个样子。

    import lombok.Data;
    import javax.persistence.*;
    import java.math.BigDecimal;
    @Data
    @Entity
    @Table(name = "subjects")
    public class Subjects {
        @Id
        private String id;//id
        private String title;//标题
        private BigDecimal rate;//豆瓣评分
        private String url;//观影地址
        private Boolean playable;//是否能够观看
        private String cover;//封面图片URL
        @Transient
        private Integer cover_x;
        @Transient
        private Integer cover_y;
        @Transient
        private Boolean is_new;
    }

    在此说明一下,之所以将cover_x,cover_y,is_new三个字段也添加进实体了,是为了防止接下来json数组转化List<Subjects>时发生异常,我已经在这三个字段上加了@Transient注解,因此三个字段不会映射数据库。

    2.3 编写向指定网址抓取json数据的工具类

    import org.springframework.boot.configurationprocessor.json.JSONObject;
    import org.springframework.stereotype.Component;
    import java.io.ByteArrayOutputStream;
    import java.io.InputStream;
    import java.net.HttpURLConnection;
    import java.net.URL;
    @Component
    public class GetJson {
        public JSONObject getHttpJson(String url){
            try {
                URL realUrl = new URL(url);
                HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection();
                //设置HTTP的请求头(参考材料准备截图的请求头信息)
                connection.setRequestProperty("Accept", "*/*");//设置浏览器可以接收的媒体类型
                connection.setRequestProperty("Connection", "keep-alive");//网页打开,建立连接
                connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3928.4 Safari/537.36");//客户端使用的操作系统和浏览器的名称和版本
                // 建立实际的连接
                connection.connect();
                //请求成功
                if (connection.getResponseCode() == 200) {
                    InputStream is = connection.getInputStream();
                    //创建字节数组输出流对象
                    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                    //10MB的缓存
                    byte[] buffer = new byte[10485760];
                    int len = 0;
                    while ((len = is.read(buffer))!= -1) {
                        byteArrayOutputStream.write(buffer, 0, len);
                    }
                    String jsonString = byteArrayOutputStream.toString();
                    byteArrayOutputStream.close();
                    is.close();
                    //转换成json数据返回
                    return new JSONObject(jsonString);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    }

    注意一点,设置连接对象的请求头信息的时候,要将我们在豆瓣上拿到的那几个参数设置成一样的,防止抓取数据失败,具体那几个参数是什么,已经在代码注释上加以说明了。

    2.4 完整业务代码糅合实现

    (1).在application.properties配置文件中加入以下代码

    #豆瓣网址
    douban_url= https://movie.douban.com/j/search_subjects

    (2) dao层加入类

    import com.maven.maildemo.entity.Subjects;
    import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
    import org.springframework.data.repository.CrudRepository;
    
    public interface SubjectsDao extends CrudRepository<Subjects, String>, JpaSpecificationExecutor<Subjects> {
    
    }

    (3) service,serviceImpl,controller层代码

    import com.maven.maildemo.entity.Subjects;
    import java.util.List;
    
    public interface SubjectsService {
        /**
         * 在豆瓣网页上抓取电视剧信息保存并返回
         * @author zae
         * @param pageNumber 页码
         */
        List<Subjects> getAndSaveSubjectsList(Integer pageNumber) throws Exception;
    }

     

    import com.alibaba.fastjson.JSON;
    import com.maven.maildemo.dao.SubjectsDao;
    import com.maven.maildemo.entity.Subjects;
    import com.maven.maildemo.service.SubjectsService;
    import com.maven.maildemo.utils.GetJson;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.configurationprocessor.json.JSONArray;
    import org.springframework.boot.configurationprocessor.json.JSONObject;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    import java.util.ArrayList;
    import java.util.List;
    
    @Slf4j
    @Service
    @Transactional
    public class SubjectsServiceImpl implements SubjectsService {
    
        @Value("${douban_url}")
        private String doubanUrl;
    
        @Autowired
        private GetJson getJson;
    
        private final String DOUBAN_PARM = "?type=tv&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=";
    
        @Autowired
        private SubjectsDao subjectsDao;
    
        @Override
        public List<Subjects> getAndSaveSubjectsList(Integer pageNumber) throws Exception {
            if(pageNumber>=0 && pageNumber <= 10000){
                String address = doubanUrl+DOUBAN_PARM+pageNumber;
                //获取json对象数据
                JSONObject httpJson = getJson.getHttpJson(address);
                if(httpJson != null){
                    //取出json数据数组
                    JSONArray subjectsArray = httpJson.getJSONArray("subjects");
                        if(subjectsArray!=null){
                            //将json数组转化为List
                            List<Subjects> subjectsList = JSON.parseArray(subjectsArray.toString(),Subjects.class);
                            for(Subjects subjects:subjectsList){
                                //爬出数据后,保存在数据库中
                                subjectsDao.save(subjects);
                            }
                            return subjectsList;
                        }else{
                            return new ArrayList<>();
                        }
                    }else{
                        return new ArrayList<>();
                    }
            }
            return new ArrayList<>();
        }
    }

     

    import com.alibaba.fastjson.JSON;
    import com.maven.maildemo.entity.Subjects;
    import com.maven.maildemo.service.SubjectsService;
    import io.swagger.annotations.Api;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    import java.util.List;
    
    @RestController
    @RequestMapping("subjects")
    @Api(description = "豆瓣")
    public class SubjectsController {
        @Autowired
        private SubjectsService subjectsService;
    
        /**
         * 在豆瓣网页上抓取电视剧信息保存并返回
         * @param pageNumber 页码
         * @author zae
         * @return
         */
        @GetMapping(value = "/getAndSaveSubjectsList")
        String getAndSaveSubjectsList(@RequestParam Integer pageNumber){
            try {
                List<Subjects> subjectsList = subjectsService.getAndSaveSubjectsList(pageNumber);
                return subjectsList==null?null: JSON.toJSONString(subjectsList);
            } catch (Exception e) {
               return "爬取数据信息发生异常"+e.getMessage();
            }
        }
    }

    业务代码没啥复杂的,基本上都加注释了,看一下就好了。

    3.测试

    启动项目,打开swaager,找到刚刚写的接口,输入参数点击进行测试。

     

     此时不出意外应该是执行成功了,打开数据库,看一下库里有没有我们爬下来的数据。

     

     发现库里有值,说明我们已经成功的将数据爬下来了。不仅仅豆瓣如此,其他网页数据也是类似的实现。

    本人java爬虫学习借鉴博客:https://blog.csdn.net/qwe86314/article/details/91450098  博主是使用的mybatis结合实现,而我的是结合springboot+jpa的项目使用的。

    如有问题,多多评论指教,文章编写不易,期待您的推荐和赞,

     

  • 相关阅读:
    jupyter 更新环境变量 %env
    viterbi 维特比解码过程,状态转移矩阵
    ValueError: cannot index with vector containing NA / NaN values
    python ElasticSearch ES 搜索词 完全匹配 精准匹配
    首页 如何在Jupyter中抑制回溯?
    python 操作ES
    python 玩转 侦探游戏 嫌疑犯 真假话 侦探推理
    python – 解析pcfg语法树 提取其语法规则 Probabilistic Context-Free Grammar Parser
    2019-09-18 关键字匹配文件名--搜索文件
    2019-07-21 win10安装rabbitmq与启动
  • 原文地址:https://www.cnblogs.com/zaevn00001/p/13821486.html
Copyright © 2020-2023  润新知