# jjsoup-spring-boot-starter
**Repository Path**: Kagura/jjsoup-spring-boot-starter
## Basic Information
- **Project Name**: jjsoup-spring-boot-starter
- **Description**: jjsoup-spring-boot-starter是对jsoup的无侵入封装,使它更好的适合于网络爬虫开发
- **Primary Language**: Java
- **License**: MIT
- **Default Branch**: master
- **Homepage**: https://github.com/KingFalse/jjsoup-spring-boot-starter
- **GVP Project**: No
## Statistics
- **Stars**: 2
- **Forks**: 1
- **Created**: 2018-09-19
- **Last Updated**: 2023-03-02
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# jjsoup-spring-boot-starter
**jjsoup-spring-boot-starter是对jsoup的无侵入封装,使它更好的适合于网络爬虫开发[Powered by Jsoup](https://github.com/jhy/jsoup)**
**Demo项目:[https://github.com/KingFalse/didi-app-auth-crawler](https://github.com/KingFalse/didi-app-auth-crawler)**
[](https://maven-badges.herokuapp.com/maven-central/me.kagura/jjsoup-spring-boot-starter)
## 如何使用:
**在spring boot项目中引入:**
```xml
me.kagura
jjsoup-spring-boot-starter
0.1.5
com.alibaba
fastjson
x.x
org.springframework.boot
spring-boot-starter-data-redis
```
**快速开始:**
```java
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 loginInfo.cookies; 用于存放cookie
// Proxy loginInfo.Proxy(Proxy proxy); 用于设置代理
// Proxy loginInfo.Proxy(); 用于获取代理
// Map 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;请求头**
```java
// 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**
```java
@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即可**
## 统一初始化
> * **用于需要给所有的请求设置属性的时候**
> * **比如要爬取的网站很容易超时,则需要对每个请求设置超时时间**
```java
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`异常**
```java
@Component
class OSSFilter implements FollowFilter {
@Override
public void doFilter(Connection connection, LoginInfo loginInfo) {
if (loginInfo == null) {
return;
}
System.err.println(connection.response().body());
}
}
```
## CaptchaTool
> * **用于在单元测试时辅助填充图片/短信验证码**
```java
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请求解析更优雅**
## 欢迎加微信

