Compare commits
4 Commits
650d55323c
...
81e10c7cfb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
81e10c7cfb | ||
|
|
ec367725a3 | ||
|
|
17c620d530 | ||
|
|
5bb2a9a1ee |
@ -22,10 +22,11 @@ import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Google排名查询工具类(基于speculationrules解析)
|
||||
*
|
||||
* <p>
|
||||
* 本工具类采用全新的解析方案:
|
||||
* 1. 不再解析复杂的DOM结构
|
||||
* 2. 直接提取Google返回的<script type="speculationrules">中的URL列表
|
||||
@ -58,13 +59,14 @@ public class GoogleRankUtil {
|
||||
private static volatile int BASE_BACKOFF_MS = 10000;
|
||||
private static volatile boolean KEEP_BROWSER_OPEN = false;
|
||||
private static volatile String GOOGLE_REGION = "GH"; // Google地理位置(如:US, CN, ZA等)
|
||||
private static volatile String CHROMEDRIVER_PATH = null; // ChromeDriver路径(优先级最高)
|
||||
|
||||
// 线程本地变量
|
||||
private static final ThreadLocal<WebDriver> TL_DRIVER = new ThreadLocal<>();
|
||||
private static final ThreadLocal<String> TL_USER_DATA_DIR = new ThreadLocal<>(); // 记录用户数据目录
|
||||
private static final AtomicLong LAST_NAV_AT = new AtomicLong(0L);
|
||||
|
||||
// 【关键修复】全局锁:防止定时任务并发执行导致的会话冲突
|
||||
private static final ReentrantLock GLOBAL_LOCK = new ReentrantLock();
|
||||
|
||||
// ==================== 配置方法 ====================
|
||||
|
||||
public static void setHeadless(boolean headless) {
|
||||
@ -97,22 +99,8 @@ public class GoogleRankUtil {
|
||||
return GOOGLE_REGION;
|
||||
}
|
||||
|
||||
public static void setChromedriverPath(String path) {
|
||||
CHROMEDRIVER_PATH = (path == null || path.trim().isEmpty()) ? null : path.trim();
|
||||
if (CHROMEDRIVER_PATH != null) {
|
||||
System.setProperty("webdriver.chrome.driver", CHROMEDRIVER_PATH);
|
||||
log.info("手动设置ChromeDriver路径: {}", CHROMEDRIVER_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getChromedriverPath() {
|
||||
return CHROMEDRIVER_PATH;
|
||||
}
|
||||
|
||||
public static void shutdownDriver() {
|
||||
WebDriver d = TL_DRIVER.get();
|
||||
String userDataDir = TL_USER_DATA_DIR.get();
|
||||
|
||||
if (d != null) {
|
||||
try {
|
||||
d.quit();
|
||||
@ -120,39 +108,6 @@ public class GoogleRankUtil {
|
||||
}
|
||||
TL_DRIVER.remove();
|
||||
}
|
||||
|
||||
// 清理临时用户数据目录
|
||||
if (userDataDir != null && !userDataDir.isEmpty()) {
|
||||
try {
|
||||
java.io.File dir = new java.io.File(userDataDir);
|
||||
if (dir.exists() && dir.isDirectory()) {
|
||||
deleteDirectory(dir);
|
||||
log.debug("已清理临时用户数据目录: {}", userDataDir);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("清理临时用户数据目录失败: {}", e.getMessage());
|
||||
}
|
||||
TL_USER_DATA_DIR.remove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归删除目录
|
||||
*/
|
||||
private static void deleteDirectory(java.io.File directory) {
|
||||
if (directory.exists()) {
|
||||
java.io.File[] files = directory.listFiles();
|
||||
if (files != null) {
|
||||
for (java.io.File file : files) {
|
||||
if (file.isDirectory()) {
|
||||
deleteDirectory(file);
|
||||
} else {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
directory.delete();
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 核心方法 ====================
|
||||
@ -324,16 +279,16 @@ public class GoogleRankUtil {
|
||||
|
||||
/**
|
||||
* 【核心方法】从speculationrules脚本中解析排名
|
||||
*
|
||||
* <p>
|
||||
* 解析逻辑:
|
||||
* 1. 查找<script type="speculationrules">标签
|
||||
* 2. 提取JSON内容
|
||||
* 3. 解析prefetch数组中的urls
|
||||
* 4. 按顺序匹配目标网站
|
||||
*
|
||||
* @param html HTML源码
|
||||
* @param html HTML源码
|
||||
* @param targetSite 目标网站
|
||||
* @param baseRank 基础排名(第1页=0,第2页=10)
|
||||
* @param baseRank 基础排名(第1页=0,第2页=10)
|
||||
* @return 排名(>0表示找到,-1表示未找到)
|
||||
*/
|
||||
private static int parseRankFromSpeculationRules(String html, String targetSite, int baseRank) {
|
||||
@ -572,8 +527,6 @@ public class GoogleRankUtil {
|
||||
d.quit();
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
// 【关键】清理旧的临时目录
|
||||
cleanupOldUserDataDir();
|
||||
TL_DRIVER.remove();
|
||||
}
|
||||
d = createWebDriver();
|
||||
@ -582,181 +535,21 @@ public class GoogleRankUtil {
|
||||
return d;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理旧的用户数据目录
|
||||
*/
|
||||
private static void cleanupOldUserDataDir() {
|
||||
String oldDir = TL_USER_DATA_DIR.get();
|
||||
if (oldDir != null && !oldDir.isEmpty()) {
|
||||
try {
|
||||
// 强制等待一下,确保 Chrome 进程完全退出
|
||||
Thread.sleep(1000);
|
||||
|
||||
java.io.File dir = new java.io.File(oldDir);
|
||||
if (dir.exists() && dir.isDirectory()) {
|
||||
deleteDirectory(dir);
|
||||
log.debug("已清理旧的用户数据目录: {}", oldDir);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("清理旧的用户数据目录失败: {}", e.getMessage());
|
||||
}
|
||||
TL_USER_DATA_DIR.remove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动搜索ChromeDriver可执行文件
|
||||
* 在常见位置查找:项目目录、系统PATH、常见安装位置
|
||||
*/
|
||||
private static String findChromeDriver() {
|
||||
String osName = System.getProperty("os.name").toLowerCase();
|
||||
boolean isWindows = osName.contains("win");
|
||||
boolean isMac = osName.contains("mac");
|
||||
|
||||
String executableName = isWindows ? "chromedriver.exe" : "chromedriver";
|
||||
|
||||
// 搜索路径列表(按优先级)
|
||||
List<String> searchPaths = new ArrayList<>();
|
||||
|
||||
// 1. 项目根目录及其子目录
|
||||
String userDir = System.getProperty("user.dir");
|
||||
searchPaths.add(userDir);
|
||||
searchPaths.add(userDir + "/drivers");
|
||||
searchPaths.add(userDir + "/driver");
|
||||
searchPaths.add(userDir + "/chromedriver");
|
||||
searchPaths.add(userDir + "/../drivers");
|
||||
searchPaths.add(userDir + "/../driver");
|
||||
|
||||
// 2. 用户目录
|
||||
String userHome = System.getProperty("user.home");
|
||||
searchPaths.add(userHome + "/drivers");
|
||||
searchPaths.add(userHome + "/driver");
|
||||
|
||||
// 3. Windows 常见位置
|
||||
if (isWindows) {
|
||||
searchPaths.add("C:/chromedriver");
|
||||
searchPaths.add("C:/chromedriver-win64");
|
||||
searchPaths.add("D:/chromedriver");
|
||||
searchPaths.add("D:/chromedriver-win64");
|
||||
searchPaths.add("C:/Program Files/chromedriver");
|
||||
searchPaths.add("C:/Program Files (x86)/chromedriver");
|
||||
searchPaths.add(userHome + "/Downloads");
|
||||
searchPaths.add(userHome + "/Downloads/chromedriver-win64");
|
||||
}
|
||||
|
||||
// 4. Mac 常见位置
|
||||
if (isMac) {
|
||||
searchPaths.add("/usr/local/bin");
|
||||
searchPaths.add("/usr/bin");
|
||||
searchPaths.add("/opt/homebrew/bin");
|
||||
searchPaths.add("/opt/local/bin");
|
||||
searchPaths.add(userHome + "/Downloads");
|
||||
}
|
||||
|
||||
// 5. Linux 常见位置
|
||||
if (!isWindows && !isMac) {
|
||||
searchPaths.add("/usr/local/bin");
|
||||
searchPaths.add("/usr/bin");
|
||||
searchPaths.add("/bin");
|
||||
searchPaths.add("/opt/chromedriver");
|
||||
searchPaths.add("/opt/google/chrome");
|
||||
searchPaths.add(userHome + "/.local/bin");
|
||||
searchPaths.add(userHome + "/bin");
|
||||
searchPaths.add("/snap/bin");
|
||||
}
|
||||
|
||||
// 6. 从 PATH 环境变量中查找
|
||||
String pathEnv = System.getenv("PATH");
|
||||
if (pathEnv != null) {
|
||||
String[] paths = pathEnv.split(isWindows ? ";" : ":");
|
||||
for (String path : paths) {
|
||||
searchPaths.add(path.trim());
|
||||
}
|
||||
}
|
||||
|
||||
// 开始搜索
|
||||
log.debug("开始在 {} 个位置搜索 ChromeDriver...", searchPaths.size());
|
||||
for (String searchPath : searchPaths) {
|
||||
java.io.File file = new java.io.File(searchPath, executableName);
|
||||
if (file.exists() && file.isFile()) {
|
||||
if (file.canExecute()) {
|
||||
log.info("✅ 自动发现ChromeDriver: {}", file.getAbsolutePath());
|
||||
return file.getAbsolutePath();
|
||||
} else {
|
||||
log.warn("⚠️ 找到ChromeDriver但无执行权限: {}", file.getAbsolutePath());
|
||||
// 尝试添加执行权限
|
||||
if (file.setExecutable(true)) {
|
||||
log.info("✅ 已自动添加执行权限: {}", file.getAbsolutePath());
|
||||
return file.getAbsolutePath();
|
||||
}
|
||||
}
|
||||
}
|
||||
// 同时尝试没有扩展名的情况(某些系统)
|
||||
if (isWindows) {
|
||||
file = new java.io.File(searchPath, "chromedriver");
|
||||
if (file.exists() && file.isFile()) {
|
||||
log.info("✅ 自动发现ChromeDriver: {}", file.getAbsolutePath());
|
||||
return file.getAbsolutePath();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.warn("❌ 未能自动找到ChromeDriver,已搜索 {} 个位置", searchPaths.size());
|
||||
log.warn("💡 建议:");
|
||||
log.warn(" 1. 手动下载 ChromeDriver: https://googlechromelabs.github.io/chrome-for-testing/");
|
||||
log.warn(" 2. 放到以下任意位置: /usr/local/bin, /usr/bin, 或项目drivers目录");
|
||||
log.warn(" 3. 或使用代码配置: GoogleRankUtil.setChromedriverPath(\"/path/to/chromedriver\")");
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建WebDriver实例
|
||||
*/
|
||||
private static WebDriver createWebDriver() {
|
||||
// 优先级1:静态配置的路径
|
||||
if (CHROMEDRIVER_PATH != null && !CHROMEDRIVER_PATH.isEmpty()) {
|
||||
System.setProperty("webdriver.chrome.driver", CHROMEDRIVER_PATH);
|
||||
log.info("使用手动配置的ChromeDriver路径: {}", CHROMEDRIVER_PATH);
|
||||
} else {
|
||||
// 优先级2:尝试使用 WebDriverManager 自动配置
|
||||
try {
|
||||
WebDriverManager.chromedriver().setup();
|
||||
log.info("WebDriverManager 已自动配置 chromedriver");
|
||||
} catch (Throwable t) {
|
||||
log.warn("WebDriverManager 配置失败,尝试其他方法: {}", t.getMessage());
|
||||
|
||||
// 优先级3:环境变量
|
||||
String sysProp = System.getProperty("webdriver.chrome.driver");
|
||||
String envProp = System.getenv("CHROMEDRIVER_PATH");
|
||||
|
||||
if (sysProp == null || sysProp.isEmpty()) {
|
||||
String foundPath = null;
|
||||
|
||||
// 优先级4:环境变量指定的路径
|
||||
if (envProp != null && !envProp.isEmpty()) {
|
||||
foundPath = envProp;
|
||||
log.info("使用环境变量CHROMEDRIVER_PATH: {}", foundPath);
|
||||
} else {
|
||||
// 优先级5:自动搜索常见位置
|
||||
foundPath = findChromeDriver();
|
||||
}
|
||||
|
||||
// 优先级6:操作系统默认路径(最后的兜底)
|
||||
if (foundPath == null) {
|
||||
String osName = System.getProperty("os.name").toLowerCase();
|
||||
if (osName.contains("win")) {
|
||||
foundPath = "D:/chromedriver-win64/chromedriver.exe";
|
||||
} else if (osName.contains("mac")) {
|
||||
foundPath = "/usr/local/bin/chromedriver";
|
||||
} else {
|
||||
foundPath = "/usr/local/bin/chromedriver";
|
||||
}
|
||||
log.warn("使用操作系统默认路径: {} (可能不存在,建议手动配置)", foundPath);
|
||||
}
|
||||
|
||||
System.setProperty("webdriver.chrome.driver", foundPath);
|
||||
log.info("最终使用ChromeDriver路径: {}", foundPath);
|
||||
}
|
||||
try {
|
||||
WebDriverManager.chromedriver().setup();
|
||||
log.info("WebDriverManager 已自动配置 chromedriver");
|
||||
} catch (Throwable t) {
|
||||
log.warn("WebDriverManager 配置失败,尝试使用手动路径: {}", t.getMessage());
|
||||
String sysProp = System.getProperty("webdriver.chrome.driver");
|
||||
String envProp = System.getenv("CHROMEDRIVER_PATH");
|
||||
if (sysProp == null || sysProp.isEmpty()) {
|
||||
String path = (envProp != null && !envProp.isEmpty()) ? envProp : "/usr/local/bin/chromedriver";
|
||||
System.setProperty("webdriver.chrome.driver", path);
|
||||
log.info("使用ChromeDriver路径: {}", path);
|
||||
}
|
||||
}
|
||||
|
||||
@ -789,15 +582,30 @@ public class GoogleRankUtil {
|
||||
options.addArguments("--no-sandbox");
|
||||
options.addArguments("--disable-dev-shm-usage");
|
||||
|
||||
// 【关键修复】服务器环境:不指定user-data-dir,让Chrome自动管理临时配置
|
||||
// 这样每次都是完全独立的临时环境,避免"already in use"冲突!
|
||||
log.debug("使用Chrome默认临时配置(不指定user-data-dir)");
|
||||
// 【关键修复】服务器环境:强制使用唯一的临时目录,彻底避免冲突
|
||||
try {
|
||||
String tempDir = System.getProperty("java.io.tmpdir");
|
||||
String uniqueDataDir = tempDir + "/chrome-data-" +
|
||||
System.currentTimeMillis() + "-" +
|
||||
Thread.currentThread().getId() + "-" +
|
||||
(int)(Math.random() * 100000);
|
||||
|
||||
// 【额外修复】添加更多服务器友好的参数
|
||||
options.addArguments("--disable-gpu"); // 禁用GPU加速
|
||||
java.io.File dataDir = new java.io.File(uniqueDataDir);
|
||||
if (!dataDir.exists()) {
|
||||
dataDir.mkdirs();
|
||||
}
|
||||
|
||||
options.addArguments("--user-data-dir=" + uniqueDataDir);
|
||||
log.info("✅ 使用唯一临时目录: {}", uniqueDataDir);
|
||||
} catch (Exception e) {
|
||||
log.warn("创建临时目录失败: {}", e.getMessage());
|
||||
}
|
||||
|
||||
// 【额外修复】添加更多服务器友好参数
|
||||
options.addArguments("--disable-gpu");
|
||||
options.addArguments("--disable-software-rasterizer");
|
||||
options.addArguments("--disable-setuid-sandbox");
|
||||
options.addArguments("--remote-debugging-port=0"); // 禁用远程调试,避免端口冲突
|
||||
options.addArguments("--remote-debugging-port=0");
|
||||
|
||||
// 是否保留浏览器窗口
|
||||
options.setExperimentalOption("detach", KEEP_BROWSER_OPEN);
|
||||
@ -814,6 +622,70 @@ public class GoogleRankUtil {
|
||||
return driver;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测是否为服务器环境(Linux 且无显示)
|
||||
*/
|
||||
private static boolean isServerEnvironment() {
|
||||
String osName = System.getProperty("os.name").toLowerCase();
|
||||
boolean isLinux = osName.contains("linux");
|
||||
|
||||
// 检查是否有 DISPLAY 环境变量(Linux 图形界面)
|
||||
String display = System.getenv("DISPLAY");
|
||||
boolean hasDisplay = (display != null && !display.isEmpty());
|
||||
|
||||
// Linux 且无显示 = 服务器环境
|
||||
return isLinux && !hasDisplay;
|
||||
}
|
||||
|
||||
/**
|
||||
* 强制清理残留的 Chrome 和 ChromeDriver 进程
|
||||
*/
|
||||
private static void forceKillChromeProcesses() {
|
||||
try {
|
||||
String osName = System.getProperty("os.name").toLowerCase();
|
||||
|
||||
if (osName.contains("linux") || osName.contains("mac")) {
|
||||
// Linux/Mac: 使用 pkill 命令
|
||||
try {
|
||||
Process p1 = Runtime.getRuntime().exec(new String[]{"pkill", "-9", "chrome"});
|
||||
p1.waitFor();
|
||||
log.debug("已执行 pkill chrome");
|
||||
} catch (Exception e) {
|
||||
log.debug("pkill chrome 失败: {}", e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
Process p2 = Runtime.getRuntime().exec(new String[]{"pkill", "-9", "chromedriver"});
|
||||
p2.waitFor();
|
||||
log.debug("已执行 pkill chromedriver");
|
||||
} catch (Exception e) {
|
||||
log.debug("pkill chromedriver 失败: {}", e.getMessage());
|
||||
}
|
||||
} else if (osName.contains("win")) {
|
||||
// Windows: 使用 taskkill 命令
|
||||
try {
|
||||
Process p1 = Runtime.getRuntime().exec("taskkill /F /IM chrome.exe");
|
||||
p1.waitFor();
|
||||
log.debug("已执行 taskkill chrome.exe");
|
||||
} catch (Exception e) {
|
||||
log.debug("taskkill chrome.exe 失败: {}", e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
Process p2 = Runtime.getRuntime().exec("taskkill /F /IM chromedriver.exe");
|
||||
p2.waitFor();
|
||||
log.debug("已执行 taskkill chromedriver.exe");
|
||||
} catch (Exception e) {
|
||||
log.debug("taskkill chromedriver.exe 失败: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
log.info("✅ 已尝试清理残留的 Chrome 进程");
|
||||
} catch (Exception e) {
|
||||
log.warn("清理 Chrome 进程失败: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化排名输出
|
||||
*/
|
||||
@ -825,48 +697,74 @@ public class GoogleRankUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询谷歌关键词排名主体方法
|
||||
* @author vinjor-M
|
||||
* @date 11:17 2025/10/24
|
||||
* @param searchText TODO
|
||||
* @param site TODO
|
||||
* @return int
|
||||
* 查询谷歌关键词排名主体方法(定时任务专用版本)
|
||||
*
|
||||
* 【关键修复】:
|
||||
* 1. 添加全局锁,防止定时任务并发执行
|
||||
* 2. 自动检测服务器环境,强制使用 headless 模式
|
||||
* 3. 禁用会话复用,每次独立执行
|
||||
* 4. 强制清理 Chrome 进程
|
||||
*
|
||||
* @param searchText 搜索关键词
|
||||
* @param site 目标网站
|
||||
* @return 排名(>0表示找到,-1表示未找到,-2表示验证码,0表示失败)
|
||||
* @author menft
|
||||
* @date 2025/10/24
|
||||
**/
|
||||
public static int getGoogleRankMain(String searchText, String site) {
|
||||
int rank = -1;
|
||||
// 配置参数
|
||||
GoogleRankUtil.setHeadless(false); // Mac环境建议 false
|
||||
GoogleRankUtil.setSessionReuse(true); // 复用浏览器会话
|
||||
GoogleRankUtil.setGlobalRequestInterval(8000, 5000); // 8s + 抖动 0~5s
|
||||
GoogleRankUtil.setRetryPolicy(3, 10000); // 重试3次,递增退避
|
||||
GoogleRankUtil.setKeepBrowserOpen(false); // 结束后关闭
|
||||
// 【关键】使用全局锁,确保同一时间只有一个任务执行
|
||||
GLOBAL_LOCK.lock();
|
||||
log.info("🔒 获取全局锁成功,开始执行 Google 排名查询任务");
|
||||
|
||||
// 【新增】设置Google地理位置
|
||||
// 常见代码:US=美国, CN=中国, ZA=南非, EG=埃及, NG=尼日利亚,GH=加纳,
|
||||
GoogleRankUtil.setGoogleRegion("GH"); // 设置为加纳
|
||||
try {
|
||||
int rank = -1;
|
||||
|
||||
// 测试关键词
|
||||
List<String> keywords = new ArrayList<>();
|
||||
keywords.add(searchText);
|
||||
// System.out.println("========== GoogleRankUtil 测试 ==========");
|
||||
// System.out.println("解析方案:speculationrules(稳定、准确)");
|
||||
// System.out.println("目标站点: " + site);
|
||||
// System.out.println("地理位置: " + (GoogleRankUtil.getGoogleRegion() != null ? GoogleRankUtil.getGoogleRegion() : "默认"));
|
||||
// System.out.println("关键词数量: " + keywords.size());
|
||||
// System.out.println("=========================================\n");
|
||||
for (String kw : keywords) {
|
||||
// System.out.println("[" + (i + 1) + "/" + keywords.size() + "] 正在采集关键词: " + kw);
|
||||
// long startTime = System.currentTimeMillis();
|
||||
rank = getGoogleRank(kw, site);
|
||||
// long elapsed = System.currentTimeMillis() - startTime;
|
||||
// System.out.println("关键词[" + kw + "] 排名: " + formatRank(rank));
|
||||
// System.out.println("耗时: " + elapsed + "ms");
|
||||
// System.out.println("-----------------------------------\n");
|
||||
// 【关键】检测是否为服务器环境(Linux/无显示环境)
|
||||
boolean isServer = isServerEnvironment();
|
||||
log.info("环境检测:isServer={}, OS={}", isServer, System.getProperty("os.name"));
|
||||
|
||||
// 配置参数(服务器环境专用)
|
||||
GoogleRankUtil.setHeadless(isServer); // 服务器强制 headless
|
||||
GoogleRankUtil.setSessionReuse(false); // 【关键】禁用会话复用
|
||||
GoogleRankUtil.setGlobalRequestInterval(8000, 5000); // 8s + 抖动 0~5s
|
||||
GoogleRankUtil.setRetryPolicy(3, 10000); // 重试3次,递增退避
|
||||
GoogleRankUtil.setKeepBrowserOpen(false); // 【关键】强制关闭浏览器
|
||||
|
||||
log.info("配置完成:headless={}, sessionReuse={}, region={}",
|
||||
HEADLESS, SESSION_REUSE, GOOGLE_REGION);
|
||||
|
||||
// 执行查询
|
||||
List<String> keywords = new ArrayList<>();
|
||||
keywords.add(searchText);
|
||||
|
||||
for (String kw : keywords) {
|
||||
log.info("正在查询关键词:{}, 目标站点:{}", kw, site);
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
rank = getGoogleRank(kw, site);
|
||||
|
||||
long elapsed = System.currentTimeMillis() - startTime;
|
||||
log.info("查询完成:关键词[{}] 排名={}, 耗时={}ms", kw, formatRank(rank), elapsed);
|
||||
}
|
||||
|
||||
// 【关键】强制清理 WebDriver
|
||||
GoogleRankUtil.shutdownDriver();
|
||||
|
||||
// 【额外保险】强制清理残留的 Chrome 进程
|
||||
if (isServer) {
|
||||
forceKillChromeProcesses();
|
||||
}
|
||||
|
||||
return rank;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("Google 排名查询异常", e);
|
||||
return 0;
|
||||
} finally {
|
||||
// 【关键】释放全局锁
|
||||
GLOBAL_LOCK.unlock();
|
||||
log.info("🔓 释放全局锁");
|
||||
}
|
||||
// System.out.println("========== 采集完成 ==========");
|
||||
// 清理
|
||||
GoogleRankUtil.shutdownDriver();
|
||||
return rank ;
|
||||
}
|
||||
// ==================== 测试方法 ====================
|
||||
|
||||
@ -882,12 +780,11 @@ public class GoogleRankUtil {
|
||||
GoogleRankUtil.setKeepBrowserOpen(false); // 结束后关闭
|
||||
|
||||
// 【新增】设置Google地理位置
|
||||
// 常见代码:US=美国, CN=中国, ZA=南非, EG=埃及, NG=尼日利亚
|
||||
GoogleRankUtil.setGoogleRegion("GH"); // 设置为南非
|
||||
|
||||
// 常见代码:US=美国, CN=中国, ZA=南非, EG=埃及, NG=尼日利亚,GH=加纳,
|
||||
GoogleRankUtil.setGoogleRegion("GH"); // 设置为加纳
|
||||
|
||||
// 测试关键词
|
||||
List<String> keywords = Arrays.asList("cd duck");
|
||||
List<String> keywords = Arrays.asList("cd truck");
|
||||
String site = "www.cdtrucktralier.com";
|
||||
|
||||
System.out.println("========== GoogleRankUtil 测试 ==========");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user