Jsoup数据解析浅析一二

前言

数据解析,常用的工具:如果是.html带有<div>、<table>等标签的源码,优先使用Jsoup或正则;如果是Json数据,fastjson即可。

本文主要讲解.html带有<div>、<table>等标签的源码的数据解析方式。在讲解之前,我们先了解一下Jsoup和正则。

  1. Jsoup是一款Java的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM、CSS以及类似于jQuery的操作方法来取出和操作数据。
  2. 正则表达式是对字符串(包括普通字符(例如,a到z之间的字母)和特殊字符(称为“元字符”))操作的一种逻辑公式,就是用事先定义好的一些特定字符及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。正则表达式是一种文本模式,该模式描述在搜索文本时要匹配的一个或多个字符串。

上面的话,简而言之、言而简之就是,Jsoup对结构抽取友好,正则对字符串抽取友好。根据以上特点,带有标签的.html解析,Jsoup负责架构的宏观定位,正则负责内容的微观调整。

下面我们举几个例子具体说明说明。

Maven依赖

        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.11.3</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.6</version>

简单Jsoup解析

示例网站:https://www.cnmn.com.cn/ShowNewsList.aspx?id=30

在这里插入图片描述

由上图可知,这勉强算个标准的.html,需要优化的是,一条完整的记录应在同一个父标签下,结果它内部数据及其它记录是统一的并列关系,中间用<div class="con-border1"></div>做了视觉上的分隔。

相关解析代码如下:

            Document pageDoc = Jsoup.parse(pageContent);
            Element dataBlockElements = pageDoc.selectFirst("div.tabbable>div.tab-content");
            Elements dataElements = dataBlockElements.select("h4");
            if (dataElements == null || dataElements.size() <= 0) {
                break;
            }

            Object[][] dataObjs = new Object[dataElements.size()][];
            for (int i = 0; i < dataElements.size(); i++) {
                Element dataElement = dataElements.get(i);
                String title = dataElement.selectFirst("a").attr("title");

                String url = dataElement.selectFirst("a").attr("href");
                url = "https://www.cnmn.com.cn" + url;
                String newsId = SHA1Utils.getDigest(url);

                dataObjs[i] = new Object[]{"中国有色网", MODULE_MAP.get(moduleUrl), newsId, title, url};
            }

代码只抽取了标题和链接,其它内容可通过详情页抽取,这里不予补充。

表格Jsoup解析

示例网站:https://www.ac-rei.org.cn/article/3a6f8bf8-424e-4f55-b701-4dac6c2eb6d9

在这里插入图片描述

由上图可知,这个表格里含有合并单元格,处理不好就会数据对应错误;抽取时需要强校验。

相关解析代码如下:

    public void extractTable(Element tableElement, Record newsRec, String dataDate) {
        Elements trElements = tableElement.children();
        Elements titleElements = trElements.get(0).children();
        if (titleElements.size() != 5 || !titleElements.get(0).text().contains("类别")
                || !titleElements.get(1).text().contains("产品") || !titleElements.get(2).text().contains("纯度")
                || !titleElements.get(3).text().contains("参考价") || !titleElements.get(4).text().contains("涨跌")) {
            Db.use("new-material-industry-crawler").update("update `ety_news_acrei_price` set `is_crawler_completed`=1,`process_status`=-1 where `id`=?;",
                    newsRec.getInt("id"));
            return;
        }

        List<Object[]> dataObjList = new ArrayList<>();
        String categoryName = null;
        String productName = null;
        for (int i = 1; i < trElements.size(); i++) {
            String purity = null;
            String price = null;
            String diff = null;

            Elements dataElements = trElements.get(i).children();
            if (dataElements.size() == 5) {
                categoryName = dataElements.get(0).text();
                productName = dataElements.get(1).text();
                purity = dataElements.get(2).text();
                price = dataElements.get(3).text();
                diff = dataElements.get(4).text();
            } else if (dataElements.size() == 4) {
                productName = dataElements.get(0).text();
                purity = dataElements.get(1).text();
                price = dataElements.get(2).text();
                diff = dataElements.get(3).text();
            } else if (dataElements.size() == 3) {
                purity = dataElements.get(0).text();
                price = dataElements.get(1).text();
                diff = dataElements.get(2).text();
            } else {
                continue;
            }

            String priceMin = RegexUtils.getMatcherInfo("(\\d+)\\s*-\\s*\\d+\\s*.*", price);
            String priceMax = RegexUtils.getMatcherInfo("\\d+\\s*-\\s*(\\d+)\\s*.*", price);
            String priceUnit = RegexUtils.getMatcherInfo("\\d+\\s*-\\s*\\d+\\s*(.*)", price);
            dataObjList.add(new Object[]{dataDate,
                    categoryName.replaceAll("&nbsp;", "").replaceAll(" ", "").trim(),
                    productName.replaceAll("&nbsp;", "").replaceAll(" ", "").trim(),
                    purity.replaceAll("&nbsp;", " ").trim(),
                    priceUnit, priceMin, priceMax, diff});
        }
    }

Jsoup+正则混合解析

示例网站:https://www.cnmn.com.cn/ShowNews1.aspx?id=438137

在这里插入图片描述

由上图可知,来源、分类、作者等字段并无标签定位,这个时候就要Jsoup+正则解析了。

相关解析代码如下:

                Document pageDoc = Jsoup.parse(pageContent);
                Element contentElement = pageDoc.selectFirst("div#content>div");

                String publishTimeStr = contentElement.selectFirst("p.info>span:nth-child(1)>span.time").text().trim();
                String dateStr = sdf_html.format(new Date());
                if (publishTimeStr != null && publishTimeStr.length() > 0) {
                    publishTimeStr = sdf_data.format(sdf_detail.parse(publishTimeStr));
                    dateStr = sdf_html.format(sdf_data.parse(publishTimeStr));
                }

                String infoStr = contentElement.selectFirst("p.info").outerHtml();
                String source = RegexUtils.getMatcherInfo("来源:\\s*(?:<a.*?>|)(.*?)\\s*(?:&nbsp;|</)", infoStr);
                String author = RegexUtils.getMatcherInfo("作者:\\s*(?:<a.*?>|)(.*?)\\s*(?:&nbsp;|</)", infoStr);

                Element summaryElement = contentElement.selectFirst("p.p1.daodu");
                String summary = new String();
                if (summaryElement != null) {
                    summary = summaryElement.text().trim();
                }

后语

个人经验,仅供参考:带有标签的.html解析,Jsoup负责架构的宏观定位,正则负责内容的微观调整。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值