修复色花堂抓取时 ChromeDriver 与浏览器版本不匹配的问题
- 移除 shehuatang_undetected 中写死的 ChromeDriver 144 主版本\n- 增加本机 Chrome/Chromium 主版本自动检测逻辑\n- 增加 SessionNotCreatedException 场景下按真实浏览器版本自动重试的兜底处理
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import time
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import requests
|
||||
from io import BytesIO
|
||||
import undetected_chromedriver as uc
|
||||
@@ -11,6 +13,7 @@ import undetected_chromedriver as uc
|
||||
# except Exception:
|
||||
# pass
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.common.exceptions import SessionNotCreatedException
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
from bs4 import BeautifulSoup
|
||||
@@ -27,6 +30,87 @@ from PyPDF2 import PdfReader, PdfWriter
|
||||
from loguru import logger
|
||||
|
||||
|
||||
def _detect_local_chrome_major_version():
|
||||
"""检测本机 Chrome/Chromium 主版本号,尽量让 ChromeDriver 跟浏览器版本保持一致。"""
|
||||
# 这里按不同平台准备一组常见的 Chrome/Chromium 可执行文件位置。
|
||||
# 这样做的目的,是避免把 driver 版本写死后,浏览器一升级就再次出现版本不兼容。
|
||||
candidate_paths = []
|
||||
if os.name == 'nt':
|
||||
candidate_paths.extend([
|
||||
os.path.join(os.environ.get("PROGRAMFILES", ""), "Google", "Chrome", "Application", "chrome.exe"),
|
||||
os.path.join(os.environ.get("PROGRAMFILES(X86)", ""), "Google", "Chrome", "Application", "chrome.exe"),
|
||||
os.path.join(os.environ.get("LOCALAPPDATA", ""), "Google", "Chrome", "Application", "chrome.exe"),
|
||||
])
|
||||
candidate_paths.extend([
|
||||
shutil.which("chrome"),
|
||||
shutil.which("chrome.exe"),
|
||||
])
|
||||
else:
|
||||
candidate_paths.extend([
|
||||
shutil.which("google-chrome"),
|
||||
shutil.which("google-chrome-stable"),
|
||||
shutil.which("chromium"),
|
||||
shutil.which("chromium-browser"),
|
||||
shutil.which("chrome"),
|
||||
])
|
||||
|
||||
# 依次尝试执行 `--version`,只要拿到类似 `147.0.7727.116` 的版本串,就提取主版本号返回。
|
||||
for chrome_path in candidate_paths:
|
||||
if not chrome_path or not os.path.exists(chrome_path):
|
||||
continue
|
||||
|
||||
try:
|
||||
version_output = subprocess.check_output(
|
||||
[chrome_path, "--version"],
|
||||
stderr=subprocess.STDOUT,
|
||||
text=True,
|
||||
timeout=5,
|
||||
).strip()
|
||||
version_match = re.search(r"(\d+)\.", version_output)
|
||||
if version_match:
|
||||
return int(version_match.group(1))
|
||||
except Exception as exc:
|
||||
logger.debug(f"检测浏览器版本失败,路径={chrome_path},原因={exc}")
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def _extract_browser_major_version_from_error(error_message):
|
||||
"""从 Selenium/ChromeDriver 报错中提取当前浏览器主版本号,用于兜底重试。"""
|
||||
# ChromeDriver 版本不匹配时,报错里通常会带 `Current browser version is 147.x.x.x` 这样的信息。
|
||||
# 这里把这个版本号解析出来,便于在首次启动失败后自动切换到正确版本再试一次。
|
||||
version_match = re.search(r"Current browser version is (\d+)\.", error_message or "")
|
||||
if version_match:
|
||||
return int(version_match.group(1))
|
||||
return None
|
||||
|
||||
|
||||
def _create_chrome_driver(options):
|
||||
"""创建 undetected_chromedriver 实例,并在版本不匹配时自动兜底重试一次。"""
|
||||
detected_major_version = _detect_local_chrome_major_version()
|
||||
chrome_kwargs = {"options": options}
|
||||
|
||||
# 优先使用本机已安装浏览器的主版本号,避免继续使用过期的 driver 版本。
|
||||
if detected_major_version:
|
||||
chrome_kwargs["version_main"] = detected_major_version
|
||||
logger.info(f"检测到本机 Chrome/Chromium 主版本: {detected_major_version}")
|
||||
else:
|
||||
logger.warning("未检测到本机 Chrome/Chromium 版本,将交给 undetected_chromedriver 自动处理")
|
||||
|
||||
try:
|
||||
return uc.Chrome(**chrome_kwargs)
|
||||
except SessionNotCreatedException as exc:
|
||||
# 如果首次启动失败,并且报错里明确告诉了当前浏览器版本,就按真实版本重试一次。
|
||||
# 这样即便服务器上实际启动的是另一个 Chrome 可执行文件,也能自动修正 driver 版本。
|
||||
retry_major_version = _extract_browser_major_version_from_error(str(exc))
|
||||
if retry_major_version and retry_major_version != detected_major_version:
|
||||
logger.warning(
|
||||
f"ChromeDriver 与浏览器版本不匹配,准备按浏览器主版本 {retry_major_version} 自动重试一次"
|
||||
)
|
||||
return uc.Chrome(options=options, version_main=retry_major_version)
|
||||
raise
|
||||
|
||||
|
||||
def download_image(url, session):
|
||||
"""使用同步的 session 下载图片,确保 Cookie 一致"""
|
||||
try:
|
||||
@@ -78,10 +162,10 @@ def fetch_and_create_pdf(url):
|
||||
options.add_argument('--disable-logging')
|
||||
options.add_argument('--disable-dev-shm-usage')
|
||||
|
||||
# 创建driver实例
|
||||
# 让 undetected_chromedriver 自动检测浏览器版本并下载匹配的 ChromeDriver
|
||||
# 强制指定版本为144,以匹配服务器当前的 Chrome 版本
|
||||
driver = uc.Chrome(options=options, version_main=144)
|
||||
# 创建 driver 实例。
|
||||
# 这里不再把版本硬编码成 144,而是优先跟随本机 Chrome 版本;
|
||||
# 如果首次启动时仍然遇到版本不匹配,再从报错里解析真实版本自动重试。
|
||||
driver = _create_chrome_driver(options)
|
||||
|
||||
logger.info(f"正在访问: {url}")
|
||||
driver.get(url)
|
||||
|
||||
Reference in New Issue
Block a user