fix: 自动绕过 SSL 证书过期的拦截页面

导出下载链接的 SSL 证书过期,Chrome 会弹出"您的连接不是私密连接"页面
阻止下载。新增 _bypass_ssl_interstitial() 方法,自动点击「高级」→「继续前往」
绕过 SSL 拦截,并在下载事件超时后做二次 SSL 绕过尝试。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-17 18:50:18 +08:00
parent e95a1723e5
commit 70f293db96
+86 -2
View File
@@ -196,13 +196,16 @@ class SecsionDownloader:
# 点击导出报表并捕获下载 # 点击导出报表并捕获下载
logger.info("点击导出报表...") logger.info("点击导出报表...")
download_timeout = 120000 # 2 分钟 download_timeout = 120000 # 2 分钟,给 SSL 绕过留足时间
try: try:
async with page.expect_download(timeout=download_timeout) as download_info: async with page.expect_download(timeout=download_timeout) as download_info:
await export_btn.click() await export_btn.click()
logger.info("等待文件下载中...") logger.info("等待文件下载中...")
# 点击导出后,可能弹出 SSL 证书过期拦截页面
await self._bypass_ssl_interstitial(page)
download = await download_info.value download = await download_info.value
filename = download.suggested_filename filename = download.suggested_filename
save_path = os.path.join(self.download_dir, filename) save_path = os.path.join(self.download_dir, filename)
@@ -211,8 +214,25 @@ class SecsionDownloader:
return save_path return save_path
except Exception as download_err: except Exception as download_err:
# Playwright download 事件未触发,尝试文件系统兜底检测 # Playwright download 事件未触发,尝试 SSL 绕过后再等
logger.warning(f"Playwright 下载事件捕获失败: {download_err}") logger.warning(f"Playwright 下载事件捕获失败: {download_err}")
# 二次尝试:可能 SSL 页面刚出现,再尝试绕过
bypassed = await self._bypass_ssl_interstitial(page)
if bypassed:
logger.info("SSL 拦截已绕过,等待下载...")
try:
async with page.expect_download(timeout=30000) as dl_info:
pass
download = await dl_info.value
filename = download.suggested_filename
save_path = os.path.join(self.download_dir, filename)
await download.save_as(save_path)
logger.info(f"SSL 绕过后下载成功: {save_path}")
return save_path
except Exception:
logger.warning("SSL 绕过后仍未触发下载事件")
logger.info("尝试文件系统兜底检测...") logger.info("尝试文件系统兜底检测...")
# 等待一小段时间让可能的下载完成 # 等待一小段时间让可能的下载完成
@@ -290,6 +310,70 @@ class SecsionDownloader:
# 过滤掉临时文件和调试截图 # 过滤掉临时文件和调试截图
return [f for f in new_files if not f.endswith(('.crdownload', '.tmp')) and not f.startswith('debug_')] return [f for f in new_files if not f.endswith(('.crdownload', '.tmp')) and not f.startswith('debug_')]
async def _bypass_ssl_interstitial(self, page):
"""
绕过 Chrome SSL 证书错误拦截页面
secsion.com 的导出下载链接 SSL 证书过期,Chrome 会弹
"您的连接不是私密连接" 警告页。点 "高级""继续前往"
Returns:
bool: 是否成功绕过(或无需绕过)
"""
try:
await page.wait_for_timeout(2000)
current_url = page.url
logger.debug(f"SSL 绕过检查: 当前 URL={current_url}")
# 检查是否在 SSL 错误页面
is_ssl_error_page = (
'chrome-error' in current_url or
'security' in current_url.lower() or
await page.evaluate(
"""() => {
return document.querySelector('#details-button') !== null ||
document.querySelector('#proceed-link') !== null ||
document.body?.innerText?.includes('您的连接不是私密连接') ||
document.body?.innerText?.includes('NET::ERR_CERT');
}"""
)
)
if not is_ssl_error_page:
return False
logger.info("检测到 SSL 证书错误拦截页面,尝试绕过...")
# 点击 "高级" 按钮展开详情
details_btn = page.locator('#details-button')
if await details_btn.count() > 0:
await details_btn.click()
await page.wait_for_timeout(500)
logger.info("已点击「高级」")
# 点击 "继续前往 xxx(不安全)"
proceed_link = page.locator('#proceed-link')
if await proceed_link.count() > 0:
await proceed_link.click()
await page.wait_for_timeout(2000)
logger.info("已点击「继续前往(不安全)」,SSL 绕过成功")
return True
# 备选:中文按钮文字
unsafe_link = page.get_by_text('继续前往')
if await unsafe_link.count() > 0:
await unsafe_link.click()
await page.wait_for_timeout(2000)
logger.info("已点击「继续前往」,SSL 绕过成功")
return True
logger.warning("SSL 拦截页面检测到但未找到绕过按钮")
return False
except Exception as e:
logger.warning(f"SSL 绕过检查异常: {e}")
return False
async def _set_date(self, page, input_box, date_str): async def _set_date(self, page, input_box, date_str):
""" """
设置 TDesign 日期选择器的值 设置 TDesign 日期选择器的值