链式抽取(0.1.x开始支持)

链式抽取是提供一套API,可以对文本处理规则执行链式叠加,他是一种优雅的API风格。本功能在webmagic也有体现,不过vs的链式相对于webmagic也有点区别。

抽取类型

VS链式抽取器支持4种数据类型,分别是RawText、Xpath、Strings、Json。他们之间各自存在相互转化的转化器,如果转化器存在,那么证明链式规则可以作用在数据类型之间。

RawText

RawText是最简单的一种数据类型,她代表从网页下载得到的最原始的文本信息,他的属性只有text。它可以向其他数据类型进行转化。当然使用者需要知道数据结构是否支持转化,否则会可能转化失败,导致数据被过滤或者抛错(试情况而定)

Xpath

Xpath是执行xpath语法抽取的数据模型,内部集成SipSoupAPI,关于SipSoup的用法,请移步SipSoup章节。XpathNode内部数据模型是SIPNode,内部包裹一个Element对象或者一个字符串(这是由于xpath抽取结果可能是dom节点也可能是字符串导致)。另外,css规则,内部也是转化为SipNode执行计算

Strings

Stirngs 是多行文本,一般来说,它可以是Xpath的计算结果。对于Xpath,VS抽取器提供了一套字符串处理函数,迁移了部分common-lang3的字符串函数,可以方便对文本字符串进行加工处理。需要说明的是,对于正则规则,内部也是转化为字符串函数处理的。关于字符串函数细节,请移步StringRule章节。

Json

Json的数据定位,主要是JsonPath的功能,VS系列抽取器的JsonPath接入API是FastJson,关于JsonPath的用法,可以自己找资料看看,貌似不复杂,如果觉得FastJson的API不好用,看看能不能重写。

selectable

所有支持链式抽取的API,都有一个父类,叫做AbstactSelectable,他们的子类则是是RawText、Xpath、Strings、Json,但是子类没有特别的方法,就是createOrGetModel用来代表节点所代表的模型。同时selectable本身包含如下方法:xpath,css,jsonpath,stirngrule,regex。分别执行对应规则链式调用。

demo:直接上demo吧,先感受一下如何使用。如下测试文本,在一个html文档中抽取json数据,同时对json的数据进行抽取,得到字符串,然后处理字符串。我们需要得到两个departureDate的值("20170 720"" 20170721"),但是这两个值包含空白字符。我们需要将空白字符干掉

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>html中包含json数据</title>
</head>
<body>
<div id="testid">
    <pre>
        {
    "isUStrip": 0,
    "bookingPassengers": [
        {
            "idType": "1",
            "idCode": "140581199408138060",
            "mobile": "18782165597",
            "psgName": "张悌斯",
            "ptc": "ADT"
        }
    ],
    "insurances": [
        {
            "insuranceNum": 0,
            "insurancePrice": 20,
            "insuranceType": 2
        },
        {
            "insuranceNum": 0,
            "insurancePrice": 20,
            "insuranceType": 1
        }
    ],
    "contactInfo": {
        "isMail": false,
        "contactName": "彭思寒",
        "mobile": "18782165597"
    },
    "tripeType": "OW",
    "bookingVoyages": [
        {
            "voyageIndex": 1,
            "bookingFlights": [
                {
                    "departureTime": "1700",
                    "departureAirport": "XMN",
                    "dstTerminal": "T2",
                    "cabin": "M",
                    "flightId": "1",
                    "groundTime": 0,
                    "seats": "A",
                    "flightNumber": "8169",
                    "et": 1,
                    "arrivalDate": "20170720",
                    "meal": "S",
                    "carrier": "MF",
                    "operatingFlightNumber": "8169",
                    "aircraftType": "789",
                    "stopQuantity": 0,
                    "rbd": "M",
                    "arrivalTime": "2005",
                    "orgTerminal": "T3",
                    "departureDate": "20170   720",
                    "operatingCarrier": "MF",
                    "arrivalAirport": "PEK"
                }, {
                    "departureTime": "1700",
                    "departureAirport": "XMN",
                    "dstTerminal": "T2",
                    "cabin": "M",
                    "flightId": "1",
                    "groundTime": 0,
                    "seats": "A",
                    "flightNumber": "8169",
                    "et": 1,
                    "arrivalDate": "20170720",
                    "meal": "S",
                    "carrier": "MF",
                    "operatingFlightNumber": "8169",
                    "aircraftType": "789",
                    "stopQuantity": 0,
                    "rbd": "M",
                    "arrivalTime": "2005",
                    "orgTerminal": "T3",
                    "departureDate": "        20170721",
                    "operatingCarrier": "MF",
                    "arrivalAirport": "PEK"
                }
            ]
        }
    ],
    "ptcOthers": [
        {
            "bestPriceAcrossAgencies": [
                "1470"
            ],
            "score": 0,
            "total": 1520,
            "refundRules": [
                "改期:航班日起飞前2小时前(含)经济舱全票价(Y)的5%(特殊时段为10%)。起飞前2小时后经济舱全票价(Y)的10%(特殊时段为20%),改期需补齐差价。\r\n退票:航班日起飞前2小时前(含)经济舱全票价(Y)的10%(特殊时段为20%),起飞前2小时后经济舱全票价(Y)的20%(特殊时段为30%);此外,来回程客票,若部分使用,应先返还已享受的优惠,同时收取舱位对应的退票费。\r\n(注:特殊时段是指航班日为每年春运、7月1日-8月31日期间)"
            ],
            "totalTaxIata": 50,
            "currency": "CNY",
            "totalTaxYQYR": 0,
            "totalBase": 1470,
            "tax": [
                {
                    "code": "CN",
                    "price": 50
                },
                {
                    "code": "YQ",
                    "price": 0
                }
            ],
            "ptc": "ADT"
        }
    ],
    "isFromOrderDetail": false,
    "dOrI": "D",
    "manualFCFN": 0
}
    </pre>
</div>

</body>
</html>

抽取代码

 public class HtmlJsonSelectorTest {
    public static void main(String[] args) throws IOException {

        AbstractSelectable selectable = Selector.rawText("http://www.virjar.com",
                IOUtils.toString(HtmlJsonSelectorTest.class.getResourceAsStream("/htmljson.html"), Charsets.UTF_8));

        List<String> allDepartureDate = selectable.css("#testid pre").xpath("/text()")
                .jsonPath("$.bookingVoyages[0:].bookingFlights[0:].departureDate").stringRule("deleteWhitespace(self())")
                .createOrGetModel();

        System.out.println(Joiner.on(",").join(allDepartureDate));
    }
}

输出结果:

20170720,20170721

Process finished with exit code 0we

是不是觉得很神奇?这里小小的玩了一下语言特性。具体细节看代码去,相信你会有所收获😄

results matching ""

    No results matching ""