今日已结
This commit is contained in:
12
pom.xml
12
pom.xml
@@ -78,6 +78,18 @@
|
|||||||
<artifactId>tess4j</artifactId>
|
<artifactId>tess4j</artifactId>
|
||||||
<version>5.8.0</version>
|
<version>5.8.0</version>
|
||||||
</dependency>-->
|
</dependency>-->
|
||||||
|
<!-- pom.xml -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-cache</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 使用Caffeine作为缓存实现 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||||
|
<artifactId>caffeine</artifactId>
|
||||||
|
<version>3.1.8</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
|||||||
42
src/main/java/com/tem/bocai/config/CacheConfig.java
Normal file
42
src/main/java/com/tem/bocai/config/CacheConfig.java
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package com.tem.bocai.config;
|
||||||
|
|
||||||
|
|
||||||
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.cache.CacheManager;
|
||||||
|
import org.springframework.cache.annotation.EnableCaching;
|
||||||
|
import org.springframework.cache.caffeine.CaffeineCacheManager;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Primary;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableCaching // 启用缓存支持
|
||||||
|
public class CacheConfig {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主缓存管理器 - 用于token缓存(19分钟过期)
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
@Primary // 标记为主缓存管理器
|
||||||
|
public CacheManager cacheManager() {
|
||||||
|
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
|
||||||
|
cacheManager.setCaffeine(Caffeine.newBuilder()
|
||||||
|
.expireAfterWrite(19, TimeUnit.MINUTES) // 19分钟过期
|
||||||
|
.maximumSize(100) // 最大缓存数量
|
||||||
|
.recordStats() // 记录统计信息
|
||||||
|
);
|
||||||
|
return cacheManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备用缓存管理器 - 如果没有配置Caffeine,使用ConcurrentMap
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean(CacheManager.class)
|
||||||
|
public CacheManager fallbackCacheManager() {
|
||||||
|
return new org.springframework.cache.concurrent.ConcurrentMapCacheManager();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,6 +24,12 @@ public class LoginCrawler {
|
|||||||
return ResponseEntity.ok(result);
|
return ResponseEntity.ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/ocr/completedToday")
|
||||||
|
public ResponseEntity<String> completedToday() throws IOException, TesseractException {
|
||||||
|
String result = loginService.completedToday();
|
||||||
|
return ResponseEntity.ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,4 +7,8 @@ public interface LoginService {
|
|||||||
|
|
||||||
//获取token
|
//获取token
|
||||||
String getToken(String username, String password, String loginUrl);
|
String getToken(String username, String password, String loginUrl);
|
||||||
|
|
||||||
|
//获取token
|
||||||
|
String completedToday();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.tem.bocai.service.impl;
|
package com.tem.bocai.service.impl;
|
||||||
|
|
||||||
import com.tem.bocai.service.LoginService;
|
import com.tem.bocai.service.LoginService;
|
||||||
|
import com.tem.bocai.util.CompletedTodayCrawler;
|
||||||
import com.tem.bocai.util.LotteryDataPipeline;
|
import com.tem.bocai.util.LotteryDataPipeline;
|
||||||
import com.tem.bocai.util.LotteryWebMagicCrawler;
|
import com.tem.bocai.util.LotteryWebMagicCrawler;
|
||||||
import com.tem.bocai.util.TokenCacheService;
|
import com.tem.bocai.util.TokenCacheService;
|
||||||
@@ -107,6 +108,25 @@ public class LoginServiceImpl implements LoginService {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String completedToday() {
|
||||||
|
String token = tokenCacheService.getToken();
|
||||||
|
System.out.println("得到token = " + token);
|
||||||
|
if (token != null && !token.isEmpty()) {
|
||||||
|
// 2. 创建爬虫实例,传入token
|
||||||
|
CompletedTodayCrawler crawler = new CompletedTodayCrawler(token);
|
||||||
|
|
||||||
|
// 4. 执行爬虫
|
||||||
|
String url = "https://4701268539-esh.qdk63ayw8g.com/member/bets?settled=true";
|
||||||
|
|
||||||
|
Spider.create(crawler)
|
||||||
|
.addUrl(url)
|
||||||
|
.thread(1)
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 单次登录尝试
|
* 单次登录尝试
|
||||||
*/
|
*/
|
||||||
|
|||||||
396
src/main/java/com/tem/bocai/util/CompletedTodayCrawler.java
Normal file
396
src/main/java/com/tem/bocai/util/CompletedTodayCrawler.java
Normal file
@@ -0,0 +1,396 @@
|
|||||||
|
package com.tem.bocai.util;
|
||||||
|
|
||||||
|
|
||||||
|
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 java.io.File;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class CompletedTodayCrawler implements PageProcessor {
|
||||||
|
|
||||||
|
private final String token;
|
||||||
|
private Site site;
|
||||||
|
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
|
public CompletedTodayCrawler(String token) {
|
||||||
|
this.token = token;
|
||||||
|
initSite();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initSite() {
|
||||||
|
site = Site.me()
|
||||||
|
.setRetryTimes(3)
|
||||||
|
.setSleepTime(2000) // 增加等待时间
|
||||||
|
.setTimeOut(15000) // 增加超时时间
|
||||||
|
.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36")
|
||||||
|
.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8")
|
||||||
|
.addHeader("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
|
||||||
|
.addHeader("Accept-Encoding", "gzip, deflate, br")
|
||||||
|
.addHeader("Connection", "keep-alive")
|
||||||
|
.addHeader("Upgrade-Insecure-Requests", "1")
|
||||||
|
.addHeader("Sec-Fetch-Dest", "document")
|
||||||
|
.addHeader("Sec-Fetch-Mode", "navigate")
|
||||||
|
.addHeader("Sec-Fetch-Site", "same-origin")
|
||||||
|
.addHeader("Sec-Fetch-User", "?1");
|
||||||
|
|
||||||
|
// 设置cookie
|
||||||
|
if (token != null && !token.isEmpty()) {
|
||||||
|
site.addHeader("cookie", "token=" + token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(Page page) {
|
||||||
|
String url = page.getUrl().toString();
|
||||||
|
System.out.println("处理页面: " + url);
|
||||||
|
|
||||||
|
Html html = page.getHtml();
|
||||||
|
String content = html.toString();
|
||||||
|
|
||||||
|
// 打印一些基本信息
|
||||||
|
System.out.println("页面标题: " + html.xpath("//title/text()").get());
|
||||||
|
System.out.println("页面大小: " + content.length() + " 字符");
|
||||||
|
|
||||||
|
// 检查是否有"暂无数据"提示
|
||||||
|
if (content.contains("暂无数据")) {
|
||||||
|
System.out.println("警告: 页面显示'暂无数据'");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 解析注单数据
|
||||||
|
List<Map<String, Object>> betList = parseBetHtml(content);
|
||||||
|
if (betList.isEmpty()) {
|
||||||
|
System.out.println("未解析到注单数据");
|
||||||
|
|
||||||
|
// 尝试从其他可能的位置解析
|
||||||
|
extractDebugInfo(html);
|
||||||
|
} else {
|
||||||
|
System.out.println("解析到 " + betList.size() + " 条注单数据");
|
||||||
|
|
||||||
|
// 打印部分数据示例
|
||||||
|
printSampleData(betList);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存原始HTML用于调试
|
||||||
|
saveHtmlForDebug(content, url);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析注单HTML数据
|
||||||
|
*/
|
||||||
|
private List<Map<String, Object>> parseBetHtml(String htmlContent) {
|
||||||
|
List<Map<String, Object>> betList = new ArrayList<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Document doc = Jsoup.parse(htmlContent);
|
||||||
|
|
||||||
|
// 查找注单表格
|
||||||
|
Element table = doc.selectFirst("table.list");
|
||||||
|
if (table == null) {
|
||||||
|
System.out.println("未找到注单表格");
|
||||||
|
return betList;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查找表头
|
||||||
|
Elements headers = table.select("thead th");
|
||||||
|
List<String> headerList = new ArrayList<>();
|
||||||
|
for (Element header : headers) {
|
||||||
|
headerList.add(header.text().trim());
|
||||||
|
}
|
||||||
|
System.out.println("表头信息: " + headerList);
|
||||||
|
|
||||||
|
// 查找数据行(跳过表头)
|
||||||
|
Elements rows = table.select("tbody tr");
|
||||||
|
|
||||||
|
for (Element row : rows) {
|
||||||
|
// 跳过"暂无数据"的行
|
||||||
|
if (row.select("td.nodata").size() > 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> betData = new HashMap<>();
|
||||||
|
Elements cells = row.select("td");
|
||||||
|
|
||||||
|
// 按列解析数据
|
||||||
|
for (int i = 0; i < cells.size() && i < headerList.size(); i++) {
|
||||||
|
String header = headerList.get(i);
|
||||||
|
String value = cells.get(i).text().trim();
|
||||||
|
|
||||||
|
// 根据表头映射到对应的字段名
|
||||||
|
switch (header) {
|
||||||
|
case "注单号":
|
||||||
|
betData.put("bet_id", value);
|
||||||
|
break;
|
||||||
|
case "时间":
|
||||||
|
betData.put("time", value);
|
||||||
|
break;
|
||||||
|
case "类型":
|
||||||
|
betData.put("type", value);
|
||||||
|
break;
|
||||||
|
case "玩法":
|
||||||
|
betData.put("game_type", value);
|
||||||
|
break;
|
||||||
|
case "盘":
|
||||||
|
betData.put("plate", value);
|
||||||
|
break;
|
||||||
|
case "下注金额":
|
||||||
|
betData.put("bet_amount", parseAmount(value));
|
||||||
|
break;
|
||||||
|
case "退水(%)":
|
||||||
|
betData.put("rebate_rate", parseRate(value));
|
||||||
|
break;
|
||||||
|
case "结果":
|
||||||
|
betData.put("result", parseResult(value));
|
||||||
|
betData.put("result_amount", parseResultAmount(value));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
betData.put(header, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加额外信息
|
||||||
|
if (!betData.isEmpty()) {
|
||||||
|
betData.put("parse_time", dateFormat.format(new Date()));
|
||||||
|
betData.put("source", "completed_today");
|
||||||
|
|
||||||
|
// 提取期数信息(从玩法中提取)
|
||||||
|
extractPeriodInfo(betData);
|
||||||
|
|
||||||
|
betList.add(betData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("解析HTML时出错: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return betList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从玩法中提取期数信息
|
||||||
|
*/
|
||||||
|
private void extractPeriodInfo(Map<String, Object> betData) {
|
||||||
|
try {
|
||||||
|
Object gameTypeObj = betData.get("game_type");
|
||||||
|
if (gameTypeObj instanceof String) {
|
||||||
|
String gameType = (String) gameTypeObj;
|
||||||
|
|
||||||
|
// 尝试匹配期数模式,如"2024001", "001", "期号2024001"等
|
||||||
|
Pattern pattern = Pattern.compile("(\\d{7})|期[号码]?(\\d{3,7})|(\\d{3,4})期");
|
||||||
|
Matcher matcher = pattern.matcher(gameType);
|
||||||
|
|
||||||
|
if (matcher.find()) {
|
||||||
|
for (int i = 1; i <= matcher.groupCount(); i++) {
|
||||||
|
if (matcher.group(i) != null) {
|
||||||
|
betData.put("period", matcher.group(i));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 忽略提取错误
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析金额(去除货币符号)
|
||||||
|
*/
|
||||||
|
private Double parseAmount(String amountStr) {
|
||||||
|
try {
|
||||||
|
if (amountStr == null || amountStr.isEmpty()) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
// 移除非数字字符(保留小数点和负号)
|
||||||
|
String cleaned = amountStr.replaceAll("[^\\d.-]", "");
|
||||||
|
return cleaned.isEmpty() ? 0.0 : Double.parseDouble(cleaned);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析退水率
|
||||||
|
*/
|
||||||
|
private Double parseRate(String rateStr) {
|
||||||
|
try {
|
||||||
|
if (rateStr == null || rateStr.isEmpty()) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
// 移除百分号
|
||||||
|
String cleaned = rateStr.replace("%", "").trim();
|
||||||
|
return cleaned.isEmpty() ? 0.0 : Double.parseDouble(cleaned) / 100;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析结果状态
|
||||||
|
*/
|
||||||
|
private String parseResult(String resultStr) {
|
||||||
|
if (resultStr == null) {
|
||||||
|
return "未知";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resultStr.contains("赢") || resultStr.contains("+")) {
|
||||||
|
return "赢";
|
||||||
|
} else if (resultStr.contains("输") || resultStr.contains("-")) {
|
||||||
|
return "输";
|
||||||
|
} else if (resultStr.contains("和") || resultStr.contains("0")) {
|
||||||
|
return "和";
|
||||||
|
} else if (resultStr.contains("取消")) {
|
||||||
|
return "取消";
|
||||||
|
} else {
|
||||||
|
return "未知";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析结果金额
|
||||||
|
*/
|
||||||
|
private Double parseResultAmount(String resultStr) {
|
||||||
|
try {
|
||||||
|
// 提取数字部分(包含负号)
|
||||||
|
Pattern pattern = Pattern.compile("[-+]?\\d+\\.?\\d*");
|
||||||
|
Matcher matcher = pattern.matcher(resultStr);
|
||||||
|
|
||||||
|
if (matcher.find()) {
|
||||||
|
return Double.parseDouble(matcher.group());
|
||||||
|
}
|
||||||
|
return 0.0;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换数据结构以适应数据库
|
||||||
|
*/
|
||||||
|
private List<Map<String, Object>> convertForDatabase(List<Map<String, Object>> betList) {
|
||||||
|
List<Map<String, Object>> dbData = new ArrayList<>();
|
||||||
|
|
||||||
|
for (Map<String, Object> bet : betList) {
|
||||||
|
Map<String, Object> dbRecord = new HashMap<>();
|
||||||
|
|
||||||
|
dbRecord.put("id", bet.get("bet_id"));
|
||||||
|
dbRecord.put("bet_id", bet.get("bet_id"));
|
||||||
|
dbRecord.put("period", bet.get("period"));
|
||||||
|
dbRecord.put("bet_time", bet.get("time"));
|
||||||
|
dbRecord.put("game_type", bet.get("game_type"));
|
||||||
|
dbRecord.put("plate", bet.get("plate"));
|
||||||
|
dbRecord.put("bet_amount", bet.get("bet_amount"));
|
||||||
|
dbRecord.put("rebate_rate", bet.get("rebate_rate"));
|
||||||
|
dbRecord.put("result", bet.get("result"));
|
||||||
|
dbRecord.put("result_amount", bet.get("result_amount"));
|
||||||
|
dbRecord.put("parse_time", bet.get("parse_time"));
|
||||||
|
dbRecord.put("source", bet.get("source"));
|
||||||
|
|
||||||
|
dbData.add(dbRecord);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dbData;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存HTML用于调试
|
||||||
|
*/
|
||||||
|
private void saveHtmlForDebug(String content, String url) {
|
||||||
|
try {
|
||||||
|
String safeUrl = url.replaceAll("[^a-zA-Z0-9]", "_");
|
||||||
|
String fileName = "debug_" + safeUrl + "_" + System.currentTimeMillis() + ".html";
|
||||||
|
String filePath = "output/debug/" + fileName;
|
||||||
|
|
||||||
|
File directory = new File("output/debug");
|
||||||
|
if (!directory.exists()) {
|
||||||
|
directory.mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
File outputFile = new File(filePath);
|
||||||
|
java.nio.file.Files.write(outputFile.toPath(), content.getBytes());
|
||||||
|
|
||||||
|
System.out.println("调试HTML已保存: " + outputFile.getAbsolutePath());
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("保存调试HTML失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提取调试信息
|
||||||
|
*/
|
||||||
|
private void extractDebugInfo(Html html) {
|
||||||
|
System.out.println("\n=== 调试信息 ===");
|
||||||
|
|
||||||
|
// 检查所有表格
|
||||||
|
List<String> tables = html.xpath("//table/@class").all();
|
||||||
|
System.out.println("所有表格class: " + tables);
|
||||||
|
|
||||||
|
// 检查所有tr
|
||||||
|
int trCount = html.xpath("//tr").all().size();
|
||||||
|
System.out.println("TR数量: " + trCount);
|
||||||
|
|
||||||
|
// 检查所有td
|
||||||
|
int tdCount = html.xpath("//td").all().size();
|
||||||
|
System.out.println("TD数量: " + tdCount);
|
||||||
|
|
||||||
|
// 检查cookie相关元素
|
||||||
|
String cookieScript = html.xpath("//script[contains(text(), 'token')]/text()").get();
|
||||||
|
if (cookieScript != null && cookieScript.contains("token")) {
|
||||||
|
System.out.println("发现token相关脚本");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否有JavaScript重定向
|
||||||
|
String redirectScript = html.xpath("//script[contains(text(), 'location.href') or contains(text(), 'window.location')]/text()").get();
|
||||||
|
if (redirectScript != null) {
|
||||||
|
System.out.println("发现重定向脚本: " + redirectScript.substring(0, Math.min(100, redirectScript.length())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打印示例数据
|
||||||
|
*/
|
||||||
|
private void printSampleData(List<Map<String, Object>> betList) {
|
||||||
|
System.out.println("\n=== 前3条数据示例 ===");
|
||||||
|
int count = Math.min(3, betList.size());
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
Map<String, Object> bet = betList.get(i);
|
||||||
|
System.out.printf("注单%d: ID=%s, 时间=%s, 金额=%.2f, 结果=%s, 金额=%.2f%n",
|
||||||
|
i + 1,
|
||||||
|
bet.get("bet_id"),
|
||||||
|
bet.get("time"),
|
||||||
|
bet.get("bet_amount"),
|
||||||
|
bet.get("result"),
|
||||||
|
bet.get("result_amount"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Site getSite() {
|
||||||
|
return site;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
String url = "https://4701268539-esh.qdk63ayw8g.com/member/bets?settled=true";
|
||||||
|
// 创建爬虫
|
||||||
|
Spider.create(new CompletedTodayCrawler(""))
|
||||||
|
.addUrl(url) // 添加起始URL
|
||||||
|
.thread(1) // 线程数
|
||||||
|
.run(); // 开始爬取
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -23,6 +23,7 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
//开奖的历史结果
|
||||||
public class LotteryWebMagicCrawler implements PageProcessor {
|
public class LotteryWebMagicCrawler implements PageProcessor {
|
||||||
|
|
||||||
private final String token;
|
private final String token;
|
||||||
|
|||||||
Reference in New Issue
Block a user