diff --git a/src/main/java/com/tem/bocai/controller/LoginCrawler.java b/src/main/java/com/tem/bocai/controller/LoginCrawler.java index 0451bc7..c0d70b9 100644 --- a/src/main/java/com/tem/bocai/controller/LoginCrawler.java +++ b/src/main/java/com/tem/bocai/controller/LoginCrawler.java @@ -1,15 +1,16 @@ package com.tem.bocai.controller; +import com.tem.bocai.param.LoginInfoParam; import com.tem.bocai.service.LoginService; import com.tem.bocai.util.ImageOcrService; import net.sourceforge.tess4j.TesseractException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import java.io.IOException; @RestController +@RequestMapping("/ocr") public class LoginCrawler { private final LoginService loginService; @@ -18,14 +19,14 @@ public class LoginCrawler { public LoginCrawler(LoginService loginService) { this.loginService = loginService; } - @GetMapping("/ocr/login") - public ResponseEntity ocrLocalImage(String username, String password,String loginUrl,Integer winNum,Integer loseNum) throws IOException, TesseractException { - String result = loginService.loginAutomatic(username,password,loginUrl,winNum,loseNum); + @PostMapping("/login") + public ResponseEntity ocrLocalImage(@RequestBody LoginInfoParam loginInfoParam) throws IOException, TesseractException { + String result = loginService.loginAutomatic(loginInfoParam); return ResponseEntity.ok(result); } //今日已结爬取 - @GetMapping("/ocr/completedToday") + @GetMapping("/completedToday") public ResponseEntity completedToday() throws IOException, TesseractException { String result = loginService.completedToday(); return ResponseEntity.ok(result); diff --git a/src/main/java/com/tem/bocai/entity/LoginInfoResult.java b/src/main/java/com/tem/bocai/entity/LoginInfoResult.java index dfffc66..8bfcf1e 100644 --- a/src/main/java/com/tem/bocai/entity/LoginInfoResult.java +++ b/src/main/java/com/tem/bocai/entity/LoginInfoResult.java @@ -3,6 +3,8 @@ package com.tem.bocai.entity; import jakarta.persistence.*; import lombok.Data; import net.sourceforge.tess4j.TesseractException; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; import org.springframework.http.ResponseEntity; import java.io.IOException; @@ -36,12 +38,13 @@ public class LoginInfoResult { @Column(name = "lose_num", nullable = false) private Integer loseNum; -/* @Column(name = "current_num", nullable = false) - private Integer currentNum;*/ - - @Column(name = "create_time", nullable = false) + /* @Column(name = "current_num", nullable = false) + private Integer currentNum;*/ + @Column(name = "create_time", nullable = false, updatable = false) + @Temporal(TemporalType.TIMESTAMP) private Date createTime; @Column(name = "update_time", nullable = false) + @Temporal(TemporalType.TIMESTAMP) private Date updateTime; - } \ No newline at end of file +} \ No newline at end of file diff --git a/src/main/java/com/tem/bocai/param/LoginInfoParam.java b/src/main/java/com/tem/bocai/param/LoginInfoParam.java new file mode 100644 index 0000000..b19380e --- /dev/null +++ b/src/main/java/com/tem/bocai/param/LoginInfoParam.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. + * + * https://www.mall4j.com/ + * + * 未经允许,不可做商业用途! + * + * 版权所有,侵权必究! + */ + +package com.tem.bocai.param; + +import lombok.Data; + +@Data +public class LoginInfoParam { + + public String username; + public String password; + public String loginUrl; + public Integer winNum; + public Integer loseNum; + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getLoginUrl() { + return loginUrl; + } + + public void setLoginUrl(String loginUrl) { + this.loginUrl = loginUrl; + } + + public Integer getWinNum() { + return winNum; + } + + public void setWinNum(Integer winNum) { + this.winNum = winNum; + } + + public Integer getLoseNum() { + return loseNum; + } + + public void setLoseNum(Integer loseNum) { + this.loseNum = loseNum; + } +} diff --git a/src/main/java/com/tem/bocai/repository/LoginInfoRepository.java b/src/main/java/com/tem/bocai/repository/LoginInfoRepository.java new file mode 100644 index 0000000..c32dc44 --- /dev/null +++ b/src/main/java/com/tem/bocai/repository/LoginInfoRepository.java @@ -0,0 +1,17 @@ +package com.tem.bocai.repository; + + +import com.tem.bocai.entity.LoginInfoResult; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface LoginInfoRepository extends JpaRepository { + Optional findByUsername(String username); + boolean existsByUsername(String username); + void deleteByUsername(String username); + // 方法1: 按创建时间倒序取第一条 + Optional findFirstByOrderByCreateTimeDesc(); +} diff --git a/src/main/java/com/tem/bocai/service/LoginService.java b/src/main/java/com/tem/bocai/service/LoginService.java index 47aa515..f5b7903 100644 --- a/src/main/java/com/tem/bocai/service/LoginService.java +++ b/src/main/java/com/tem/bocai/service/LoginService.java @@ -1,9 +1,11 @@ package com.tem.bocai.service; +import com.tem.bocai.param.LoginInfoParam; + public interface LoginService { - String loginAutomatic(String username, String password,String loginUrl,Integer winNum,Integer loseNum); + String loginAutomatic(LoginInfoParam loginInfoParam); //获取token String completedToday(); diff --git a/src/main/java/com/tem/bocai/service/impl/LoginServiceImpl.java b/src/main/java/com/tem/bocai/service/impl/LoginServiceImpl.java index 921f803..a94977c 100644 --- a/src/main/java/com/tem/bocai/service/impl/LoginServiceImpl.java +++ b/src/main/java/com/tem/bocai/service/impl/LoginServiceImpl.java @@ -1,58 +1,45 @@ package com.tem.bocai.service.impl; import com.tem.bocai.entity.LoginInfoResult; +import com.tem.bocai.param.LoginInfoParam; +import com.tem.bocai.repository.LoginInfoRepository; +import com.tem.bocai.repository.LotteryResultRepository; import com.tem.bocai.service.LoginService; import com.tem.bocai.util.*; +import jakarta.transaction.Transactional; +import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import net.sourceforge.tess4j.Tesseract; -import net.sourceforge.tess4j.TesseractException; -import org.apache.http.Header; -import org.apache.http.NameValuePair; -import org.apache.http.client.CookieStore; -import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.*; -import org.apache.http.impl.client.BasicCookieStore; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.util.EntityUtils; import org.springframework.beans.factory.annotation.Autowired; - -import javax.imageio.ImageIO; -import java.awt.image.BufferedImage; import java.io.*; -import java.util.ArrayList; +import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.Map; - -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; - -import org.apache.http.client.config.RequestConfig; -import org.apache.http.cookie.Cookie; import us.codecraft.webmagic.Spider; @Service public class LoginServiceImpl implements LoginService { - private static final String BASE_URL = "https://4701268539-esh.qdk63ayw8g.com"; private static final int MAX_RETRY = 10; @Autowired - private Tesseract tesseract; - @Autowired private TokenCacheService tokenCacheService; + @Autowired + private LoginInfoRepository loginInfoRepository; + private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @Override - public String loginAutomatic(String username, String password, String loginUrl, Integer winNum, Integer loseNum) { + public String loginAutomatic(LoginInfoParam loginInfoParam) { String token = ""; for (int attempt = 1; attempt <= MAX_RETRY; attempt++) { System.out.println("\n=== 第 " + attempt + " 次尝试 ==="); try { - token = tokenCacheService.attemptLogin(); + token = tokenCacheService.attemptLogin(loginInfoParam); + System.out.println("1token = " + token); tokenCacheService.saveToken(token); if (token != null && !token.isEmpty()) { //保存用户信息 - addLoginInfo(username, password, loginUrl, winNum, loseNum); + addLoginInfo(loginInfoParam); // 2. 创建爬虫实例,传入token LotteryWebMagicCrawler crawler = new LotteryWebMagicCrawler(token); @@ -69,8 +56,6 @@ public class LoginServiceImpl implements LoginService { // 5. 返回爬取的数据 List> result = pipeline.getLotteryData(); - System.out.println("爬虫完成,获取到 " + result.size() + " 条数据"); - System.out.println("===="+result); return result.toString(); } @@ -109,14 +94,13 @@ public class LoginServiceImpl implements LoginService { /** * 添加登录信息 */ - public boolean addLoginInfo(String username, String password, - String loginUrl, Integer winNum, Integer loseNum) { + public boolean addLoginInfo(LoginInfoParam loginInfoParam) { LoginInfoResult loginInfo = new LoginInfoResult(); - loginInfo.setUsername(username); - loginInfo.setPassword(password); - loginInfo.setLoginUrl(loginUrl); - loginInfo.setWinNum(winNum != null ? winNum : 0); - loginInfo.setLoseNum(loseNum != null ? loseNum : 0); + loginInfo.setUsername(loginInfoParam.getUsername()); + loginInfo.setPassword(loginInfoParam.getPassword()); + loginInfo.setLoginUrl(loginInfoParam.getLoginUrl()); + loginInfo.setWinNum(loginInfoParam.getWinNum() != null ? loginInfoParam.getWinNum() : 0); + loginInfo.setLoseNum(loginInfoParam.getLoseNum() != null ? loginInfoParam.getLoseNum() : 0); loginInfo.setCreateTime(new Date()); loginInfo.setUpdateTime(new Date()); diff --git a/src/main/java/com/tem/bocai/util/SQLiteUtil.java b/src/main/java/com/tem/bocai/util/SQLiteUtil.java index 1dca1d5..7db64e3 100644 --- a/src/main/java/com/tem/bocai/util/SQLiteUtil.java +++ b/src/main/java/com/tem/bocai/util/SQLiteUtil.java @@ -3,9 +3,11 @@ package com.tem.bocai.util; import com.tem.bocai.entity.LoginInfoResult; import java.sql.*; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Date; public class SQLiteUtil { private static final String DB_URL = "jdbc:sqlite:bocai.db"; @@ -287,16 +289,23 @@ public class SQLiteUtil { insertStmt.setString(3, loginInfo.getLoginUrl()); insertStmt.setInt(4, loginInfo.getWinNum() != null ? loginInfo.getWinNum() : 0); insertStmt.setInt(5, loginInfo.getLoseNum() != null ? loginInfo.getLoseNum() : 0); - insertStmt.setTimestamp(6, new Timestamp( - loginInfo.getCreateTime() != null ? - loginInfo.getCreateTime().getTime() : - System.currentTimeMillis() - )); - insertStmt.setTimestamp(7, new Timestamp( - loginInfo.getUpdateTime() != null ? - loginInfo.getUpdateTime().getTime() : - System.currentTimeMillis() - )); + + // 使用ISO8601格式: yyyy-MM-dd HH:mm:ss + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + // 处理create_time + if (loginInfo.getCreateTime() != null) { + insertStmt.setString(6, sdf.format(loginInfo.getCreateTime())); + } else { + insertStmt.setString(6, sdf.format(new Date())); + } + + // 处理update_time + if (loginInfo.getUpdateTime() != null) { + insertStmt.setString(7, sdf.format(loginInfo.getUpdateTime())); + } else { + insertStmt.setString(7, sdf.format(new Date())); + } int inserted = insertStmt.executeUpdate(); diff --git a/src/main/java/com/tem/bocai/util/TokenCacheService.java b/src/main/java/com/tem/bocai/util/TokenCacheService.java index 804f225..206a20e 100644 --- a/src/main/java/com/tem/bocai/util/TokenCacheService.java +++ b/src/main/java/com/tem/bocai/util/TokenCacheService.java @@ -1,6 +1,10 @@ package com.tem.bocai.util; +import com.tem.bocai.entity.LoginInfoResult; +import com.tem.bocai.param.LoginInfoParam; +import com.tem.bocai.repository.LoginInfoRepository; import com.tem.bocai.service.LoginService; +import lombok.val; import net.sourceforge.tess4j.Tesseract; import net.sourceforge.tess4j.TesseractException; import org.apache.http.Header; @@ -44,7 +48,8 @@ public class TokenCacheService { private Tesseract tesseract; @Autowired private CacheManager tokenCacheManager; - + @Autowired + private LoginInfoRepository loginInfoRepository; /** * 保存token到缓存 */ @@ -126,8 +131,14 @@ public class TokenCacheService { for (int attempt = 1; attempt <= MAX_RETRY; attempt++) { System.out.println("\n=== 第 " + attempt + " 次尝试 ==="); try { - token = attemptLogin(); - + LoginInfoResult firstByOrderByCreateTimeDesc = loginInfoRepository.findFirstByOrderByCreateTimeDesc() + .orElse(null); + LoginInfoParam loginInfoParam = new LoginInfoParam(); + loginInfoParam.setUsername(firstByOrderByCreateTimeDesc.getUsername()); + loginInfoParam.setPassword(firstByOrderByCreateTimeDesc.getPassword()); + loginInfoParam.setLoginUrl(firstByOrderByCreateTimeDesc.getLoginUrl()); + token = attemptLogin(loginInfoParam); + System.out.println("2token = " + token); if (token != null && !token.isEmpty()) { return token; } @@ -153,7 +164,7 @@ public class TokenCacheService { /** * 单次登录尝试 */ - public String attemptLogin() { + public String attemptLogin(LoginInfoParam loginInfoParam) { CookieStore cookieStore = new BasicCookieStore(); try (CloseableHttpClient httpClient = createHttpClient(cookieStore)) { // 1. 获取验证码 @@ -167,7 +178,7 @@ public class TokenCacheService { return null; } // 3. 执行登录 - return performLogin(httpClient, cookieStore, code); + return performLogin(httpClient, cookieStore, code,loginInfoParam); } catch (Exception e) { System.out.println("登录尝试失败" + e); @@ -262,13 +273,13 @@ public class TokenCacheService { */ private String performLogin(CloseableHttpClient httpClient, CookieStore cookieStore, - String code) throws IOException, InterruptedException { + String code,LoginInfoParam loginInfoParam) throws IOException, InterruptedException { System.out.println("执行登录..."); // 等待一下再发送登录请求 Thread.sleep(1500 + (long) (Math.random() * 1000)); - HttpPost loginPost = createLoginRequest(code); + HttpPost loginPost = createLoginRequest(code,loginInfoParam); try (CloseableHttpResponse loginResponse = httpClient.execute(loginPost)) { return processLoginResponse(loginResponse, cookieStore); @@ -278,20 +289,20 @@ public class TokenCacheService { /** * 创建登录请求 */ - private HttpPost createLoginRequest(String code) throws UnsupportedEncodingException { - HttpPost loginPost = new HttpPost(BASE_URL + "/login"); + private HttpPost createLoginRequest(String code,LoginInfoParam loginInfoParam) throws UnsupportedEncodingException { + HttpPost loginPost = new HttpPost(loginInfoParam.loginUrl + "/login"); // 设置请求头 setCommonHeaders(loginPost); - loginPost.setHeader("Referer", BASE_URL + "/login"); - loginPost.setHeader("Origin", BASE_URL); + loginPost.setHeader("Referer", loginInfoParam.loginUrl + "/login"); + loginPost.setHeader("Origin", loginInfoParam.loginUrl); loginPost.setHeader("Accept", "application/json, text/plain, */*"); // 构建登录参数 List params = new ArrayList<>(); params.add(new BasicNameValuePair("type", "1")); - params.add(new BasicNameValuePair("account", "pmk1")); - params.add(new BasicNameValuePair("password", "Asd123123")); + params.add(new BasicNameValuePair("account", loginInfoParam.username)); + params.add(new BasicNameValuePair("password", loginInfoParam.password)); params.add(new BasicNameValuePair("code", code)); loginPost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));