解析json数据,并将解析后的数据通过list暂存和for遍历进行存储
当爬虫程序执行的时候碰到需要解析json类型的数据的时候,我们如果想要将json数据整理成我们需要的二维表的形式的数据的时候就需要考虑怎么将一个多个相同的实体类按照顺序存入到mysql数据库中,我在进行爬虫项目的时候就遇到了一个类似的问题,我在整理json数据的时候不知道如何去将解析好的数据通过实体类存入到mysql数据库中,最开始的时候我借鉴网上的代码,希望在实体类中遍历这些数据,但是最后没能实现我想要的结果,所以我放弃通过使用定制实体类来进行数据的导入了。
后来我通过定制Pipeline来进行遍历实体类数组来进行数据的导入。
下面我详细介绍一下我的思路和代码:思路基于mave工程,使用spring boot框架进行代码的配置和管理
第一步:
在MySQL中创建表institution_domain
DROP TABLE IF EXISTS `institution_domain`;CREATE TABLE `institution_domain` (`id` int(255) NOT NULL AUTO_INCREMENT COMMENT '主键ID',`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '姓名',`content` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '评估说明',`domain` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '授权签字领域',`description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '说明',`status` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '状态',PRIMARY KEY (`id`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 3599 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;SET FOREIGN_KEY_CHECKS = 1;
第二步:
创建实体类:
import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;@Entity(name = "institution_domain")public class InstitutionDomain {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String name;private String content;private String domain;private String description;private String status;//getter、setter和toString方法省略直接使用快捷键导入就行很方便}
第三步:
创建实体类的dao包接口:
import org.springframework.data.jpa.repository.JpaRepository;public interface InstitutionDomainDao extends JpaRepository<InstitutionDomain, Long> {}
第四步:
创建service层的方法接口:
import org.springframework.stereotype.Component;@Componentpublic interface InstitutionDomainService {/*** fetch data by rule id** @param institutionDomains rule id*/void save(List<InstitutionDomain> institutionDomains);/*** fetch data by rule id** @param institutionDomain rule id* @return Result<institutionDomain>*/List<InstitutionDomain> findInstitutionDomain(InstitutionDomain institutionDomain);}
第五步:
创建service接口的impl方法实现类:
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.domain.Example;import org.springframework.data.domain.Page;import org.springframework.data.domain.PageRequest;import org.springframework.stereotype.Service;import java.util.List;@Servicepublic class InstitutionDomainServiceImpl implements InstitutionDomainService {private InstitutionDomainDao institutionDomainDao;@Autowiredpublic void setInstitutionDomain(InstitutionDomainDao institutionDomainDao) {this.institutionDomainDao = institutionDomainDao;}@Overridepublic void save(List<InstitutionDomain> institutionDomains) {//根据签字人姓名和所属机构查询数据InstitutionDomain param = new InstitutionDomain();//遍历json数组for (InstitutionDomain institutionDomain:institutionDomains){param.setName(institutionDomain.getName());//执行查询List<InstitutionDomain> list = this.findInstitutionDomain(param);//判断查询结果是否为空if (list.size() == 0){this.institutionDomainDao.save(institutionDomain);}}}@Overridepublic List<InstitutionDomain> findInstitutionDomain(InstitutionDomain institutionDomain) {//设置查询条件Example<InstitutionDomain> example = Example.of(institutionDomain);return this.institutionDomainDao.findAll(example);}}
第六步:
定制Pipeline实现遍历解析json数据后形成的实体类:
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import us.codecraft.webmagic.ResultItems;import us.codecraft.webmagic.Task;import us.codecraft.webmagic.pipeline.Pipeline;import java.util.List;@Componentpublic class InstitutionDomainPipeline implements Pipeline {private InstitutionDomainService institutionDomainService;@Autowiredpublic void setInstitutionDomainService(InstitutionDomainService institutionDomainService) {this.institutionDomainService = institutionDomainService;}@Overridepublic void process(ResultItems resultItems, Task task) {//获取封装好的pojo对象List<InstitutionDomain> institutionDomains = resultItems.get("institutionDomains");//判断数据是否为不空if (institutionDomains != null) {this.institutionDomainService.save(institutionDomains);}}}
第七步:
创建application类,需要注意的是application类需要处于所有类的外面,他是spring boot项目的启动入口:
import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.scheduling.annotation.EnableScheduling;@SpringBootApplication@EnableSchedulingpublic class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}}
最后一步:
重写processor类,进行页面解析:
@Componentpublic class JobProcessor implements PageProcessor {@Overridepublic void process(Page page) {//判断url的类型String queryData = page.getUrl().regex("query\\w+").toString();String domainInfo = "queryPublishSignatory";if (queryData.equals(domainInfo)) {//判断url目的地址是不是queryPublishSignatorythis.saveDomainInfo(page);}}private void saveDomainInfo(Page page) {//创建一个机构基本信息的实体类查询机构的基本信息,准备整合数据InstitutionInfo param = new InstitutionInfo();//创建认可的签字人及领域实体类对象List<InstitutionDomain> institutionDomains = new ArrayList<>();//解析json数据, 分离json数据Json json = page.getJson();//获取json数据中的所有姓名的值List<String> nameCh = json.jsonPath("$.data[*].nameCh").all();//获取json数据中的所有评估说明的值List<String> content = json.jsonPath("$.data[*].assessmentcontent").all();//获取json数据中的所有授权签字领域的值List<String> authorizedFieldCh = json.jsonPath("$.data[*].authorizedFieldCh").all();//获取json数据中的所有说明的值List<String> note = json.jsonPath("$.data[*].note").all();//获取json数据中的所有状态的值statusList<String> status;status = json.jsonPath("$.data[*].status").all();for (int num = 0; num < nameCh.size(); num++) {//创建认可的签字人及领域实体类对象InstitutionDomain institutionDomain = new InstitutionDomain();institutionDomain.setName(nameCh.get(num));institutionDomain.setContent(content.get(num));institutionDomain.setDomain(authorizedFieldCh.get(num));institutionDomain.setDescription(note.get(num));if ("0".equals(status.get(num))) {institutionDomain.setStatus("有效");} else {institutionDomain.setStatus("无效");}institutionDomains.add(institutionDomain);}page.putField("institutionDomains", institutionDomains);}private Site site = Site.me()//设置编码格式.setCharset("utf8")//设置超时时间.setTimeOut(10 * 1000)//设置重试的间隔时间.setRetrySleepTime(3 * 1000)//设置重试的次数.setRetryTimes(3);@Overridepublic Site getSite() {return site;}private InstitutionDomainPipeline institutionDomainPipeline;@Autowiredpublic void setInstitutionDomainPipeline(InstitutionDomainPipeline institutionDomainPipeline) {this.institutionDomainPipeline = institutionDomainPipeline;}@Scheduled(initialDelay = 1000, fixedDelay = 100 * 1000)public void process() {//开启线程Spider.create(new JobProcessor()).addUrl("https://las.cnas.org.cn/LAS/publish/queryPublishSignatory.action?baseinfoId=b9823e479f524538aa2eeada55cef10e").setScheduler(new QueueScheduler().setDuplicateRemover(new BloomFilterDuplicateRemover(100000))).thread(10).addPipeline(this.institutionDomainPipeline).run();}}
按照这个流程就能够实现将List<实体类名称>类型的数据全部存到mysql数据库里面了。
这些代码是我完成的项目中的一部分代码,但是应该能够实现我说的这些功能,部分improt的结果我没有附上去,那部分就是自己书写的类的路径,大家可以自行添加。
希望能够给大家提供帮助。有好的想法也希望能够和我进行交流谢谢大家。
