jjsoup-spring-boot-starter


License

License

Categories

Categories

Spring Boot Container Microservices jsoup Business Logic Libraries
GroupId

GroupId

me.kagura
ArtifactId

ArtifactId

jjsoup-spring-boot-starter
Last Version

Last Version

0.1.9
Release Date

Release Date

Type

Type

jar
Description

Description

jjsoup-spring-boot-starter
jjsoup-spring-boot-starter
Project URL

Project URL

https://github.com/KingFalse/jjsoup-spring-boot-starter
Source Code Management

Source Code Management

https://github.com/KingFalse/jjsoup-spring-boot-starter.git

Download jjsoup-spring-boot-starter

How to add to project

<!-- https://jarcasting.com/artifacts/me.kagura/jjsoup-spring-boot-starter/ -->
<dependency>
    <groupId>me.kagura</groupId>
    <artifactId>jjsoup-spring-boot-starter</artifactId>
    <version>0.1.9</version>
</dependency>
// https://jarcasting.com/artifacts/me.kagura/jjsoup-spring-boot-starter/
implementation 'me.kagura:jjsoup-spring-boot-starter:0.1.9'
// https://jarcasting.com/artifacts/me.kagura/jjsoup-spring-boot-starter/
implementation ("me.kagura:jjsoup-spring-boot-starter:0.1.9")
'me.kagura:jjsoup-spring-boot-starter:jar:0.1.9'
<dependency org="me.kagura" name="jjsoup-spring-boot-starter" rev="0.1.9">
  <artifact name="jjsoup-spring-boot-starter" type="jar" />
</dependency>
@Grapes(
@Grab(group='me.kagura', module='jjsoup-spring-boot-starter', version='0.1.9')
)
libraryDependencies += "me.kagura" % "jjsoup-spring-boot-starter" % "0.1.9"
[me.kagura/jjsoup-spring-boot-starter "0.1.9"]

Dependencies

compile (6)

Group / Artifact Type Version
org.springframework.boot : spring-boot-starter-aop jar 1.5.0.RELEASE
org.springframework.boot : spring-boot-starter jar
org.jsoup : jsoup jar 1.11.3
org.javassist : javassist jar 3.22.0-GA
com.sun.istack : istack-commons-runtime jar 3.0.5
commons-io : commons-io jar 2.6

Project Modules

There are no modules declared in this project.

jjsoup-spring-boot-starter

jjsoup-spring-boot-starter是对jsoup的无侵入封装,使它更好的适合于网络爬虫开发Powered by Jsoup

Demo项目:https://github.com/KingFalse/didi-app-auth-crawler

Maven Central

如何使用:

在spring boot项目中引入:

<dependency>
    <groupId>me.kagura</groupId>
    <artifactId>jjsoup-spring-boot-starter</artifactId>
    <version>0.1.9</version>
</dependency>
<!--可选,用于在@RestController中支持@JSONBodyField-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>x.x</version>
</dependency>
<!--可选,用于支持@LoginInfoKey跟LoginInfo自动保存-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

快速开始:

import me.kagura.FollowProcess;
import me.kagura.JJsoup;
import me.kagura.LoginInfo;
import org.jsoup.Connection;
import org.jsoup.nodes.Document;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.IOException;

@RunWith(SpringRunner.class)
@SpringBootTest
public class JJsoupTest {
    @Autowired
    JJsoup jJsoup;

    @Test
    public void Test() throws Exception {
        // 常规
        Document document = jJsoup.connect("https://github.com/KingFalse").get();
        System.err.println(document);

        // 携带Logininfo
        LoginInfo loginInfo = new LoginInfo();//随机生成UUID作为key,new LoginInfo("xxx");指定key
        // String              loginInfo.key;                一个字符串值,在序列化时作为key使用
        // Map<String, String> loginInfo.cookies;            用于存放cookie
        // Proxy               loginInfo.Proxy(Proxy proxy); 用于设置代理
        // Proxy               loginInfo.Proxy();            用于获取代理
        // Map<String, Object> loginInfo.extras;             用于存放一些自定义变量
        Connection.Response response = jJsoup.connect("https://github.com/KingFalse", loginInfo)
                .method(Connection.Method.GET)
                .execute();

        // 携带FollowProcess
        FollowProcess followProcess = new FollowProcess() {
            /**
             * 用于解析返回数据,必须重写
             * @param connection
             * @param loginInfo
             * @return
             */
            @Override
            public String doProcess(Connection connection, LoginInfo loginInfo) {
                String title = "";
                try {
                    Document responseDocument = connection.response().parse();
                    title = responseDocument.title();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return title;
            }

            /**
             * 用于处理请求时发生的异常
             * 请求时发生异常会自动重试5次
             * 5次都失败进入此方法
             * 带入最后一次的异常
             * @param connection
             * @param loginInfo
             * @param e
             * @throws Exception
             */
            @Override
            public void doException(Connection connection, LoginInfo loginInfo, Exception e) throws Exception {
                super.doException(connection, loginInfo, e);
            }

            /**
             * 用于逻辑性的请求成功判断
             * 比如接口返回200,但是返回json提示系统超时,可以return false去重试请求
             * @param connection
             * @param loginInfo
             * @return
             */
            @Override
            public boolean isSuccess(Connection connection, LoginInfo loginInfo) {
                return super.isSuccess(connection, loginInfo);
            }
        };
        response = jJsoup.connect("https://github.com/KingFalse", loginInfo, followProcess)
                .method(Connection.Method.GET)
                .execute();
        System.err.println(followProcess.result);


    }

}

依赖版本:

  • spring boot 建议1.5以上
  • jsoup 1.9.1 以上(默认最新,目前1.11.3)

@JSONBodyField

请求时务必添加Content-Type: application/json;请求头

// POST发送json到RestController:{"name":"kagura"}

// 常规写法:
@RestController
class AuthController{
    @PostMapping("post")
    public ResponseEntity post(@RequestBody String body){
        JSONObject jsonObject = JSON.parseObject(body);
        System.err.println(jsonObject.getString("name"));
        return ResponseEntity.ok("OK");
    }
}

// 使用@JSONBodyField
@RestController
class AuthController {
    @PostMapping("post")
    public ResponseEntity post(
            @JSONBodyField String name //如果是请求体的根元素不用写jsonPath
//          @JSONBodyField("$.name") String name
    ) {
        System.err.println(name);
        return ResponseEntity.ok("OK");
    }
}

@LoginInfoKey (LoginInfo自动获取)

@LoginInfoKey注解用于在Controller的方法参数中指定某个参数作为LoginInfo的key,用于实现自动从redis获取对应的LoginInfo

@RestController
class AuthController {
    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String loginInfo(LoginInfo loginInfo, @LoginInfoKey @RequestParam String traceid
    ) {
        // 此时jjsoup会根据traceid去redis中拿对应的LoginInfo对象赋值给loginInfo
        System.err.println(loginInfo.toString());
        return "OK";
    }
}

LoginInfo自动保存

  • 默认情况下jjsoup自带的切面会将@Service中所有带LoginInfo类型参数的方法的@AfterReturning跟AfterThrowing时自动将LoginInfo序列化到redis
  • 如果不需要序列化时请使用@LoginInfoSolidify(false),加在对应的方法或者类名上

关于LoginInfo自动存取

  • jjsoup自带了一个redis序列化实现,您只需要添加spring-boot-starter-data-redis即可
  • 如果您的项目没有使用redis进行缓存,或者您想自定义缓存策略时可以实现me.kagura.LoginInfoSerializable接口并添加@Component即可

统一初始化

  • 用于需要给所有的请求设置属性的时候
  • 比如要爬取的网站很容易超时,则需要对每个请求设置超时时间
import me.kagura.InitConnection;
import org.jsoup.Connection;

@Component
class initJsoup implements InitConnection {

    @Override
    public void init(Connection connection) {
        connection.proxy("127.0.0.1", 8888);
        connection.timeout(50000);
        connection.followRedirects(true);
        connection.maxBodySize(1024 * 10);
    }
}

统一过滤器

  • 用于请求执行后统一处理
  • 比如将请求结果输出到控制台,或者上传OSS等需求
  • 注意:
  • FollowFilter会在请求结束后最先执行,如果您需要使用response.bodyStream()获取流时请在doFilter方法中跳过对此请求的处理,否则会导致java.lang.IllegalArgumentException: Request has already been read异常
@Component
class OSSFilter implements FollowFilter {

    @Override
    public void doFilter(Connection connection, LoginInfo loginInfo) {
        if (loginInfo == null) {
            return;
        }
        System.err.println(connection.response().body());
    }
}

CaptchaTool

  • 用于在单元测试时辅助填充图片/短信验证码
import me.kagura.util.CaptchaTool;
import javax.swing.*;
import java.util.Base64;

public class CaptchaToolTest {

    public static void main(String[] args) {
        String base64 = "data:image/png;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcG...";
        // 图片验证码
        String captcha = CaptchaTool.show(base64);
        System.err.println(captcha);
        // 短信验证码
        String sms = CaptchaTool.show();
        System.err.println(sms);
    }

}

图片验证码 短信验证码

特点

  • 自动重试
  • 自动设置Content-Type: application/json;
  • 自动存取LoginInfo
  • @JSONBodyField json请求解析更优雅

欢迎加微信

Work on it

Work on it

Versions

Version
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3