从API到DSL —— 使用 Kotlin 特性为爬虫框架进一步封装

本文探讨如何使用 Kotlin 的特性,如带接收者的 Lambda、运算符重载和中缀表达式,来为爬虫框架 NetDiscovery 创建内部 DSL,提升代码的可读性和易用性。通过示例展示了 Request、SpiderEngine 和 Selenium 模块的 DSL 封装,简化了爬虫配置和操作,使得非编程专家也能更好地理解和使用爬虫框架。
摘要由CSDN通过智能技术生成

640?wx_fmt=jpeg


NetDiscovery (https://github.com/fengzhizi715/NetDiscovery)  是一款基于 Vert.x、RxJava 2 等框架实现的爬虫框架。

一. 如何创建 DSL

领域特定语言(英语:domain-specific language、DSL)指的是专注于某个应用程序领域的计算机语言。又译作领域专用语言。DSL 能够简化程序设计过程,提高生产效率的技术,同时也让非编程领域专家的人直接描述逻辑成为可能。

NetDiscovery 本身提供了很多功能的 API,然而它的 DSL 模块是为了让使用者拥有更多的选择。

本文讨论的 DSL 是内部 DSL。

内部 DSL:通用语言的特定语法,用内部DSL写成的脚本是一段合法的程序,但是它具有特定的风格,而且仅仅用到了语言的一部分特性,用于处理整个系统一个小方面的问题。

NetDiscovery 的 DSL 主要是结合 Kotlin 带接收者的 Lambda、运算符重载、中缀表达式等 Kotlin 语法特性来编写。

运算符重载、中缀表达式其实很多语言都有,那么我们着重介绍一下带接收者的 Lambda。

在介绍 Kotlin 带接收者的 Lambda 之前,先介绍一下带接收者的函数类型。

带接收者的函数类型,例如 A.(B) -> C,其中 A 是接收者类型,B是参数类型,C是返回类型。

例如:

 
 
  1.    val sum: Int.(Int) -> Int = {

  2.        this + it

  3.    }

sum 是带接收者的函数类型,它在使用上类似于扩展函数。在函数内部,可以使用this指代传给调用的接收者对象。

而带接收者的 Lambda 典型代表是 Kotlin 标准库的扩展函数:with 和 apply。

看一下 apply 的源码:

 
 
  1. public inline fun <T> T.apply(block: T.() -> Unit): T {

  2.    contract {

  3.        callsInPlace(block, InvocationKind.EXACTLY_ONCE)

  4.    }

  5.    block()

  6.    return this

  7. }

在 apply 函数中,参数 block 是一个带有接收者的函数类型的参数。

对于 apply 函数的使用,先定义一个 User 对象:

 
 
  1. class User{

  2.    var name:String?=null

  3.    var password: String?=null

  4.    override fun toString(): String {

  5.        return "name:$name,password=$password"

  6.    }

  7. }

然后,使用 apply 函数对 User 的属性进行赋值:

 
 
  1. fun main(args: Array<String>) {

  2.    val user = User().apply {

  3.        name = "Tony"

  4.        password = "123456"

  5.    }

  6.    println(user)

  7. }

二. Request 的 DSL 封装

Request 请求包含了爬虫网络请求 Request 的封装,例如:url、userAgent、httpMethod、header、proxy 等等。当然,还包含了请求发生之前、之后做的一些事情,类似于AOP。

那么,我们来看一下使用 DSL 来编写Request:

 
 
  1.        val request = request {

  2.            url = "https://www.baidu.com/"

  3.            httpMethod = HttpMethod.GET

  4.            spiderName = "tony"

  5.            header {

  6.                "111" to "2222"

  7.                "333" to "44444"

  8.            }

  9.            extras {

  10.                "tt" to "qqq"

  11.            }

  12.        }

  13.        Spider.create().name("tony").request(request).pipeline(DebugPipeline()).run()

可以看到,Request 使用 DSL 封装之后,非常简单明了。

下面的代码是具体的实现,主要是使用带接收者的 Lambda、中缀表达式。

 
 
  1. package com.cv4j.netdiscovery.dsl

  2. import com.cv4j.netdiscovery.core.domain.Request

  3. import io

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值