Compare commits
15 Commits
9460367dc1
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67335e08aa | ||
| 029109d559 | |||
|
|
740dc15197 | ||
| 274f2a31af | |||
|
|
f6a9730879 | ||
|
|
e1695854a8 | ||
| 7a61514e1c | |||
| 22e3d844bf | |||
|
|
1a562ffc1c | ||
| 3f7b0568d3 | |||
|
|
419e00e74a | ||
| bded6f899b | |||
| c7918ad0e4 | |||
| 9376a85673 | |||
| 3f4e0b8f8f |
@@ -4,13 +4,13 @@ import axios from 'axios';
|
||||
import * as echarts from 'echarts';
|
||||
|
||||
// 输入框数据
|
||||
const input1 = ref('');
|
||||
const input2 = ref('');
|
||||
const betAmount = ref('');
|
||||
|
||||
// 登录模态框数据
|
||||
const loginDialogVisible = ref(false);
|
||||
const isLoggedIn = ref(false);
|
||||
const username = ref('未记录');
|
||||
const balance = ref('0'); // 余额
|
||||
const loginForm = ref({
|
||||
username: '',
|
||||
password: '',
|
||||
@@ -237,20 +237,20 @@ async function fetchUserSettings() {
|
||||
username.value = response.data.username;
|
||||
isLoggedIn.value = true;
|
||||
}
|
||||
// 更新止盈点
|
||||
if (response.data.winNum) {
|
||||
input1.value = response.data.winNum;
|
||||
// 更新投注金额
|
||||
if (response.data.betAmount) {
|
||||
betAmount.value = response.data.betAmount;
|
||||
}
|
||||
// 更新止亏点
|
||||
if (response.data.loseNum) {
|
||||
input2.value = response.data.loseNum;
|
||||
// 更新余额
|
||||
if (response.data.balance) {
|
||||
balance.value = response.data.balance;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('用户设置数据获取完成');
|
||||
console.log('username.value:', username.value);
|
||||
console.log('input1.value:', input1.value);
|
||||
console.log('input2.value:', input2.value);
|
||||
console.log('betAmount.value:', betAmount.value);
|
||||
console.log('balance.value:', balance.value);
|
||||
} catch (err) {
|
||||
console.error('获取用户设置数据失败:', err);
|
||||
// 失败时不显示错误,使用默认值
|
||||
@@ -343,19 +343,18 @@ function handleLogout() {
|
||||
|
||||
// 处理确认按钮点击
|
||||
async function handleConfirm() {
|
||||
console.log('确认按钮点击,止盈点:', input1.value, '止亏点:', input2.value);
|
||||
console.log('确认按钮点击,投注金额:', betAmount.value);
|
||||
|
||||
// 验证输入
|
||||
if (!input1.value || !input2.value) {
|
||||
alert('请填写完整的止盈止亏点');
|
||||
if (!betAmount.value) {
|
||||
alert('请填写投注金额');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 构建提交数据
|
||||
const submitData = {
|
||||
winNum: input1.value,
|
||||
loseNum: input2.value
|
||||
betAmount: betAmount.value
|
||||
};
|
||||
|
||||
console.log('提交数据:', submitData);
|
||||
@@ -446,6 +445,7 @@ onUnmounted(() => {
|
||||
<div class="account-avatar">👤</div>
|
||||
<div class="account-details">
|
||||
<div class="account-name">{{ username }}</div>
|
||||
<div class="account-balance">余额: {{ balance }}</div>
|
||||
</div>
|
||||
<div class="account-actions">
|
||||
<button type="button" class="login-button" @click="loginDialogVisible = true">账号信息</button>
|
||||
@@ -493,15 +493,9 @@ onUnmounted(() => {
|
||||
<!-- 顶部输入框区域 -->
|
||||
<div class="top-inputs">
|
||||
<div class="input-group">
|
||||
<label for="input1">止盈点:</label>
|
||||
<label for="betAmount">投注金额:</label>
|
||||
<div class="input-with-button">
|
||||
<input type="text" id="input1" v-model="input1" placeholder="请输入止盈点">
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label for="input2">止亏点:</label>
|
||||
<div class="input-with-button">
|
||||
<input type="text" id="input2" v-model="input2" placeholder="请输入止亏点">
|
||||
<input type="text" id="betAmount" v-model="betAmount" placeholder="请输入投注金额">
|
||||
<div class="button-group">
|
||||
<button type="button" class="confirm-button" @click="handleConfirm">确认</button>
|
||||
</div>
|
||||
@@ -612,6 +606,11 @@ onUnmounted(() => {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.account-balance {
|
||||
font-size: 0.85rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.account-role {
|
||||
font-size: 0.85rem;
|
||||
color: #666;
|
||||
@@ -683,14 +682,15 @@ onUnmounted(() => {
|
||||
.input-group {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.input-with-button {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: flex-start;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.input-with-button input {
|
||||
|
||||
@@ -18,9 +18,9 @@ public class BocaiApplication {
|
||||
// // 依次执行三个任务
|
||||
//
|
||||
// 1. 执行CrawlerSchedule方法
|
||||
// System.out.println("\n=== 开始执行CrawlerSchedule任务 ===");
|
||||
// CrawlerSchedule crawlerSchedule = context.getBean(CrawlerSchedule.class);
|
||||
// crawlerSchedule.executeLotteryDraw();
|
||||
System.out.println("\n=== 开始执行初始化爬取最近7天的开奖结果任务 ===");
|
||||
CrawlerSchedule crawlerSchedule = context.getBean(CrawlerSchedule.class);
|
||||
crawlerSchedule.executeLotteryDrawHistory();
|
||||
//
|
||||
// 3. 执行ExBetScriptSchedule方法
|
||||
// System.out.println("\n=== 开始执行ExBetScriptSchedule任务 ===");
|
||||
|
||||
@@ -12,8 +12,8 @@ public class TessConfig {
|
||||
|
||||
Tesseract instance = new Tesseract();
|
||||
instance.setLanguage("oci"); // 设置语言包,这里使用英语
|
||||
instance.setDatapath("src/main/resources/tessdata"); // 设置语言包路径
|
||||
// instance.setDatapath("tessdata"); // 设置语言包路径
|
||||
// instance.setDatapath("src/main/resources/tessdata"); // 设置语言包路径
|
||||
instance.setDatapath("tessdata"); // 设置语言包路径
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,10 +61,7 @@ public class ChartController {
|
||||
// 生成每5分钟的时间间隔标签
|
||||
List<String> labels = new ArrayList<>();
|
||||
List<Double> data = new ArrayList<>();
|
||||
|
||||
// 计算累计盈亏
|
||||
double totalProfit = 0.0;
|
||||
|
||||
|
||||
// 遍历每5分钟间隔
|
||||
Calendar intervalCalendar = (Calendar) calendar.clone();
|
||||
while (intervalCalendar.getTime().before(currentTime)) {
|
||||
@@ -79,20 +76,12 @@ public class ChartController {
|
||||
intervalProfit += item.getResultAmount();
|
||||
}
|
||||
}
|
||||
|
||||
// 更新总盈亏
|
||||
totalProfit = intervalProfit;
|
||||
data.add(totalProfit);
|
||||
data.add(intervalProfit);
|
||||
|
||||
// 增加5分钟
|
||||
intervalCalendar.add(Calendar.MINUTE, 5);
|
||||
}
|
||||
|
||||
// 添加当前时间点的数据
|
||||
if (!labels.isEmpty()) {
|
||||
String currentTimeLabel = DateFormatUtils.format(currentTime, "HH:mm");
|
||||
labels.add(currentTimeLabel);
|
||||
data.add(totalProfit);
|
||||
|
||||
}
|
||||
|
||||
// 如果没有今日数据,生成默认的5分钟间隔数据
|
||||
|
||||
@@ -56,6 +56,8 @@ public class LoginInfoResult {
|
||||
@Column(name = "balance")
|
||||
private String balance;
|
||||
|
||||
private Integer betAmount;
|
||||
|
||||
@Column(name = "create_time", nullable = false, updatable = false)
|
||||
@CreationTimestamp
|
||||
@Convert(converter = SQLiteDateConverter.class)
|
||||
|
||||
@@ -19,39 +19,41 @@ public class LotteryResult {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
/*@Column(name = "id", nullable = false, unique = true)
|
||||
/*@Column(name = "id", unique = true)
|
||||
private String id; // 期号*/
|
||||
|
||||
@Column(name = "issue", nullable = false, unique = true)
|
||||
@Column(name = "issue", unique = true)
|
||||
private String issue; // 期号
|
||||
|
||||
@Column(name = "time", nullable = false)
|
||||
@Column(name = "time")
|
||||
private String time; // 开奖时间
|
||||
|
||||
@Column(name = "result")
|
||||
private String result; // 开奖号码
|
||||
|
||||
@Column(name = "winner", nullable = false)
|
||||
@Column(name = "winner")
|
||||
private String winner; //
|
||||
|
||||
|
||||
@Column(name = "sum1", nullable = false)
|
||||
@Column(name = "sum1")
|
||||
private String sum1; // 总和值
|
||||
|
||||
@Column(name = "sum2", nullable = false)
|
||||
@Column(name = "sum2")
|
||||
private String sum2; // 冠亚和
|
||||
|
||||
|
||||
|
||||
@Column(name = "gd1", nullable = false)
|
||||
@Column(name = "gd1")
|
||||
private String gd1; // 冠亚单
|
||||
|
||||
|
||||
@Column(name = "gd2", nullable = false)
|
||||
@Column(name = "gd2")
|
||||
private String gd2; // 冠亚大
|
||||
|
||||
|
||||
@Column(name = "glh_result", nullable = false)
|
||||
@Column(name = "glh_result")
|
||||
private String glh_result; //[ "龙", "龙", "龙", "虎", "虎" ] 龙虎
|
||||
|
||||
@Column(name = "bet_result")
|
||||
private String betResult;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.tem.bocai.schedules;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.tem.bocai.util.TokenCacheService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -20,9 +21,11 @@ import java.util.Optional;
|
||||
import org.json.JSONObject;
|
||||
import com.tem.bocai.entity.LoginInfoResult;
|
||||
import com.tem.bocai.entity.BetRecord;
|
||||
import com.tem.bocai.entity.LotteryResult;
|
||||
import com.tem.bocai.repository.CompletedTodayRepository;
|
||||
import com.tem.bocai.repository.LoginInfoRepository;
|
||||
import com.tem.bocai.repository.BetRecordRepository;
|
||||
import com.tem.bocai.repository.LotteryResultRepository;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@@ -40,8 +43,11 @@ public class BetSchedule {
|
||||
@Autowired
|
||||
private BetRecordRepository betRecordRepository;
|
||||
|
||||
@Autowired
|
||||
private LotteryResultRepository lotteryResultRepository;
|
||||
|
||||
// 从7:02分钟起每5分钟执行一次
|
||||
@Scheduled(cron = "30 2/5 * * * ?")
|
||||
@Scheduled(cron = "30 2/5 * * * ?")
|
||||
public void placeBet() {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
int hour = now.getHour();
|
||||
@@ -74,32 +80,32 @@ public class BetSchedule {
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查winNum和loseNum字段是否合理
|
||||
Integer winNum = loginInfo.getWinNum();
|
||||
Integer loseNum = loginInfo.getLoseNum();
|
||||
|
||||
if (winNum != null || loseNum != null) {
|
||||
// 根据LoginInfo的startTime 查询CompletedToday的resultAmount总和 判断是否达到 winNum 和 loseNum的值
|
||||
Date startTime = loginInfo.getStartTime();
|
||||
if (startTime != null) {
|
||||
Double totalResultAmount = completedTodayRepository.sumResultAmountByCreateTimeAfter(startTime);
|
||||
if (totalResultAmount != null) {
|
||||
log.info(" - 今日盈亏总和: {}", totalResultAmount);
|
||||
|
||||
// 判断是否达到止盈点
|
||||
if (totalResultAmount >= winNum) {
|
||||
log.info("{}", currentTime + " - 已达到止盈点 " + winNum + ",跳过执行");
|
||||
return;
|
||||
}
|
||||
|
||||
// 判断是否达到止亏点
|
||||
if (totalResultAmount <= -loseNum) {
|
||||
log.info("{}", currentTime + " - 已达到止亏点 " + loseNum + ",跳过执行");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// // 检查winNum和loseNum字段是否合理
|
||||
// Integer winNum = loginInfo.getWinNum();
|
||||
// Integer loseNum = loginInfo.getLoseNum();
|
||||
//
|
||||
// if (winNum != null || loseNum != null) {
|
||||
// // 根据LoginInfo的startTime 查询CompletedToday的resultAmount总和 判断是否达到 winNum 和 loseNum的值
|
||||
// Date startTime = loginInfo.getStartTime();
|
||||
// if (startTime != null) {
|
||||
// Double totalResultAmount = completedTodayRepository.sumResultAmountByCreateTimeAfter(startTime);
|
||||
// if (totalResultAmount != null) {
|
||||
// log.info(" - 今日盈亏总和: {}", totalResultAmount);
|
||||
//
|
||||
// // 判断是否达到止盈点
|
||||
// if (totalResultAmount >= winNum) {
|
||||
// log.info("{}", currentTime + " - 已达到止盈点 " + winNum + ",跳过执行");
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // 判断是否达到止亏点
|
||||
// if (totalResultAmount <= -loseNum) {
|
||||
// log.info("{}", currentTime + " - 已达到止亏点 " + loseNum + ",跳过执行");
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
log.info("{}", currentTime + " - 开始执行投注...");
|
||||
|
||||
@@ -202,9 +208,27 @@ public class BetSchedule {
|
||||
* 记录投注结果
|
||||
*/
|
||||
private void recordBetResult(String betData, String betResult) {
|
||||
// 这里可以实现将投注结果记录到数据库或日志文件的逻辑
|
||||
// 为了简单起见,我们这里只打印日志
|
||||
// 这里实现将投注结果记录到LotteryResult的betResult字段的逻辑
|
||||
String currentTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||
log.info(" - 投注记录: [{}] 数据: {}, 结果: {}", currentTime, betData, betResult);
|
||||
|
||||
try {
|
||||
// 解析betData获取drawNumber(term)
|
||||
com.alibaba.fastjson.JSONObject jsonObject = JSON.parseObject(betData);
|
||||
String drawNumber = jsonObject.getString("drawNumber");
|
||||
if (StringUtils.isBlank(drawNumber)){
|
||||
log.error(" - 新增LotteryResult记录失败:");
|
||||
return;
|
||||
}
|
||||
// 创建新的LotteryResult记录
|
||||
LotteryResult newLotteryResult = new LotteryResult();
|
||||
newLotteryResult.setIssue(drawNumber);
|
||||
newLotteryResult.setBetResult(betData);
|
||||
// 保存新记录
|
||||
lotteryResultRepository.save(newLotteryResult);
|
||||
log.info(" - 已新增LotteryResult记录,期号: {}", drawNumber);
|
||||
} catch (Exception e) {
|
||||
log.error(" - 新增LotteryResult记录失败:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ public class CrawlerSchedule {
|
||||
/*@Scheduled(cron = "0 6-59/5 7-23 * * ?")
|
||||
@Scheduled(cron = "0 0-55/5 0-6 * * ?")*/
|
||||
// 从7:00分30秒起每5分钟执行一次
|
||||
@Scheduled(cron = "30 0/5 * * * ?")
|
||||
@Scheduled(cron = "30 0/5 * * * ?")
|
||||
public void executeLotteryDraw() {
|
||||
log.info("开始爬取开奖结果");
|
||||
int retryCount = 0;
|
||||
@@ -105,7 +105,7 @@ public class CrawlerSchedule {
|
||||
}
|
||||
|
||||
|
||||
@Scheduled(cron = "55 0/5 * * * ?")
|
||||
@Scheduled(cron = "55 0/5 * * * ?")
|
||||
//@Scheduled(cron = "*/9 * * * * ?")
|
||||
public void executePksHistory() {
|
||||
log.info("开始获取历史开奖结果");
|
||||
@@ -337,4 +337,135 @@ public class CrawlerSchedule {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//开始爬取最近7天的开奖结果
|
||||
public void executeLotteryDrawHistory() {
|
||||
log.info("开始爬取最近7天的开奖结果");
|
||||
|
||||
LoginInfoResult firstByOrderByCreateTimeDesc = loginInfoRepository.findFirstByOrderByCreateTimeDesc()
|
||||
.orElse(null);
|
||||
if (firstByOrderByCreateTimeDesc == null) {
|
||||
log.error("未找到登录信息");
|
||||
return;
|
||||
}
|
||||
if(firstByOrderByCreateTimeDesc.getOnOff() == ONOFF){
|
||||
log.info("开关已关闭,停止爬取");
|
||||
return;
|
||||
}
|
||||
|
||||
String token = tokenCacheService.getToken();
|
||||
if (token == null || token.isEmpty()) {
|
||||
log.error("token为空");
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取过去7天的日期列表
|
||||
List<String> dateList = DateUtils.getLast7Days();
|
||||
|
||||
for (String date : dateList) {
|
||||
log.info("\n=== 开始爬取日期: {} 的数据 ===", date);
|
||||
|
||||
// 检查该日期的数据文件是否已存在且有数据
|
||||
if (isDateDataExists(date)) {
|
||||
log.info("日期 {} 的数据已存在,跳过爬取", date);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 对每个日期进行重试
|
||||
boolean success = crawlDataForDate(date, token);
|
||||
|
||||
if (success) {
|
||||
log.info("日期 {} 数据爬取成功", date);
|
||||
} else {
|
||||
log.error("日期 {} 数据爬取失败,已达到最大重试次数", date);
|
||||
}
|
||||
|
||||
// 每次请求后稍作等待,避免请求过于频繁
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
log.info("最近7天数据爬取完成");
|
||||
}
|
||||
|
||||
/**
|
||||
* 爬取指定日期的数据
|
||||
*/
|
||||
private boolean crawlDataForDate(String date, String token) {
|
||||
int retryCount = 0;
|
||||
boolean success = false;
|
||||
String currentToken = token;
|
||||
|
||||
LoginInfoResult loginInfo = loginInfoRepository.findFirstByOrderByCreateTimeDesc()
|
||||
.orElse(null);
|
||||
if (loginInfo == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (!success && retryCount < MAX_CRA) {
|
||||
log.info("\n=== 第 " + (retryCount + 1) + " 次尝试获取 " + date + " 的开奖结果 ===");
|
||||
|
||||
if (currentToken == null || currentToken.isEmpty()) {
|
||||
log.info("token为空,从数据库重新获取");
|
||||
currentToken = tokenCacheService.getTokenSqlite();
|
||||
if (currentToken == null) {
|
||||
log.error("无法获取有效token");
|
||||
retryCount++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
log.info("使用token: " + (currentToken.length() > 20 ? currentToken.substring(0, 20) + "..." : currentToken));
|
||||
|
||||
// 创建爬虫实例,传入token
|
||||
LotteryHistoryCrawler crawler = new LotteryHistoryCrawler(currentToken, pypath,date);
|
||||
|
||||
// 构建URL
|
||||
String url = loginInfo.getLoginUrl() + "/member/dresult?lottery=SGFT&date=" + date;
|
||||
|
||||
Spider.create(crawler)
|
||||
.addUrl(url)
|
||||
.thread(1)
|
||||
.run();
|
||||
|
||||
// 检查是否成功解析数据
|
||||
success = LotteryHistoryCrawler.isLastParseSuccess();
|
||||
|
||||
if (!success) {
|
||||
log.info("本次尝试未解析到数据");
|
||||
// 重新获取token(下次重试用)
|
||||
currentToken = tokenCacheService.getTokenSqlite();
|
||||
retryCount++;
|
||||
|
||||
// 等待一下再重试
|
||||
if (retryCount < MAX_CRA) {
|
||||
try {
|
||||
Thread.sleep(2000 * retryCount); // 等待时间递增
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.info("成功解析到数据");
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
/**
|
||||
* 检查指定日期的数据文件是否存在且包含数据
|
||||
*/
|
||||
private boolean isDateDataExists(String date) {
|
||||
try {
|
||||
List<LotteryResult> data = lotteryResultRepository.findByTimeContaining(date);
|
||||
return data != null && !data.isEmpty();
|
||||
} catch (Exception e) {
|
||||
log.warn("检查文件失败: " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,7 +26,9 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.tem.bocai.entity.BetRecord;
|
||||
import com.tem.bocai.entity.LotteryResult;
|
||||
import com.tem.bocai.repository.BetRecordRepository;
|
||||
import com.tem.bocai.repository.LotteryResultRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
@@ -39,93 +41,15 @@ public class ExBetScriptSchedule {
|
||||
@Autowired
|
||||
private BetRecordRepository betRecordRepository;
|
||||
|
||||
@Autowired
|
||||
private LotteryResultRepository lotteryResultRepository;
|
||||
|
||||
@Value("${pypath}")
|
||||
private String pypath;
|
||||
|
||||
/**
|
||||
* 检查PyModel/current_data目录下最新的文件是否存在新数据
|
||||
* @return 如果存在新数据返回true,否则返回false
|
||||
*/
|
||||
private boolean checkNewDataExists() {
|
||||
try {
|
||||
File currentDataDir = new File(pypath, "current_data");
|
||||
if (!currentDataDir.exists() || !currentDataDir.isDirectory()) {
|
||||
log.info("current_data目录不存在");
|
||||
return false;
|
||||
}
|
||||
|
||||
File[] files = currentDataDir.listFiles();
|
||||
if (files == null || files.length == 0) {
|
||||
log.info("current_data目录为空");
|
||||
return false;
|
||||
}
|
||||
|
||||
File latestFile = null;
|
||||
FileTime latestTime = null;
|
||||
|
||||
for (File file : files) {
|
||||
if (file.getName().endsWith(".json")) {
|
||||
Path path = Paths.get(file.getAbsolutePath());
|
||||
BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);
|
||||
FileTime fileTime = attrs.lastModifiedTime();
|
||||
|
||||
if (latestTime == null || fileTime.compareTo(latestTime) > 0) {
|
||||
latestTime = fileTime;
|
||||
latestFile = file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (latestFile == null) {
|
||||
log.info("未找到JSON文件");
|
||||
return false;
|
||||
}
|
||||
|
||||
LocalDateTime fileModifiedTime = LocalDateTime.ofInstant(
|
||||
latestTime.toInstant(),
|
||||
ZoneId.systemDefault()
|
||||
);
|
||||
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
LocalDateTime fiveMinutesAgo = now.minusMinutes(5);
|
||||
|
||||
if (fileModifiedTime.isAfter(fiveMinutesAgo)) {
|
||||
log.info("发现新数据文件: {}, 修改时间: {}", latestFile.getName(), fileModifiedTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||
return true;
|
||||
} else {
|
||||
log.info("最新数据文件: {}, 修改时间: {}, 超过5分钟,跳过执行", latestFile.getName(), fileModifiedTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||
return false;
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("检查新数据时发生错误:", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理文件路径,确保路径正确
|
||||
* @param filePath 文件路径
|
||||
* @return 处理后的文件路径
|
||||
*/
|
||||
private String handleFilePath(String filePath) {
|
||||
// 处理路径分隔符,统一使用系统默认分隔符
|
||||
filePath = filePath.replace("/", System.getProperty("file.separator"));
|
||||
filePath = filePath.replace("\\", System.getProperty("file.separator"));
|
||||
|
||||
// 如果路径包含空格,确保路径被正确处理
|
||||
// Runtime.exec会自动处理带空格的路径,不需要手动添加引号
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
ExBetScriptSchedule schedule = new ExBetScriptSchedule();
|
||||
schedule.executePythonScript();
|
||||
}
|
||||
|
||||
// 从7:01分钟起每5分钟执行一次
|
||||
@Scheduled(cron = "30 1/5 * * * ?")
|
||||
@Scheduled(cron = "30 1/5 * * * ?")
|
||||
public void executePythonScript() {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
int hour = now.getHour();
|
||||
@@ -148,8 +72,8 @@ public class ExBetScriptSchedule {
|
||||
|
||||
log.info("开始执行Python脚本...");
|
||||
|
||||
// 获取当前时间,格式化为yyyy-MM-dd HH:mm:ss
|
||||
String currentTime = java.time.LocalDateTime.now().format(
|
||||
// 获取当前时间减去5分钟,格式化为yyyy-MM-dd HH:mm:ss
|
||||
String currentTime = java.time.LocalDateTime.now().plusMinutes(5).format(
|
||||
java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
|
||||
);
|
||||
|
||||
@@ -387,4 +311,69 @@ public class ExBetScriptSchedule {
|
||||
log.error("保存投注记录到数据库失败:", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 检查数据库中最新的开奖记录是否存在新数据
|
||||
* @return 如果存在新数据返回true,否则返回false
|
||||
*/
|
||||
private boolean checkNewDataExists() {
|
||||
try {
|
||||
// 查询最新的开奖记录
|
||||
Optional<LotteryResult> latestResult = lotteryResultRepository.findTopByOrderByTimeDesc();
|
||||
if (!latestResult.isPresent()) {
|
||||
log.info("数据库中未找到开奖记录");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取最新记录的时间
|
||||
String timeStr = latestResult.get().getTime();
|
||||
if (timeStr == null || timeStr.isEmpty()) {
|
||||
log.info("最新开奖记录时间为空");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 解析时间字符串为LocalDateTime
|
||||
LocalDateTime recordTime;
|
||||
try {
|
||||
// 假设时间格式为yyyy-MM-dd HH:mm:ss
|
||||
recordTime = LocalDateTime.parse(timeStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||
} catch (Exception e) {
|
||||
log.error("解析开奖记录时间失败: {}", timeStr, e);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查时间是否在最近5分钟内
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
LocalDateTime fiveMinutesAgo = now.minusMinutes(5);
|
||||
|
||||
if (recordTime.isAfter(fiveMinutesAgo)) {
|
||||
log.info("发现新开奖记录: 期号={}, 时间={}", latestResult.get().getIssue(), timeStr);
|
||||
return true;
|
||||
} else {
|
||||
log.info("最新开奖记录: 期号={}, 时间={}, 超过5分钟,跳过执行", latestResult.get().getIssue(), timeStr);
|
||||
return false;
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("检查新数据时发生错误:", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理文件路径,确保路径正确
|
||||
* @param filePath 文件路径
|
||||
* @return 处理后的文件路径
|
||||
*/
|
||||
private String handleFilePath(String filePath) {
|
||||
// 处理路径分隔符,统一使用系统默认分隔符
|
||||
filePath = filePath.replace("/", System.getProperty("file.separator"));
|
||||
filePath = filePath.replace("\\", System.getProperty("file.separator"));
|
||||
|
||||
// 如果路径包含空格,确保路径被正确处理
|
||||
// Runtime.exec会自动处理带空格的路径,不需要手动添加引号
|
||||
|
||||
return filePath;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,6 +188,10 @@ public class LoginServiceImpl implements LoginService {
|
||||
if (loginInfoResult.getAmount() != null) {
|
||||
dbUser.setAmount(loginInfoResult.getAmount());
|
||||
}
|
||||
// 如果传入了 betAmount,写入到配置文件
|
||||
if (loginInfoResult.getBetAmount() != null) {
|
||||
writeBaseBetUnitToConfig(loginInfoResult.getBetAmount());
|
||||
}
|
||||
if (loginInfoResult.getOnOff() != null) {
|
||||
dbUser.setOnOff(loginInfoResult.getOnOff());
|
||||
if (loginInfoResult.getOnOff().equals(1)) {
|
||||
@@ -258,16 +262,115 @@ public class LoginServiceImpl implements LoginService {
|
||||
return SQLiteUtil.addOrUpdateLoginInfo(loginInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 BASE_BET_UNIT 值写入到配置文件,保留原有结构
|
||||
*/
|
||||
private void writeBaseBetUnitToConfig(Integer betAmount) {
|
||||
String configPath = pypath+"/conf.ini";
|
||||
java.io.File configFile = new java.io.File(configPath);
|
||||
if (configFile.exists()) {
|
||||
try {
|
||||
// 读取所有行
|
||||
java.util.List<String> lines = new java.util.ArrayList<>();
|
||||
try (java.io.BufferedReader br = new java.io.BufferedReader(new java.io.FileReader(configFile))) {
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
lines.add(line);
|
||||
}
|
||||
}
|
||||
|
||||
// 查找并更新 BASE_BET_UNIT 行
|
||||
boolean updated = false;
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
String line = lines.get(i);
|
||||
if (line.startsWith("BASE_BET_UNIT =")) {
|
||||
lines.set(i, "BASE_BET_UNIT = " + betAmount);
|
||||
updated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有找到,在 [init] 节末尾添加
|
||||
if (!updated) {
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
String line = lines.get(i);
|
||||
if (line.startsWith("[init]")) {
|
||||
// 找到 [init] 节,在其后添加
|
||||
for (int j = i + 1; j < lines.size(); j++) {
|
||||
String nextLine = lines.get(j);
|
||||
if (nextLine.startsWith("[")) {
|
||||
// 遇到下一个节,在此之前添加
|
||||
lines.add(j, "BASE_BET_UNIT = " + betAmount);
|
||||
updated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!updated) {
|
||||
// 如果是最后一个节,在文件末尾添加
|
||||
lines.add("BASE_BET_UNIT = " + betAmount);
|
||||
updated = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 写回文件
|
||||
if (updated) {
|
||||
try (java.io.BufferedWriter bw = new java.io.BufferedWriter(new java.io.FileWriter(configFile))) {
|
||||
for (String line : lines) {
|
||||
bw.write(line);
|
||||
bw.newLine();
|
||||
}
|
||||
}
|
||||
System.out.println("BASE_BET_UNIT 已更新为: " + betAmount);
|
||||
} else {
|
||||
System.err.println("未找到 [init] 节,无法更新 BASE_BET_UNIT");
|
||||
}
|
||||
} catch (java.io.IOException e) {
|
||||
System.err.println("读写配置文件失败: " + e.getMessage());
|
||||
}
|
||||
} else {
|
||||
System.err.println("配置文件不存在: " + configPath);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoginInfoResult getUserSettings() {
|
||||
try {
|
||||
// 获取最新的用户设置信息
|
||||
Optional<LoginInfoResult> existingUser = loginInfoRepository.findFirstByOrderByCreateTimeDesc();
|
||||
LoginInfoResult loginInfoResult;
|
||||
if (existingUser.isPresent()) {
|
||||
return existingUser.get();
|
||||
loginInfoResult = existingUser.get();
|
||||
} else {
|
||||
// 如果没有找到,返回一个空的对象
|
||||
loginInfoResult = new LoginInfoResult();
|
||||
}
|
||||
// 如果没有找到,返回一个空的对象
|
||||
return new LoginInfoResult();
|
||||
|
||||
// 读取 PyModel/conf.ini 文件中的 BASE_BET_UNIT 值
|
||||
String configPath = pypath+"/conf.ini";
|
||||
java.io.File configFile = new java.io.File(configPath);
|
||||
if (configFile.exists()) {
|
||||
java.util.Properties properties = new java.util.Properties();
|
||||
try (java.io.FileInputStream fis = new java.io.FileInputStream(configFile)) {
|
||||
properties.load(fis);
|
||||
String baseBetUnit = properties.getProperty("BASE_BET_UNIT");
|
||||
if (baseBetUnit != null) {
|
||||
try {
|
||||
loginInfoResult.setBetAmount(Integer.parseInt(baseBetUnit));
|
||||
} catch (NumberFormatException e) {
|
||||
System.err.println("BASE_BET_UNIT 格式错误: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
} catch (java.io.IOException e) {
|
||||
System.err.println("读取配置文件失败: " + e.getMessage());
|
||||
}
|
||||
} else {
|
||||
System.err.println("配置文件不存在: " + configPath);
|
||||
}
|
||||
|
||||
return loginInfoResult;
|
||||
} catch (Exception e) {
|
||||
System.err.println("获取用户设置信息失败: " + e.getMessage());
|
||||
return new LoginInfoResult();
|
||||
|
||||
@@ -48,16 +48,48 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
|
||||
*
|
||||
* @return 当天日期的字符串,例如:2026-01-27
|
||||
*/
|
||||
|
||||
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
||||
public static String getTodayDate() {
|
||||
LocalDate today = LocalDate.now();
|
||||
return today.format(DateTimeFormatter.ofPattern(YYYY_MM_DD));
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
LocalTime thresholdTime = LocalTime.of(6, 1, 0);
|
||||
LocalDate date;
|
||||
if (now.toLocalTime().isBefore(thresholdTime)) {
|
||||
date = now.toLocalDate().minusDays(1); // 昨天
|
||||
} else {
|
||||
date = now.toLocalDate(); // 今天
|
||||
}
|
||||
return date.format(DateTimeFormatter.ofPattern(YYYY_MM_DD));
|
||||
}
|
||||
/*public static String getTodayDate() {
|
||||
// Java 17中可使用var简化局部变量声明
|
||||
var now = LocalDateTime.now();
|
||||
// 核心判断逻辑:小时数<6则取前一天,否则取当天
|
||||
LocalDate targetDate = now.getHour() <= 6
|
||||
? now.toLocalDate().minusDays(1)
|
||||
: now.toLocalDate();
|
||||
// 格式化返回
|
||||
return targetDate.format(DATE_FORMATTER);
|
||||
}*/
|
||||
|
||||
// 近7天日期的方法
|
||||
public static List<String> getLast7Days() {
|
||||
List<String> dateList = new ArrayList<>();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
|
||||
// 从今天开始,往前推7天
|
||||
for (int i = 0; i < 7; i++) {
|
||||
dateList.add(sdf.format(calendar.getTime()));
|
||||
calendar.add(Calendar.DAY_OF_YEAR, -1);
|
||||
}
|
||||
|
||||
return dateList;
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
List<String> test = new ArrayList<>();
|
||||
test.add("12312");
|
||||
test.add("12312");
|
||||
System.out.println("====="+test.get(6));
|
||||
System.out.println("====="+getTodayDate());
|
||||
/* Date now = new Date(); // 当前时间
|
||||
Date fifteenMinutesAgo = DateUtil.offsetMinute(now, -15); // 15分钟前的时间
|
||||
|
||||
|
||||
@@ -15,7 +15,20 @@ import java.net.URL;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.impl.client.LaxRedirectStrategy;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
@Slf4j
|
||||
public class HttpClientExample {
|
||||
|
||||
@@ -28,16 +41,247 @@ public class HttpClientExample {
|
||||
return "";
|
||||
}
|
||||
|
||||
public static List<Map<String, Object>> getPksHistoryList(){
|
||||
|
||||
|
||||
|
||||
|
||||
public static List<Map<String, Object>> getPksHistoryList() {
|
||||
List<Map<String, Object>> resultList = new ArrayList<>();
|
||||
String todayDate = DateUtils.getTodayDate();
|
||||
|
||||
// 最大重试次数
|
||||
int maxRetries = 10;
|
||||
// 重试延迟(毫秒)
|
||||
int retryDelay = 2000;
|
||||
|
||||
for (int retryCount = 0; retryCount < maxRetries; retryCount++) {
|
||||
System.out.println("=== 第 " + (retryCount + 1) + " 次尝试请求 ===");
|
||||
|
||||
CloseableHttpClient httpClient = null;
|
||||
CloseableHttpResponse response = null;
|
||||
|
||||
try {
|
||||
String url = "https://api.api168168.com/pks/getPksHistoryList.do?lotCode=10058&date=" + todayDate;
|
||||
System.out.println("请求URL: " + url);
|
||||
|
||||
// 创建自定义配置的HttpClient
|
||||
RequestConfig requestConfig = RequestConfig.custom()
|
||||
.setConnectTimeout(15000) // 15秒连接超时
|
||||
.setSocketTimeout(15000) // 15秒socket超时
|
||||
.setConnectionRequestTimeout(15000)
|
||||
.setCircularRedirectsAllowed(true)
|
||||
.setMaxRedirects(5)
|
||||
.build();
|
||||
|
||||
httpClient = HttpClients.custom()
|
||||
.setDefaultRequestConfig(requestConfig)
|
||||
.setRedirectStrategy(new LaxRedirectStrategy())
|
||||
.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
|
||||
.disableCookieManagement()
|
||||
.build();
|
||||
|
||||
HttpGet request = new HttpGet(url);
|
||||
|
||||
// 设置完整的请求头
|
||||
request.setHeader("Accept", "application/json, text/javascript, */*; q=0.01");
|
||||
request.setHeader("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8");
|
||||
request.setHeader("Cache-Control", "no-cache");
|
||||
request.setHeader("Connection", "keep-alive");
|
||||
request.setHeader("Host", "api.api168168.com");
|
||||
request.setHeader("Origin", "https://xy678kjw.com");
|
||||
request.setHeader("Pragma", "no-cache");
|
||||
request.setHeader("Referer", "https://xy678kjw.com/");
|
||||
request.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36");
|
||||
request.setHeader("X-Requested-With", "XMLHttpRequest");
|
||||
|
||||
// 设置Sec-Fetch相关头
|
||||
request.setHeader("Sec-Fetch-Dest", "empty");
|
||||
request.setHeader("Sec-Fetch-Mode", "cors");
|
||||
request.setHeader("Sec-Fetch-Site", "cross-site");
|
||||
|
||||
// 执行请求
|
||||
response = httpClient.execute(request);
|
||||
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
System.out.println("响应状态码: " + statusCode);
|
||||
|
||||
// 打印响应头用于调试
|
||||
System.out.println("响应头信息:");
|
||||
Arrays.stream(response.getAllHeaders())
|
||||
.limit(10)
|
||||
.forEach(header -> System.out.println(" " + header.getName() + ": " + header.getValue()));
|
||||
|
||||
if (statusCode == 200) {
|
||||
HttpEntity entity = response.getEntity();
|
||||
if (entity != null) {
|
||||
String responseString = EntityUtils.toString(entity, "UTF-8");
|
||||
System.out.println("响应内容长度: " + responseString.length());
|
||||
|
||||
// 打印响应前200个字符用于调试
|
||||
if (responseString.length() > 0) {
|
||||
int previewLength = Math.min(200, responseString.length());
|
||||
System.out.println("响应预览: " + responseString.substring(0, previewLength));
|
||||
|
||||
// 检查响应是否有效
|
||||
if (responseString.contains("errorCode") || responseString.contains("result")) {
|
||||
// 解析JSON
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
JsonNode rootNode = objectMapper.readTree(responseString);
|
||||
|
||||
// 检查是否成功
|
||||
int errorCode = rootNode.get("errorCode").asInt();
|
||||
if (errorCode == 0) {
|
||||
// 获取data数组
|
||||
JsonNode dataArray = rootNode
|
||||
.get("result")
|
||||
.get("data");
|
||||
|
||||
if (dataArray.isArray()) {
|
||||
for (JsonNode item : dataArray) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
|
||||
// 解析原始数据
|
||||
String preDrawCode = item.get("preDrawCode").asText();
|
||||
String[] codeArray = preDrawCode.split(",");
|
||||
|
||||
// 转换为List<Integer>
|
||||
List<Integer> resultNumbers = new ArrayList<>();
|
||||
for (String code : codeArray) {
|
||||
resultNumbers.add(Integer.parseInt(code.trim()));
|
||||
}
|
||||
|
||||
// 计算sum1和sum2
|
||||
int sum1 = 0;
|
||||
int sum2 = 0;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
sum1 += resultNumbers.get(i);
|
||||
}
|
||||
for (int i = 5; i < 10; i++) {
|
||||
sum2 += resultNumbers.get(i);
|
||||
}
|
||||
|
||||
// 计算winner(前五个号码的和)
|
||||
int winner = sum1;
|
||||
|
||||
// 计算冠亚和(前两个号码的和)
|
||||
int championSum = resultNumbers.get(0) + resultNumbers.get(1);
|
||||
|
||||
// 判断冠亚单双
|
||||
String GD2 = (championSum % 2 == 0) ? "冠亚双" : "冠亚单";
|
||||
|
||||
// 判断冠亚大小(冠亚和11为大,11为小)
|
||||
String GD1 = (championSum > 11) ? "冠亚大" : "冠亚小";
|
||||
if (championSum == 11) {
|
||||
GD1 = "冠亚小"; // 特殊处理:和值为11算小
|
||||
}
|
||||
|
||||
// 计算龙虎(1-5位对比)
|
||||
List<String> GLH_result = new ArrayList<>();
|
||||
for (int i = 0; i < 5; i++) {
|
||||
if (resultNumbers.get(i) > resultNumbers.get(9 - i)) {
|
||||
GLH_result.add("龙");
|
||||
} else {
|
||||
GLH_result.add("虎");
|
||||
}
|
||||
}
|
||||
|
||||
// 构建转换后的map
|
||||
map.put("result", resultNumbers);
|
||||
map.put("sum1", sum1);
|
||||
map.put("sum2", sum2);
|
||||
map.put("winner", winner);
|
||||
map.put("GD2", GD2);
|
||||
map.put("GD1", GD1);
|
||||
map.put("GLH_result", GLH_result);
|
||||
map.put("id", String.valueOf(item.get("preDrawIssue").asLong()));
|
||||
map.put("time", item.get("preDrawTime").asText());
|
||||
|
||||
resultList.add(map);
|
||||
}
|
||||
System.out.println("成功获取 " + resultList.size() + " 条数据");
|
||||
|
||||
// 成功获取数据,关闭资源并返回
|
||||
if (response != null) {
|
||||
response.close();
|
||||
}
|
||||
if (httpClient != null) {
|
||||
httpClient.close();
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
} else {
|
||||
System.err.println("API返回错误: errorCode=" + errorCode);
|
||||
}
|
||||
} else {
|
||||
System.err.println("响应内容格式不正确,不包含期望的字段");
|
||||
}
|
||||
} else {
|
||||
System.err.println("响应内容为空");
|
||||
}
|
||||
}
|
||||
} else if (statusCode == 403 || statusCode == 404 || statusCode == 500) {
|
||||
System.err.println("服务器返回错误状态码: " + statusCode);
|
||||
// 如果是这些状态码,可能不需要重试
|
||||
break;
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println("第 " + (retryCount + 1) + " 次请求异常: " +
|
||||
e.getClass().getSimpleName() + " - " + e.getMessage());
|
||||
|
||||
// 如果是连接重置错误,打印更多信息
|
||||
if (e.getMessage() != null && e.getMessage().contains("Connection reset")) {
|
||||
System.err.println("连接被服务器重置");
|
||||
}
|
||||
|
||||
// 最后一次重试仍然失败,打印完整堆栈
|
||||
if (retryCount == maxRetries - 1) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} finally {
|
||||
// 确保资源关闭
|
||||
try {
|
||||
if (response != null) {
|
||||
response.close();
|
||||
}
|
||||
if (httpClient != null) {
|
||||
httpClient.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("关闭资源时出错: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 如果不是最后一次尝试,等待后重试
|
||||
if (retryCount < maxRetries - 1) {
|
||||
System.out.println("等待 " + (retryDelay/1000) + " 秒后重试...");
|
||||
try {
|
||||
Thread.sleep(retryDelay);
|
||||
} catch (InterruptedException ie) {
|
||||
Thread.currentThread().interrupt();
|
||||
System.err.println("重试等待被中断");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (resultList.isEmpty()) {
|
||||
System.err.println("经过 " + maxRetries + " 次重试后,仍未能获取数据");
|
||||
}
|
||||
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/*public static List<Map<String, Object>> getPksHistoryList(){
|
||||
List<Map<String, Object>> resultList = new ArrayList<>();
|
||||
String todayDate = DateUtils.getTodayDate();
|
||||
try {
|
||||
String url = "https://api.api168168.com/pks/getPksHistoryList.do?lotCode=10058&"+todayDate;
|
||||
|
||||
// 设置代理 127.0.0.1:7890
|
||||
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 7890));
|
||||
//Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 7890));
|
||||
|
||||
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(proxy);
|
||||
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
|
||||
conn.setRequestMethod("GET");
|
||||
conn.setRequestProperty("Origin", "https://xy678kjw.com");
|
||||
conn.setRequestProperty("Referer", "https://xy678kjw.com/");
|
||||
@@ -133,7 +377,7 @@ public class HttpClientExample {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
/*public static List<Map<String, Object>> getPksHistoryList(){
|
||||
@@ -255,7 +499,7 @@ public class HttpClientExample {
|
||||
|
||||
// 使用年月日作为文件名(格式:result_yyyyMMdd.json)
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||
String dateStr = dateFormat.format(new Date());
|
||||
String dateStr = DateUtils.getTodayDate();
|
||||
String fileName = "result_" + dateStr + ".json";
|
||||
String filePath = directoryPath + "/" + fileName;
|
||||
|
||||
@@ -264,9 +508,52 @@ public class HttpClientExample {
|
||||
if (!directory.exists()) {
|
||||
directory.mkdirs(); // 创建多级目录
|
||||
}
|
||||
|
||||
// 创建文件对象
|
||||
File outputFile = new File(filePath);
|
||||
// 如果文件已存在,读取现有数据并对比
|
||||
List<Map<String, Object>> existingData = new ArrayList<>();
|
||||
Set<String> existingIds = new HashSet<>();
|
||||
if (outputFile.exists()) {
|
||||
try {
|
||||
existingData = objectMapper.readValue(outputFile,
|
||||
objectMapper.getTypeFactory().constructCollectionType(List.class, Map.class));
|
||||
for (Map<String, Object> item : existingData) {
|
||||
if (item.containsKey("id")) {
|
||||
existingIds.add(item.get("id").toString());
|
||||
}
|
||||
}
|
||||
log.info("已读取现有数据,共 " + existingData.size() + " 条记录");
|
||||
} catch (IOException e) {
|
||||
log.warn("读取现有文件失败,将覆盖写入: " + e.getMessage());
|
||||
existingIds.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// 筛选出新增的数据(id不在existingIds中的记录)
|
||||
List<Map<String, Object>> newData = new ArrayList<>();
|
||||
for (Map<String, Object> item : resultList) {
|
||||
if (item.containsKey("id")) {
|
||||
String id = item.get("id").toString();
|
||||
if (!existingIds.contains(id)) {
|
||||
newData.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 合并现有数据和新数据
|
||||
List<Map<String, Object>> finalData = new ArrayList<>();
|
||||
if (!existingData.isEmpty()) {
|
||||
finalData.addAll(existingData);
|
||||
}
|
||||
finalData.addAll(newData);
|
||||
|
||||
// 将合并后的数据写入 JSON 文件
|
||||
objectMapper.writeValue(outputFile, finalData);
|
||||
log.info("数据已成功写入文件: " + outputFile.getAbsolutePath() +
|
||||
" (现有: " + existingData.size() + " 条, 新增: " + newData.size() + " 条, 总计: " + finalData.size() + " 条)");
|
||||
|
||||
/* // 创建文件对象
|
||||
File outputFile = new File(filePath);
|
||||
|
||||
// 如果文件已存在,删除旧文件(实现替换功能)
|
||||
if (outputFile.exists()) {
|
||||
@@ -279,7 +566,7 @@ public class HttpClientExample {
|
||||
|
||||
// 将 List 写入 JSON 文件
|
||||
objectMapper.writeValue(outputFile, resultList);
|
||||
log.info("数据已成功写入文件: " + outputFile.getAbsolutePath());
|
||||
log.info("数据已成功写入文件: " + outputFile.getAbsolutePath());*/
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
log.error("写入 JSON 文件失败: " + e.getMessage(), e);
|
||||
|
||||
332
src/main/java/com/tem/bocai/util/LotteryHistoryCrawler.java
Normal file
332
src/main/java/com/tem/bocai/util/LotteryHistoryCrawler.java
Normal file
@@ -0,0 +1,332 @@
|
||||
package com.tem.bocai.util;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
import us.codecraft.webmagic.Page;
|
||||
import us.codecraft.webmagic.Site;
|
||||
import us.codecraft.webmagic.Spider;
|
||||
import us.codecraft.webmagic.processor.PageProcessor;
|
||||
import us.codecraft.webmagic.selector.Html;
|
||||
import us.codecraft.webmagic.selector.Selectable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
//开奖的历史结果
|
||||
@Slf4j
|
||||
public class LotteryHistoryCrawler implements PageProcessor {
|
||||
|
||||
private final String token;
|
||||
// 站点配置
|
||||
private Site site;
|
||||
// final LoginService loginService;
|
||||
// 添加一个字段标记是否成功解析数据
|
||||
private static volatile boolean lastParseSuccess = true;
|
||||
|
||||
private String path;
|
||||
private String date;
|
||||
|
||||
public LotteryHistoryCrawler(String token, String path,String date) {
|
||||
this.token = token;
|
||||
this.path =path;
|
||||
this.date =date;
|
||||
initSite();
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化Site配置
|
||||
*/
|
||||
private void initSite() {
|
||||
site = Site.me()
|
||||
.setRetryTimes(3)
|
||||
.setSleepTime(1000)
|
||||
.setTimeOut(10000)
|
||||
.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36");
|
||||
|
||||
// 设置cookie
|
||||
if (token != null && !token.isEmpty()) {
|
||||
site.addHeader("cookie", "token=" + token);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void process(Page page) {
|
||||
// 获取页面HTML
|
||||
Html html = page.getHtml();
|
||||
|
||||
// 打印页面基本信息
|
||||
log.info("页面URL: " + page.getUrl());
|
||||
log.info("页面标题: " + html.xpath("//title/text()").get());
|
||||
// 示例:提取所有表格数据
|
||||
Selectable tables = html.xpath("//table");
|
||||
log.info("找到 " + tables.nodes().size() + " 个表格");
|
||||
if(tables.nodes().isEmpty()){
|
||||
lastParseSuccess = false;
|
||||
}else {
|
||||
lastParseSuccess = true;
|
||||
}
|
||||
// 提取表格数据(根据实际页面结构调整选择器)
|
||||
extractTableData(html);
|
||||
|
||||
// 示例:提取所有链接
|
||||
Selectable links = html.links();
|
||||
System.out.println("页面包含 " + links.all().size() + " 个链接");
|
||||
// 如果需要继续爬取其他页面
|
||||
// page.addTargetRequests(links.all());
|
||||
|
||||
// 将数据存入结果
|
||||
/* page.putField("html========", html.toString());
|
||||
page.putField("title", html.xpath("//title/text()").get());*/
|
||||
parseLotteryHtml(html.toString());
|
||||
|
||||
}
|
||||
|
||||
private void extractTableData(Html html) {
|
||||
// 根据实际页面结构编写数据提取逻辑
|
||||
// 示例:提取所有tr元素
|
||||
Selectable rows = html.xpath("//tr");
|
||||
for (Selectable row : rows.nodes()) {
|
||||
// 提取每行的td内容
|
||||
String rowText = row.xpath("//td/text()").all().toString();
|
||||
if (!rowText.isEmpty()) {
|
||||
System.out.println("行数据: " + rowText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Site getSite() {
|
||||
|
||||
return site;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个方法获取解析状态
|
||||
*/
|
||||
public static boolean isLastParseSuccess() {
|
||||
return lastParseSuccess;
|
||||
}
|
||||
/**
|
||||
* 解析彩票HTML数据,转换成指定的List<Map<String, Object>>格式
|
||||
*
|
||||
* @param htmlContent 爬取到的HTML文本内容
|
||||
* @return 解析后的结构化数据列表
|
||||
*/
|
||||
public List<Map<String, Object>> parseLotteryHtml(String htmlContent) {
|
||||
List<Map<String, Object>> resultList = new ArrayList<>();
|
||||
|
||||
// 初始化Jsoup解析器
|
||||
Document doc = Jsoup.parse(htmlContent);
|
||||
|
||||
// 定位到数据所在的表格行(drawTable下的table > tbody > tr)
|
||||
Element targetTable = doc.selectFirst("#drawTable");
|
||||
if (targetTable == null) {
|
||||
return resultList;
|
||||
}
|
||||
|
||||
Elements trList = targetTable.select("table > tbody > tr");
|
||||
|
||||
// 遍历每一行数据
|
||||
for (Element tr : trList) {
|
||||
Map<String, Object> rowData = new HashMap<>();
|
||||
|
||||
// 1. 提取期数(id)
|
||||
Element periodTd = tr.selectFirst("td.period");
|
||||
rowData.put("id", periodTd != null ? periodTd.text().trim() : "");
|
||||
|
||||
// 2. 提取开奖时间(time)
|
||||
Element timeTd = tr.selectFirst("td.drawTime");
|
||||
rowData.put("time", timeTd != null ? timeTd.text().trim() : "");
|
||||
|
||||
// 3. 提取开出号码(result)- 10个ballname的数字
|
||||
Elements ballTds = tr.select("td.ballname");
|
||||
List<Integer> resultNumbers = new ArrayList<>();
|
||||
int count = 0;
|
||||
for (Element td : ballTds) {
|
||||
if (count >= 10) break;
|
||||
String text = td.text().trim();
|
||||
if (text.matches("\\d+")) {
|
||||
resultNumbers.add(Integer.parseInt(text));
|
||||
count++;
|
||||
}
|
||||
}
|
||||
rowData.put("result", resultNumbers);
|
||||
|
||||
// 4. 提取winner(other1)
|
||||
Element winnerTd = tr.selectFirst("td.other1");
|
||||
if (winnerTd != null) {
|
||||
String winnerText = winnerTd.text().trim();
|
||||
if (winnerText.matches("\\d+")) {
|
||||
rowData.put("winner", Integer.parseInt(winnerText));
|
||||
} else {
|
||||
rowData.put("winner", "");
|
||||
}
|
||||
} else {
|
||||
rowData.put("winner", "");
|
||||
}
|
||||
|
||||
// 5. 提取GD1(冠亚小/大)、GD2(冠亚单/双)
|
||||
Elements otherTds = tr.select("td.other");
|
||||
String gd1 = "";
|
||||
String gd2 = "";
|
||||
for (Element td : otherTds) {
|
||||
String className = td.className();
|
||||
if (className.contains("GDX")) {
|
||||
gd1 = td.text().trim();
|
||||
} else if (className.contains("GDS")) {
|
||||
gd2 = td.text().trim();
|
||||
}
|
||||
}
|
||||
rowData.put("GD1", gd1);
|
||||
rowData.put("GD2", gd2);
|
||||
|
||||
// 6. 提取sum1(dldhl_sum)、sum2(dldhh_sum)
|
||||
Element sum1Td = tr.selectFirst("td.dldhl_sum");
|
||||
if (sum1Td != null) {
|
||||
String sum1Text = sum1Td.text().trim();
|
||||
if (sum1Text.matches("\\d+")) {
|
||||
rowData.put("sum1", Integer.parseInt(sum1Text));
|
||||
} else {
|
||||
rowData.put("sum1", "");
|
||||
}
|
||||
} else {
|
||||
rowData.put("sum1", "");
|
||||
}
|
||||
|
||||
Element sum2Td = tr.selectFirst("td.dldhh_sum");
|
||||
if (sum2Td != null) {
|
||||
String sum2Text = sum2Td.text().trim();
|
||||
if (sum2Text.matches("\\d+")) {
|
||||
rowData.put("sum2", Integer.parseInt(sum2Text));
|
||||
} else {
|
||||
rowData.put("sum2", "");
|
||||
}
|
||||
} else {
|
||||
rowData.put("sum2", "");
|
||||
}
|
||||
|
||||
// 7. 提取GLH_result(龙虎结果,5个GLH开头的td)
|
||||
List<String> glhResults = new ArrayList<>();
|
||||
int glhCount = 0;
|
||||
for (Element td : otherTds) {
|
||||
if (glhCount >= 5) break;
|
||||
String className = td.className();
|
||||
if (className.contains("GLH_")) {
|
||||
glhResults.add(td.text().trim());
|
||||
glhCount++;
|
||||
}
|
||||
}
|
||||
rowData.put("GLH_result", glhResults);
|
||||
|
||||
// 将单行数据加入结果列表(只保留有期数的有效行)
|
||||
if (!rowData.get("id").toString().isEmpty()) {
|
||||
resultList.add(rowData);
|
||||
}
|
||||
}
|
||||
// 将数据写入SQLite数据库
|
||||
SQLiteUtil.writeToSQLite(resultList);
|
||||
// 将数据写入JSON文件(保留原有功能)
|
||||
writeToJsonFile(resultList);
|
||||
log.info("历史爬虫打印结果===" + resultList);
|
||||
return resultList;
|
||||
}
|
||||
|
||||
public void writeToJsonFile(List<Map<String, Object>> resultList) {
|
||||
try {
|
||||
// 创建 ObjectMapper 实例
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
// 设置 JSON 格式化(可选,更易读)
|
||||
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
|
||||
|
||||
// 定义输出目录
|
||||
String directoryPath = path+"/current_data"; // 项目根目录下的 output/json 文件夹
|
||||
|
||||
// 使用年月日作为文件名(格式:result_yyyyMMdd.json)
|
||||
String fileName = "result_" + date + ".json";
|
||||
String filePath = directoryPath + "/" + fileName;
|
||||
|
||||
// 创建目录(如果不存在)
|
||||
File directory = new File(directoryPath);
|
||||
if (!directory.exists()) {
|
||||
directory.mkdirs(); // 创建多级目录
|
||||
}
|
||||
|
||||
// 创建文件对象
|
||||
File outputFile = new File(filePath);
|
||||
|
||||
// 如果文件已存在,读取现有数据并对比
|
||||
List<Map<String, Object>> existingData = new ArrayList<>();
|
||||
Set<String> existingIds = new HashSet<>();
|
||||
if (outputFile.exists()) {
|
||||
try {
|
||||
existingData = objectMapper.readValue(outputFile,
|
||||
objectMapper.getTypeFactory().constructCollectionType(List.class, Map.class));
|
||||
for (Map<String, Object> item : existingData) {
|
||||
if (item.containsKey("id")) {
|
||||
existingIds.add(item.get("id").toString());
|
||||
}
|
||||
}
|
||||
log.info("已读取现有数据,共 " + existingData.size() + " 条记录");
|
||||
} catch (IOException e) {
|
||||
log.warn("读取现有文件失败,将覆盖写入: " + e.getMessage());
|
||||
existingIds.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// 筛选出新增的数据(id不在existingIds中的记录)
|
||||
List<Map<String, Object>> newData = new ArrayList<>();
|
||||
for (Map<String, Object> item : resultList) {
|
||||
if (item.containsKey("id")) {
|
||||
String id = item.get("id").toString();
|
||||
if (!existingIds.contains(id)) {
|
||||
newData.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 合并现有数据和新数据
|
||||
List<Map<String, Object>> finalData = new ArrayList<>();
|
||||
if (!existingData.isEmpty()) {
|
||||
finalData.addAll(existingData);
|
||||
}
|
||||
finalData.addAll(newData);
|
||||
|
||||
// 将合并后的数据写入 JSON 文件
|
||||
objectMapper.writeValue(outputFile, finalData);
|
||||
log.info("数据已成功写入文件: " + outputFile.getAbsolutePath() +
|
||||
" (现有: " + existingData.size() + " 条, 新增: " + newData.size() + " 条, 总计: " + finalData.size() + " 条)");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
log.error("写入 JSON 文件失败: " + e.getMessage(), e);
|
||||
throw new RuntimeException("写入 JSON 文件失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
String url = "https://4701268539-esh.qdk63ayw8g.com/member/dresult?lottery=SGFT&date=2026-02-06";
|
||||
|
||||
// 创建爬虫
|
||||
Spider.create(new LotteryHistoryCrawler("","",""))
|
||||
.addUrl(url) // 添加起始URL
|
||||
.thread(1) // 线程数
|
||||
.run(); // 开始爬取
|
||||
}
|
||||
|
||||
|
||||
// 自定义headers
|
||||
/*private Map<String, String> getHeaders() {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("cookie", "token=a1b219fe7e39374d6af532c56fdc911b76ae8f83");
|
||||
|
||||
return headers;
|
||||
}*/
|
||||
}
|
||||
@@ -255,8 +255,7 @@ public class LotteryWebMagicCrawler implements PageProcessor {
|
||||
String directoryPath = path+"/current_data"; // 项目根目录下的 output/json 文件夹
|
||||
|
||||
// 使用年月日作为文件名(格式:result_yyyyMMdd.json)
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||
String dateStr = dateFormat.format(new Date());
|
||||
String dateStr = DateUtils.getTodayDate();
|
||||
String fileName = "result_" + dateStr + ".json";
|
||||
String filePath = directoryPath + "/" + fileName;
|
||||
|
||||
@@ -269,18 +268,47 @@ public class LotteryWebMagicCrawler implements PageProcessor {
|
||||
// 创建文件对象
|
||||
File outputFile = new File(filePath);
|
||||
|
||||
// 如果文件已存在,删除旧文件(实现替换功能)
|
||||
// 如果文件已存在,读取现有数据并对比
|
||||
List<Map<String, Object>> existingData = new ArrayList<>();
|
||||
Set<String> existingIds = new HashSet<>();
|
||||
if (outputFile.exists()) {
|
||||
boolean deleted = outputFile.delete();
|
||||
if (!deleted) {
|
||||
throw new IOException("无法删除已存在的文件: " + filePath);
|
||||
try {
|
||||
existingData = objectMapper.readValue(outputFile,
|
||||
objectMapper.getTypeFactory().constructCollectionType(List.class, Map.class));
|
||||
for (Map<String, Object> item : existingData) {
|
||||
if (item.containsKey("id")) {
|
||||
existingIds.add(item.get("id").toString());
|
||||
}
|
||||
}
|
||||
log.info("已读取现有数据,共 " + existingData.size() + " 条记录");
|
||||
} catch (IOException e) {
|
||||
log.warn("读取现有文件失败,将覆盖写入: " + e.getMessage());
|
||||
existingIds.clear();
|
||||
}
|
||||
System.out.println("已删除旧文件,准备创建新文件: " + fileName);
|
||||
}
|
||||
|
||||
// 将 List 写入 JSON 文件
|
||||
objectMapper.writeValue(outputFile, resultList);
|
||||
log.info("数据已成功写入文件: " + outputFile.getAbsolutePath());
|
||||
// 筛选出新增的数据(id不在existingIds中的记录)
|
||||
List<Map<String, Object>> newData = new ArrayList<>();
|
||||
for (Map<String, Object> item : resultList) {
|
||||
if (item.containsKey("id")) {
|
||||
String id = item.get("id").toString();
|
||||
if (!existingIds.contains(id)) {
|
||||
newData.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 合并现有数据和新数据
|
||||
List<Map<String, Object>> finalData = new ArrayList<>();
|
||||
if (!existingData.isEmpty()) {
|
||||
finalData.addAll(existingData);
|
||||
}
|
||||
finalData.addAll(newData);
|
||||
|
||||
// 将合并后的数据写入 JSON 文件
|
||||
objectMapper.writeValue(outputFile, finalData);
|
||||
log.info("数据已成功写入文件: " + outputFile.getAbsolutePath() +
|
||||
" (现有: " + existingData.size() + " 条, 新增: " + newData.size() + " 条, 总计: " + finalData.size() + " 条)");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
log.error("写入 JSON 文件失败: " + e.getMessage(), e);
|
||||
@@ -290,7 +318,7 @@ public class LotteryWebMagicCrawler implements PageProcessor {
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
String url = "https://4701268539-esh.qdk63ayw8g.com/member/dresult?lottery=SGFT&date=2026-01-18";
|
||||
String url = "https://4701268539-esh.qdk63ayw8g.com/member/dresult?lottery=SGFT&date=2026-02-06";
|
||||
|
||||
// 创建爬虫
|
||||
Spider.create(new LotteryWebMagicCrawler("",""))
|
||||
|
||||
@@ -42,12 +42,25 @@ public class SQLiteUtil {
|
||||
// 先初始化数据库
|
||||
//initDatabase();
|
||||
|
||||
String insertSQL = """
|
||||
/*String insertSQL = """
|
||||
INSERT OR REPLACE INTO lottery_results
|
||||
(issue,time, result, winner, gd1, gd2, sum1, sum2, glh_result)
|
||||
VALUES (?,?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""";
|
||||
|
||||
""";*/
|
||||
String insertSQL = """
|
||||
INSERT INTO lottery_results
|
||||
(issue, time, result, winner, gd1, gd2, sum1, sum2, glh_result)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT(issue) DO UPDATE SET
|
||||
time = excluded.time,
|
||||
result = excluded.result,
|
||||
winner = excluded.winner,
|
||||
gd1 = excluded.gd1,
|
||||
gd2 = excluded.gd2,
|
||||
sum1 = excluded.sum1,
|
||||
sum2 = excluded.sum2,
|
||||
glh_result = excluded.glh_result
|
||||
""";
|
||||
Connection conn = null;
|
||||
PreparedStatement pstmt = null;
|
||||
|
||||
|
||||
@@ -373,16 +373,16 @@ public class TokenCacheService {
|
||||
// 等待一下再发送登录请求
|
||||
Thread.sleep(1500 + (long) (Math.random() * 1000));
|
||||
|
||||
// 新增代码:增加代理
|
||||
String proxyHost = "127.0.0.1";
|
||||
int proxyPort = 7890;
|
||||
HttpHost proxy = new HttpHost(proxyHost, proxyPort);
|
||||
RequestConfig proxyConfig = RequestConfig.custom()
|
||||
.setProxy(proxy)
|
||||
.build();
|
||||
// // 新增代码:增加代理
|
||||
// String proxyHost = "127.0.0.1";
|
||||
// int proxyPort = 7890;
|
||||
// HttpHost proxy = new HttpHost(proxyHost, proxyPort);
|
||||
// RequestConfig proxyConfig = RequestConfig.custom()
|
||||
// .setProxy(proxy)
|
||||
// .build();
|
||||
HttpPost loginPost = createLoginRequest(code,loginInfoParam);
|
||||
// 新增代码:将代理类放入配置中
|
||||
loginPost.setConfig(proxyConfig);
|
||||
// // 新增代码:将代理类放入配置中
|
||||
// loginPost.setConfig(proxyConfig);
|
||||
try (CloseableHttpResponse loginResponse = httpClient.execute(loginPost)) {
|
||||
return processLoginResponse(loginResponse, cookieStore);
|
||||
}
|
||||
|
||||
@@ -10,4 +10,4 @@ spring.jpa.show-sql=true
|
||||
spring.jpa.database-platform=org.hibernate.community.dialect.SQLiteDialect
|
||||
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
|
||||
|
||||
pypath:c:/py/PyModel
|
||||
pypath:D:/py/PyModel
|
||||
Reference in New Issue
Block a user