请大家关注一下地球号这个可以比较快的接收到最新的文章: Java量化系列(三十一) 别再手动整理板块数据了Java 批量爬取某券商板块列表3 种分类自动入库你是否在做量化系统开发时遇到过这些痛点 手动整理板块数据耗时耗力容易遗漏最新板块板块分类混乱行业、概念、地域傻傻分不清导致数据管理杂乱手动更新板块信息不及时影响策略回测准确性。今天这篇系列第三十一篇就彻底解决这些问题 —— 从板块概念,地区 基础认知到数据库设计再到东方财富板块列表批量爬取实战分页 接口解析 自动入库全程聚焦技术实现帮你搭建高效的板块数据自动化管理模块。所有内容均为技术学习用途不涉及任何投资建议可放心复用。一、先搞懂3 种核心板块分类对应技术枚举设计在量化系统中板块本质是 “时序数据的分类标签”不同分类对应不同的分析维度。结合代码中的BKType枚举核心分为 3 类覆盖绝大多数分析场景分类类型枚举值code核心含义典型示例行业板块1BK按行业属性划分反映某一行业的整体趋势新能源、半导体、生物医药概念板块2GN按特定概念 / 主题划分反映市场热点方向人工智能、光伏、数字经济地域板块3DY按地域属性划分反映区域经济相关趋势长三角、粤港澳、京津冀 技术设计亮点通过BKType枚举统一管理分类后续新增分类如 “主题板块”只需扩展枚举无需修改核心业务逻辑符合 “开闭原则”。二、数据存储设计板块信息表stock_bk结构解析板块数据需要持久化存储方便后续查询、筛选和关联分析。下面拆解stock_bk表的设计思路适配 3 种分类的存储需求2.1 表结构核心字段说明CREATE TABLE stock_bk ( id int NOT NULL AUTO_INCREMENT COMMENT 主键ID, code varchar(10) DEFAULT NULL COMMENT 版块编码唯一标识, name varchar(30) DEFAULT NULL COMMENT 版块名称, type int DEFAULT 1 COMMENT 类型 1板块 2概念 3地域关联BKType枚举, hot_num int DEFAULT 0 COMMENT 热度用于排序展示, create_date datetime DEFAULT NULL COMMENT 创建时间, ths_code varchar(10) DEFAULT NULL COMMENT 同花顺版块Code多源数据兼容, ths_name varchar(30) DEFAULT NULL COMMENT 同花顺版块Name多源数据兼容, -- 其他扩展字段五行、成绩标记等用于个性化分析 PRIMARY KEY (id), KEY idx_stock_bk_1 (code) -- 编码索引提升查询效率 ) ENGINEInnoDB COMMENT股票版块信息表;2.2 设计思路拆解多源兼容预留ths_code、ths_name字段支持东方财富、同花顺等多平台板块数据接入避免单一数据源依赖分类明确type字段直接关联BKType枚举确保分类统一后续查询 “某类板块” 时直接通过type过滤高效便捷可扩展性hot_num热度、five_xing五行等字段为扩展字段可根据业务需求灵活使用如按热度排序展示热门板块实体映射对应StockBkDo实体类通过 MyBatis-Plus 实现 ORM 映射无需手动编写 SQL提升开发效率。三、重点实战东方财富板块列表批量爬取全程代码解析这是本文核心内容 —— 通过东方财富公开接口实现板块列表的批量爬取支持分页获取自动解析数据并适配后续入库逻辑。实体类: StockBkDo 和 BKInfo 一致DataEqualsAndHashCode(callSuperfalse)TableName(stock_bk)publicclassStockBkDoimplementsSerializable{privatestaticfinallongserialVersionUID1L;/** * id */TableId(valueid,typeIdType.AUTO)privateIntegerid;/** * 板块编码 */TableField(code)privateStringcode;/** * 板块名称 */TableField(name)privateStringname;/** * 类型 1是板块 2是 概念 3是地域 */TableField(type)privateIntegertype;/** * 板块顺序 */TableField(hot_num)privateStringhotNum;/** * 板块五行 */TableField(five_xing)privateStringfiveXing;/** * 五行原因 */TableField(five_reason)privateStringfiveReason;/** * 成绩标记 */TableField(score_type)privateIntegerscoreType;/** * 成绩标记原因 */TableField(score_message)privateStringscoreMessage;TableField(create_date)privateDatecreateDate;TableField(ths_code)privateStringthsCode;TableField(ths_name)privateStringthsName;TableField(existfalse)privateStringwebUrl;}3.1 先分析爬取接口核心信息目标接口https://push2.eastmoney.com/api/qt/clist/get?cbjinhaiyuejiangpn1pz50po1np1fieldsf12,f13,f14,f62fidf62fsm:90t:2utb2884a393a59ad64002292a3e90d46a5_提取关键词:https://push2.eastmoney.com/api/qt/clist/get?cb{0}pn{1}pz50po1np1fieldsf12,f13,f14,f62fidf62fsm:90t:2utb2884a393a59ad64002292a3e90d46a5_接口参数说明关键cb回调函数名用于 JSONP 跨域代码中通过CB_BK常量定义pn页码分页核心参数从 1 开始递增pz每页条数固定 50 条接口限制fields需要返回的字段f12板块编码、f14板块名称对应后续解析字段fs筛选条件m:90t:2表示查询行业板块列表若查询概念 / 地域需调整该参数。3.2 核心代码分页爬取实现/** * 批量获取全量板块列表分页爬取东方财富接口 * return 全量板块信息列表 */OverridepublicListBKInfofindAllBkList(){try{booleanstopSearchfalse;// 终止爬取标记intpage1;// 起始页码ListBKInfoallResultListnewArrayList();// 分页循环爬取直到获取不到数据为止do{// 1. 拼接完整URL替换回调函数名和页码StringurlMessageFormat.format(https://push2.eastmoney.com/api/qt/clist/get?cb{0}pn{1}pz50po1np1fieldsf12,f13,f14,f62fidf62fsm:90t:2utb2884a393a59ad64002292a3e90d46a5_{2},CB_BK,page,MyDateUtil.getTimezone()// 时间戳参数防缓存);try{// 2. 调用接口并解析数据ListBKInfocurrentPageListparseBKInfoList(url,BKType.BK);// 3. 处理当前页数据if(!CollUtil.isEmpty(currentPageList)){allResultList.addAll(currentPageList);page;// 页码递增继续爬取下一页}else{stopSearchtrue;// 无数据终止爬取}// 4. 延迟1秒避免高频请求被限制IP反爬关键ThreadUtil.safeSleep(1000);}catch(Exceptione){log.error(第{}页板块数据爬取出错,page,e);throwe;// 可根据需求调整是否终止整体爬取}}while(!stopSearch);log.info(板块列表爬取完成共获取{}条数据,allResultList.size());returnallResultList;}catch(Exceptione){log.error(全量板块列表爬取异常,e);returnCollections.emptyList();}}3.3 关键步骤数据解析实现爬取接口返回的是 JSONP 格式数据需要先处理格式再解析核心字段板块编码、名称/** * 解析板块列表数据JSONP格式转JSON提取核心字段 * param url 爬取接口URL * param bkType 板块类型对应BKType枚举 * return 解析后的板块信息列表 */privateListBKInfoparseBKInfoList(Stringurl,BKTypebkType){try{// 1. 发送GET请求获取数据携带请求头模拟浏览器请求StringcontentHttpUtil.sendGet(HttpClientConfig.proxyNoUseCloseableHttpClient(),url,buildDfHeaderMap()// 构建请求头含Cookie提升爬取稳定性);// 2. 处理JSONP格式去掉回调函数包裹如 cbName(...) → ... StringcbgetCb(bkType);contentcontent.substring(cb.length()1);// 去掉cbName(contentcontent.substring(0,content.length()-2);// 去掉);// 3. JSON解析提取data.diff中的板块列表JSONObjectjsonObjectJSONObject.parseObject(content);JSONObjectdatajsonObject.getJSONObject(data);if(ObjectUtils.isEmpty(data)){returnCollections.emptyList();}JSONArrayjsonArraydata.getJSONArray(diff);if(jsonArray.size()0){returnCollections.emptyList();}// 4. 映射为BKInfo对象后续可直接转StockBkDo入库ListBKInforesultnewArrayList(jsonArray.size());jsonArray.forEach(n-{JSONObjecttempObjectJSONObject.parseObject(n.toString());BKInfobkInfonewBKInfo();bkInfo.setCode(tempObject.getString(f12));// 板块编码bkInfo.setName(tempObject.getString(f14));// 板块名称bkInfo.setType(bkType.getCode());// 板块类型编码result.add(bkInfo);});returnresult;}catch(Exceptione){log.error(板块数据解析异常,e);globalWebExceptionHandlerAspect.addException();returnCollections.emptyList();}}/** * 构建请求头关键模拟浏览器提升爬取成功率 */privateNotNullMapString,StringbuildDfHeaderMap(){MapString,StringheaderMapnewHashMap();headerMap.put(Host,20.push2.eastmoney.com);headerMap.put(Cookie,东方财富的Cookie);returnheaderMap;}3.4 最后一步数据入库衔接 StockBkDo将解析后的BKInfo列表转换为StockBkDo批量插入数据库/** * 板块数据批量入库 * param bkInfoList 解析后的板块信息列表 * return 入库成功数量 */publicintbatchInsertBkData(ListBKInfobkInfoList){if(CollUtil.isEmpty(bkInfoList)){return0;}// 转换为StockBkDo对象ListStockBkDobkDoListbkInfoList.stream().map(bkInfo-{StockBkDobkDonewStockBkDo();bkDo.setCode(bkInfo.getCode());bkDo.setName(bkInfo.getName());bkDo.setType(bkInfo.getType());bkDo.setCreateDate(newDate());// 创建时间// 其他扩展字段可根据需求补充returnbkDo;}).collect(Collectors.toList());// 批量插入MyBatis-Plus方法returnstockBkMapper.insertBatch(bkDoList);}四、技术要点爬取稳定性与扩展性优化4.1 稳定性优化反爬 容错请求延迟爬取每页后延迟 1 秒ThreadUtil.safeSleep(1000)避免高频请求被封 IP请求头伪装携带Host、Cookie等请求头模拟浏览器行为提升爬取成功率异常容错单页爬取失败时抛出异常可根据需求调整为 “跳过当前页”避免影响整体爬取时间戳防缓存URL 拼接时间戳参数MyDateUtil.getTimezone()避免获取缓存的旧数据。4.2 扩展性优化支持多类型板块爬取当前代码爬取的是 “行业板块”fsm:90t:2若要爬取 “概念板块”“地域板块”只需调整fs参数// 爬取概念板块fs参数改为 m:90t:3StringgnUrlMessageFormat.format(https://push2.eastmoney.com/api/qt/clist/get?cb{0}pn{1}pz50po1np1fieldsf12,f13,f14,f62fidf62fsm:90t:3utb2884a393a59ad64002292a3e90d46a5_{2},CB_GN,page,MyDateUtil.getTimezone());// 爬取地域板块fs参数改为 m:90t:1StringdyUrlMessageFormat.format(https://push2.eastmoney.com/api/qt/clist/get?cb{0}pn1pz50po1np1fieldsf12,f14fidf62fsm:90t:1utb2884a393a59ad64002292a3e90d46a5_{2},CB_DY,page,MyDateUtil.getTimezone());五. 避坑指南: 板块爬取的 5 个典型问题 ⚠️JSONP 格式处理错误忘记去掉回调函数包裹如cbName(...)导致 JSON 解析失败 → 严格按substring方法处理格式高频请求被封 IP未加延迟或请求头伪装 → 必须添加 1-2 秒延迟携带真实 Cookie 和 Host分页终止条件错误页码递增无限制 → 只有当 “当前页无数据” 时才终止爬取字段映射错误把f13当成板块编码实际f12是编码 → 先通过浏览器调试接口确认字段含义数据库插入重复未做去重处理 → 入库前先查询数据库存在则更新不存在则插入。六、下期预告下期主要讲解一下 板块概念地区 这些的区别用于读者更好的理解。私信回复: “板块获取” 获取到目前最新的 板块数据直接导入到数据库中即可使用。最后留个小问题你在做量化系统时还需要爬取哪些类型的分类数据是否需要支持 “板块 - 数据” 关联关系的自动维护欢迎在评论区留言讨论后续将持续优化完善请大家关注一下地球号这个可以比较快的接收到最新的文章: Java量化系列(三十一) 别再手动整理板块数据了Java 批量爬取某券商板块列表3 种分类自动入库