<!-- HTML解析器 --><dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.13.1</version></dependency>
??由于单个网站的数据可能不全,所以我们需要逐个进行抓取 。先抓取第一个,如果抓取不到,则抓取下一个网站,这样依次进行下去 。这样的业务场景,我们可以使用变种的责任链设计模式来进行代码的编写 。
BankBranchVO支行信息@Data@Builderpublic class BankBranchVO { /** * 支行名称 */ private String bankName; /** * 联行号 */ private String bankCode; /** * 省份 */ private String provName; /** * 市 */ private String cityName;}
BankBranchSpider抽象类public abstract class BankBranchSpider { /** * 下一个爬虫 */ private BankBranchSpider nextSpider; /** * 解析支行信息 * * @param bankBranchCode 支行联行号 * @return 支行信息 */ protected abstract BankBranchVO parse(String bankBranchCode); /** * 设置下一个爬虫 * * @param nextSpider 下一个爬虫 */ public void setNextSpider(BankBranchSpider nextSpider) { this.nextSpider = nextSpider; } /** * 使用下一个爬虫 * 根据爬取的结果进行判定是否使用下一个网站进行爬取 * * @param vo 支行信息 * @return true 或者 false */ protected abstract boolean useNextSpider(BankBranchVO vo); /** * 查询支行信息 * * @param bankBranchCode 支行联行号 * @return 支行信息 */ public BankBranchVO search(String bankBranchCode) { BankBranchVO vo = parse(bankBranchCode); while (useNextSpider(vo) && this.nextSpider != null) { vo = nextSpider.search(bankBranchCode); } if (vo == null) { throw new SpiderException("无法获取支行信息:" + bankBranchCode); } return vo; }}
??针对不同的网站解析方式不太一样,简言之就是获取HTML标签的属性值,对于这步可以有很多种方式实现,下面贴出我的实现方式,仅供参考 。
JsonCnSpider@Slf4jpublic class JsonCnSpider extends BankBranchSpider { /** * 爬取URL */ private static final String URL = "http://www.jsons.cn/banknum/"; @Override protected BankBranchVO parse(String bankBranchCode) { try { log.info("json.cn-支行信息查询:{}", bankBranchCode); // 设置请求参数 Map<String, String> map = new HashMap<>(2); map.put("keyword", bankBranchCode); map.put("txtflag", "1"); // 查询支行信息 Document doc = Jsoup.connect(URL).data(map).post(); Elements td = doc.selectFirst("tbody") .selectFirst("tr") .select("td"); if (td.size() < 3) { return null; } // 获取详情url String detailUrl = td.get(3) .selectFirst("a") .attr("href"); if (StringUtil.isBlank(detailUrl)) { return null; } log.info("json.cn-支行详情-联行号:{}, 详情页:{}", bankBranchCode, detailUrl); // 获取详细信息 Elements footers = Jsoup.connect(detailUrl).get().select("blockquote").select("footer"); String bankName = footers.get(1).childNode(2).toString(); String bankCode = footers.get(2).childNode(2).toString(); String provName = footers.get(3).childNode(2).toString(); String cityName = footers.get(4).childNode(2).toString(); return BankBranchVO.builder() .bankName(bankName) .bankCode(bankCode) .provName(provName) .cityName(cityName) .build(); } catch (IOException e) { log.error("json.cn-支行信息查询失败:{}, 失败原因:{}", bankBranchCode, e.getLocalizedMessage()); return null; } } @Override protected boolean useNextSpider(BankBranchVO vo) { return vo == null; }}
秒懂生活扩展阅读
- 联想小新pro16 联想小新
- 人民和公民的区别与联系
- 联通手机网络标志显示
- 建设银行客服电话是免费的吗 建设银行客服电话
- 微信怎么取消显示手机联系人
- 淘宝联盟内容推广方法是什么?如何推广?
- 淘宝联盟自助推广收费吗?如何自助推广?
- 淘宝联盟申请高佣条件是什么?怎么申请高佣?
- 怎么才可以联系上导演
- 英雄联盟9900点券多少元