Add anti-collapse menu nav and fix multi-tab Strict Mode leakage
- Rewrite yunda_smart_menu_click to check each parent submenu's is-opened state before clicking (skip if already open), using XPath parent-child isolation to avoid collapsing accordion menus - Scope the expected/actual-arrival loading mask, #sum panel, and empty-record hint to #tab-1 and add .first to fix Playwright Strict Mode (5 elements found) leaks across multiple open tabs - Move _yunda_poll_and_download_tasks above yunda_actual_download for definition order Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
416
site_yunda.py
416
site_yunda.py
@@ -52,12 +52,40 @@ def _wait_and_get_frame_by_selector(page, selector, timeout_ms=20000):
|
|||||||
|
|
||||||
|
|
||||||
def yunda_smart_menu_click(page, menu_path):
|
def yunda_smart_menu_click(page, menu_path):
|
||||||
"""韵达排他性二级树形菜单智能展开器"""
|
"""
|
||||||
print(f">> 正在导航韵达菜单: {' -> '.join(menu_path)}")
|
韵达排他性多级树形菜单智能导航器(带防折叠状态断言机制)
|
||||||
|
采用 XPath 亲子轴绝对隔离技术,彻底斩断嵌套手风琴菜单的向下漏包干扰
|
||||||
|
"""
|
||||||
|
print(f">> 正在智能路由韵达菜单: {' -> '.join(menu_path)}")
|
||||||
|
|
||||||
for item in menu_path:
|
for item in menu_path:
|
||||||
locator = page.locator(".el-submenu__title, .el-menu-item", has_text=item).first
|
title_locator = page.locator(
|
||||||
locator.click()
|
f"xpath=//div[contains(@class, 'el-submenu__title') and .//span[normalize-space(.)='{item}']]"
|
||||||
page.wait_for_timeout(600)
|
).first
|
||||||
|
parent_li = page.locator(
|
||||||
|
f"xpath=//div[contains(@class, 'el-submenu__title') and .//span[normalize-space(.)='{item}']]/.."
|
||||||
|
).first
|
||||||
|
leaf_locator = page.locator(
|
||||||
|
f"xpath=//li[contains(@class, 'el-menu-item') and .//span[normalize-space(.)='{item}']]"
|
||||||
|
).first
|
||||||
|
|
||||||
|
if title_locator.is_visible():
|
||||||
|
current_class = parent_li.get_attribute("class") or ""
|
||||||
|
is_opened = "is-opened" in current_class
|
||||||
|
|
||||||
|
if not is_opened:
|
||||||
|
print(f" -> 探测到父菜单 [{item}] 当前处于【收起】状态,执行点击展开")
|
||||||
|
title_locator.click()
|
||||||
|
page.wait_for_timeout(500)
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
f" -> 探测到父菜单 [{item}] 当前已经处于【展开】状态,安全跳过点击(防折叠保护激活)"
|
||||||
|
)
|
||||||
|
|
||||||
|
elif leaf_locator.is_visible():
|
||||||
|
print(f" -> 成功对焦目标叶子节点 [{item}],直接执行跳转点击")
|
||||||
|
leaf_locator.click()
|
||||||
|
page.wait_for_timeout(1000)
|
||||||
|
|
||||||
|
|
||||||
def yunda_expected_download(page):
|
def yunda_expected_download(page):
|
||||||
@@ -125,27 +153,26 @@ def yunda_expected_download(page):
|
|||||||
calendar2.locator(".laydate-btns-confirm").click()
|
calendar2.locator(".laydate-btns-confirm").click()
|
||||||
page.wait_for_timeout(500)
|
page.wait_for_timeout(500)
|
||||||
|
|
||||||
# ====================================================================
|
# 3. 多维状态机静默加载校验
|
||||||
# 🛡️ 深度优化:三段式安全缓冲,彻底规避 DOM 旧状态穿透陷阱
|
|
||||||
# ====================================================================
|
|
||||||
print(">> 正在触发现场查询数据流...")
|
print(">> 正在触发现场查询数据流...")
|
||||||
ws_frame.locator("a.btn-success", has_text="查询").click()
|
ws_frame.locator("a.btn-success", has_text="查询").click()
|
||||||
|
|
||||||
# 阶段1:物理安全挂起,赋予浏览器触发渲染周期和 Ajax 的生命力
|
|
||||||
page.wait_for_timeout(800)
|
page.wait_for_timeout(800)
|
||||||
|
|
||||||
# 阶段2:精准抓取 Bootstrap Table 专属的加载遮罩层
|
# ====================================================================
|
||||||
|
# 🛡️ 核心修复:将 Loading 蒙层和数据断言限制在当前的 #tab-1 结界内部
|
||||||
|
# 彻底解决多标签页导致 Strict Mode (5 elements found) 的污染问题
|
||||||
|
# ====================================================================
|
||||||
loading_mask = ws_frame.locator(
|
loading_mask = ws_frame.locator(
|
||||||
".fixed-table-loading", has_text="正在努力地加载数据中"
|
"#tab-1 .fixed-table-loading", has_text="正在努力地加载数据中"
|
||||||
)
|
).first
|
||||||
if loading_mask.is_visible():
|
if loading_mask.is_visible():
|
||||||
print(" ⏳ 检测到专属数据加载罩,正在等待后端重载返回...")
|
print(" ⏳ 检测到专属数据加载罩,正在等待后端重载返回...")
|
||||||
loading_mask.wait_for(state="hidden", timeout=30000)
|
loading_mask.wait_for(state="hidden", timeout=30000)
|
||||||
|
|
||||||
page.wait_for_timeout(500) # DOM 重排完毕后再缓冲半秒
|
page.wait_for_timeout(500)
|
||||||
|
|
||||||
# 阶段3:进入绝对真实的终态判定世界
|
sum_panel = ws_frame.locator("#sum").first
|
||||||
sum_panel = ws_frame.locator("#sum")
|
|
||||||
has_data = False
|
has_data = False
|
||||||
|
|
||||||
if sum_panel.is_visible():
|
if sum_panel.is_visible():
|
||||||
@@ -158,9 +185,10 @@ def yunda_expected_download(page):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if not has_data:
|
if not has_data:
|
||||||
|
# 同样将空数据提示隔离在当前 tab 中
|
||||||
if ws_frame.locator(
|
if ws_frame.locator(
|
||||||
".no-records-found", has_text="没有找到匹配的记录"
|
"#tab-1 .no-records-found", has_text="没有找到匹配的记录"
|
||||||
).is_visible():
|
).first.is_visible():
|
||||||
print(
|
print(
|
||||||
" ⚠️ 确认为空数据环境:系统提示【没有找到匹配的记录】,正在执行复位净化..."
|
" ⚠️ 确认为空数据环境:系统提示【没有找到匹配的记录】,正在执行复位净化..."
|
||||||
)
|
)
|
||||||
@@ -184,7 +212,7 @@ def yunda_expected_download(page):
|
|||||||
current_row = ws_frame.locator("#exampleTable1 tbody tr[data-index]").nth(i)
|
current_row = ws_frame.locator("#exampleTable1 tbody tr[data-index]").nth(i)
|
||||||
|
|
||||||
raw_no = current_row.locator("td").nth(1).inner_text().strip()
|
raw_no = current_row.locator("td").nth(1).inner_text().strip()
|
||||||
print(f" -> 锁定提取单号: {raw_no}")
|
print(f" -> 锁定交接单号: {raw_no}")
|
||||||
|
|
||||||
current_row.dblclick()
|
current_row.dblclick()
|
||||||
|
|
||||||
@@ -201,7 +229,6 @@ def yunda_expected_download(page):
|
|||||||
export_frame.locator(".allRight").click()
|
export_frame.locator(".allRight").click()
|
||||||
page.wait_for_timeout(400)
|
page.wait_for_timeout(400)
|
||||||
|
|
||||||
# 智能重试容错状态机
|
|
||||||
print(" >> 正在建立后台离线任务...")
|
print(" >> 正在建立后台离线任务...")
|
||||||
task_success = False
|
task_success = False
|
||||||
for attempt in range(5):
|
for attempt in range(5):
|
||||||
@@ -263,180 +290,6 @@ def yunda_expected_download(page):
|
|||||||
print(f"\n❌ 任务执行过程中发生异常: {e}")
|
print(f"\n❌ 任务执行过程中发生异常: {e}")
|
||||||
|
|
||||||
|
|
||||||
def yunda_actual_download(page):
|
|
||||||
"""韵达:实到货物数据下载"""
|
|
||||||
print("\n▶ 开始执行【韵达 - 实到货物数据下载】任务...")
|
|
||||||
target_task_title = "扫描记录数据"
|
|
||||||
|
|
||||||
download_dir = os.path.join(os.getcwd(), "downloads")
|
|
||||||
if not os.path.exists(download_dir):
|
|
||||||
os.makedirs(download_dir)
|
|
||||||
|
|
||||||
export_times = []
|
|
||||||
|
|
||||||
try:
|
|
||||||
page.locator(".el-menu-item", has_text="首页").wait_for(
|
|
||||||
state="visible", timeout=15000
|
|
||||||
)
|
|
||||||
print("✅ 韵达工作台首页成功加载")
|
|
||||||
|
|
||||||
yunda_smart_menu_click(page, ["报表管理", "扫描记录查询"])
|
|
||||||
|
|
||||||
print(">> [雷达扫描] 正在跨域动态追踪【扫描记录查询】业务窗体...")
|
|
||||||
ws_frame = _wait_and_get_frame_by_selector(page, "#startDate")
|
|
||||||
|
|
||||||
ws_frame.locator(".no-records-found", has_text="没有找到匹配的记录").wait_for(
|
|
||||||
state="visible", timeout=15000
|
|
||||||
)
|
|
||||||
print("✅ 扫描记录查询工作区初始化完毕")
|
|
||||||
|
|
||||||
query_days = 1
|
|
||||||
try:
|
|
||||||
if os.path.exists("config.yaml"):
|
|
||||||
with open("config.yaml", "r", encoding="utf-8") as f:
|
|
||||||
config = yaml.safe_load(f) or {}
|
|
||||||
query_days = int(config.get("yunda", {}).get("query_days", 1))
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
today = datetime.now()
|
|
||||||
start_date = today - timedelta(days=(query_days - 1))
|
|
||||||
|
|
||||||
print(f">> 正在精准对焦实到时间区间: [近 {query_days} 天]")
|
|
||||||
|
|
||||||
print(" >> 正在设定起始时间...")
|
|
||||||
ws_frame.locator("#startDate").click()
|
|
||||||
page.wait_for_timeout(400)
|
|
||||||
box1 = ws_frame.locator("#laydate_box:visible").first
|
|
||||||
box1.locator(
|
|
||||||
f"td[y='{start_date.year}'][m='{start_date.month}'][d='{start_date.day}']"
|
|
||||||
).click()
|
|
||||||
page.wait_for_timeout(400)
|
|
||||||
|
|
||||||
print(" >> 正在设定截止时间...")
|
|
||||||
ws_frame.locator("#endDate").click()
|
|
||||||
page.wait_for_timeout(400)
|
|
||||||
box2 = ws_frame.locator("#laydate_box:visible").first
|
|
||||||
box2.locator(
|
|
||||||
f"td[y='{today.year}'][m='{today.month}'][d='{today.day}']"
|
|
||||||
).click()
|
|
||||||
page.wait_for_timeout(500)
|
|
||||||
|
|
||||||
print(" >> 正在变更扫描类型为【到件】...")
|
|
||||||
ws_frame.locator("#scanRecordTyp").select_option(value="03")
|
|
||||||
page.wait_for_timeout(500)
|
|
||||||
|
|
||||||
# ====================================================================
|
|
||||||
# 🛡️ 深度优化:实到数据的三段式安全缓冲判定
|
|
||||||
# ====================================================================
|
|
||||||
print(">> 正在触发现场查询数据流...")
|
|
||||||
ws_frame.locator('input[type="button"][value="查询"]').click()
|
|
||||||
|
|
||||||
page.wait_for_timeout(800)
|
|
||||||
|
|
||||||
loading_mask = ws_frame.locator(
|
|
||||||
".fixed-table-loading", has_text="正在努力地加载数据中"
|
|
||||||
)
|
|
||||||
if loading_mask.is_visible():
|
|
||||||
print(" ⏳ 检测到专属数据加载罩,正在等待后端重载返回...")
|
|
||||||
loading_mask.wait_for(state="hidden", timeout=30000)
|
|
||||||
|
|
||||||
page.wait_for_timeout(500)
|
|
||||||
|
|
||||||
pg_info = ws_frame.locator(".pagination-info")
|
|
||||||
has_records = False
|
|
||||||
|
|
||||||
if pg_info.is_visible():
|
|
||||||
info_text = pg_info.inner_text()
|
|
||||||
match_total = re.search(r"总共\s*(\d+)\s*条记录", info_text)
|
|
||||||
if match_total and int(match_total.group(1)) > 0:
|
|
||||||
has_records = True
|
|
||||||
print(
|
|
||||||
f" ✅ 深度断言:实到数据渲染完毕,总记录数: [{match_total.group(1)}] 条。"
|
|
||||||
)
|
|
||||||
|
|
||||||
if not has_records:
|
|
||||||
if ws_frame.locator(
|
|
||||||
".no-records-found", has_text="没有找到匹配的记录"
|
|
||||||
).is_visible():
|
|
||||||
print(
|
|
||||||
" ⚠️ 当前查询范围内确认为空数据:系统提示【没有找到匹配的记录】,终止并关闭环境。"
|
|
||||||
)
|
|
||||||
page.locator(".tags-view-item", has_text="扫描记录查询").locator(
|
|
||||||
".el-icon-close"
|
|
||||||
).click()
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
print(" ⚠️ 发生渲染异常,未找到数据也未找到空记录提示。安全收尾...")
|
|
||||||
page.locator(".tags-view-item", has_text="扫描记录查询").locator(
|
|
||||||
".el-icon-close"
|
|
||||||
).click()
|
|
||||||
return
|
|
||||||
|
|
||||||
# 5. 执行导出流
|
|
||||||
print(">> 正在发起【导出】申请指令...")
|
|
||||||
ws_frame.locator('input[type="button"][id="export"]').click()
|
|
||||||
|
|
||||||
ws_frame.locator(".layui-layer-title", has_text="数据导出").wait_for(
|
|
||||||
state="visible", timeout=15000
|
|
||||||
)
|
|
||||||
export_frame = ws_frame.frame_locator('iframe[name="myFrame"]')
|
|
||||||
|
|
||||||
export_frame.locator(".allRight").click()
|
|
||||||
page.wait_for_timeout(400)
|
|
||||||
|
|
||||||
print(" >> 正在建立后台离线任务...")
|
|
||||||
task_success = False
|
|
||||||
for attempt in range(5):
|
|
||||||
export_frame.locator("#submitbutton", has_text="导出数据").click()
|
|
||||||
confirm_link = export_frame.get_by_role("link", name="确定")
|
|
||||||
try:
|
|
||||||
confirm_link.wait_for(state="visible", timeout=6000)
|
|
||||||
if export_frame.get_by_text("导出任务建立成功").is_visible():
|
|
||||||
print(" ✅ 判定通过:成功捕获到【导出任务建立成功】特征!")
|
|
||||||
confirm_link.click()
|
|
||||||
task_success = True
|
|
||||||
break
|
|
||||||
elif export_frame.get_by_text("请选择格式相应的导出字段").is_visible():
|
|
||||||
print(" ⚠️ 警告:检测到字段未全选,执行强补点击...")
|
|
||||||
confirm_link.click()
|
|
||||||
page.wait_for_timeout(500)
|
|
||||||
export_frame.locator(".allRight").click()
|
|
||||||
page.wait_for_timeout(500)
|
|
||||||
else:
|
|
||||||
confirm_link.click()
|
|
||||||
page.wait_for_timeout(1000)
|
|
||||||
except Exception:
|
|
||||||
page.wait_for_timeout(1000)
|
|
||||||
|
|
||||||
if not task_success:
|
|
||||||
raise RuntimeError(
|
|
||||||
"致命异常:连续 5 次尝试均无法成功建立实到数据离线任务。"
|
|
||||||
)
|
|
||||||
|
|
||||||
ws_frame.locator(".layui-layer-close1").click()
|
|
||||||
page.wait_for_timeout(500)
|
|
||||||
export_times.append(datetime.now())
|
|
||||||
|
|
||||||
print(">> 📤 任务提交流闭环,正在执行【扫描记录查询】工作台销毁...")
|
|
||||||
page.locator(".tags-view-item", has_text="扫描记录查询").locator(
|
|
||||||
".el-icon-close"
|
|
||||||
).click()
|
|
||||||
page.wait_for_timeout(500)
|
|
||||||
|
|
||||||
# 6. 收割下载
|
|
||||||
_yunda_poll_and_download_tasks(
|
|
||||||
page,
|
|
||||||
export_times,
|
|
||||||
target_task_title,
|
|
||||||
download_dir,
|
|
||||||
"韵达-实到货物数据.xlsx",
|
|
||||||
)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"\n❌ 任务执行过程中发生异常: {e}")
|
|
||||||
|
|
||||||
|
|
||||||
def _yunda_poll_and_download_tasks(
|
def _yunda_poll_and_download_tasks(
|
||||||
page, export_times, target_task_title, download_dir, final_filename
|
page, export_times, target_task_title, download_dir, final_filename
|
||||||
):
|
):
|
||||||
@@ -445,6 +298,7 @@ def _yunda_poll_and_download_tasks(
|
|||||||
yunda_smart_menu_click(page, ["基础数据", "导出服务"])
|
yunda_smart_menu_click(page, ["基础数据", "导出服务"])
|
||||||
|
|
||||||
export_ws_frame = page.frame_locator("section iframe")
|
export_ws_frame = page.frame_locator("section iframe")
|
||||||
|
|
||||||
export_ws_frame.get_by_role("cell", name="模块名称", exact=True).wait_for(
|
export_ws_frame.get_by_role("cell", name="模块名称", exact=True).wait_for(
|
||||||
state="visible", timeout=15000
|
state="visible", timeout=15000
|
||||||
)
|
)
|
||||||
@@ -531,7 +385,7 @@ def _yunda_poll_and_download_tasks(
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f" ❌ 文件流接收失败: {e}")
|
print(f" ❌ 文件流接收失败: {e}")
|
||||||
|
|
||||||
# 环境清理
|
# 环境清理:彻底关闭“导出服务”Tab
|
||||||
print(">> 📥 【导出服务】数据提取链闭环,正在执行当前 Tab 窗口销毁...")
|
print(">> 📥 【导出服务】数据提取链闭环,正在执行当前 Tab 窗口销毁...")
|
||||||
try:
|
try:
|
||||||
page.locator(".tags-view-item", has_text="导出服务").locator(
|
page.locator(".tags-view-item", has_text="导出服务").locator(
|
||||||
@@ -541,7 +395,7 @@ def _yunda_poll_and_download_tasks(
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# 合并扁平数据集
|
# 9. 合并扁平数据集
|
||||||
if downloaded_files:
|
if downloaded_files:
|
||||||
print("\n>> 🧪 正在启动离线数据清洗与高能扁平合并流...")
|
print("\n>> 🧪 正在启动离线数据清洗与高能扁平合并流...")
|
||||||
all_dfs = []
|
all_dfs = []
|
||||||
@@ -565,3 +419,175 @@ def _yunda_poll_and_download_tasks(
|
|||||||
for file_path in downloaded_files:
|
for file_path in downloaded_files:
|
||||||
os.remove(file_path)
|
os.remove(file_path)
|
||||||
print(" ✅ 临时缓存阵列已无缝净化。")
|
print(" ✅ 临时缓存阵列已无缝净化。")
|
||||||
|
|
||||||
|
|
||||||
|
def yunda_actual_download(page):
|
||||||
|
"""韵达:实到货物数据下载"""
|
||||||
|
print("\n▶ 开始执行【韵达 - 实到货物数据下载】任务...")
|
||||||
|
target_task_title = "扫描记录数据"
|
||||||
|
|
||||||
|
download_dir = os.path.join(os.getcwd(), "downloads")
|
||||||
|
if not os.path.exists(download_dir):
|
||||||
|
os.makedirs(download_dir)
|
||||||
|
|
||||||
|
export_times = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
page.locator(".el-menu-item", has_text="首页").wait_for(
|
||||||
|
state="visible", timeout=15000
|
||||||
|
)
|
||||||
|
print("✅ 韵达工作台首页成功加载")
|
||||||
|
|
||||||
|
yunda_smart_menu_click(page, ["报表管理", "扫描记录查询"])
|
||||||
|
|
||||||
|
print(">> [雷达扫描] 正在跨域动态追踪【扫描记录查询】业务窗体...")
|
||||||
|
ws_frame = _wait_and_get_frame_by_selector(page, "#startDate")
|
||||||
|
|
||||||
|
ws_frame.locator(
|
||||||
|
".no-records-found", has_text="没有找到匹配的记录"
|
||||||
|
).first.wait_for(state="visible", timeout=15000)
|
||||||
|
print("✅ 扫描记录查询工作区初始化完毕")
|
||||||
|
|
||||||
|
query_days = 1
|
||||||
|
try:
|
||||||
|
if os.path.exists("config.yaml"):
|
||||||
|
with open("config.yaml", "r", encoding="utf-8") as f:
|
||||||
|
config = yaml.safe_load(f) or {}
|
||||||
|
query_days = int(config.get("yunda", {}).get("query_days", 1))
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
today = datetime.now()
|
||||||
|
start_date = today - timedelta(days=(query_days - 1))
|
||||||
|
|
||||||
|
print(f">> 正在精准对焦实到时间区间: [近 {query_days} 天]")
|
||||||
|
|
||||||
|
print(" >> 正在设定起始时间...")
|
||||||
|
ws_frame.locator("#startDate").click()
|
||||||
|
page.wait_for_timeout(400)
|
||||||
|
box1 = ws_frame.locator("#laydate_box:visible").first
|
||||||
|
box1.locator(
|
||||||
|
f"td[y='{start_date.year}'][m='{start_date.month}'][d='{start_date.day}']"
|
||||||
|
).click()
|
||||||
|
page.wait_for_timeout(400)
|
||||||
|
|
||||||
|
print(" >> 正在设定截止时间...")
|
||||||
|
ws_frame.locator("#endDate").click()
|
||||||
|
page.wait_for_timeout(400)
|
||||||
|
box2 = ws_frame.locator("#laydate_box:visible").first
|
||||||
|
box2.locator(
|
||||||
|
f"td[y='{today.year}'][m='{today.month}'][d='{today.day}']"
|
||||||
|
).click()
|
||||||
|
page.wait_for_timeout(500)
|
||||||
|
|
||||||
|
print(" >> 正在变更扫描类型为【到件】...")
|
||||||
|
ws_frame.locator("#scanRecordTyp").select_option(value="03")
|
||||||
|
page.wait_for_timeout(500)
|
||||||
|
|
||||||
|
print(">> 正在触发现场查询数据流...")
|
||||||
|
ws_frame.locator('input[type="button"][value="查询"]').click()
|
||||||
|
|
||||||
|
page.wait_for_timeout(800)
|
||||||
|
|
||||||
|
# 同样在这里加上防 strict mode 穿透的 first 隔离
|
||||||
|
loading_mask = ws_frame.locator(
|
||||||
|
".fixed-table-loading", has_text="正在努力地加载数据中"
|
||||||
|
).first
|
||||||
|
if loading_mask.is_visible():
|
||||||
|
print(" ⏳ 检测到专属数据加载罩,正在等待后端重载返回...")
|
||||||
|
loading_mask.wait_for(state="hidden", timeout=30000)
|
||||||
|
|
||||||
|
page.wait_for_timeout(500)
|
||||||
|
|
||||||
|
pg_info = ws_frame.locator(".pagination-info").first
|
||||||
|
has_records = False
|
||||||
|
|
||||||
|
if pg_info.is_visible():
|
||||||
|
info_text = pg_info.inner_text()
|
||||||
|
match_total = re.search(r"总共\s*(\d+)\s*条记录", info_text)
|
||||||
|
if match_total and int(match_total.group(1)) > 0:
|
||||||
|
has_records = True
|
||||||
|
print(
|
||||||
|
f" ✅ 深度断言:实到数据渲染完毕,总记录数: [{match_total.group(1)}] 条。"
|
||||||
|
)
|
||||||
|
|
||||||
|
if not has_records:
|
||||||
|
if ws_frame.locator(
|
||||||
|
".no-records-found", has_text="没有找到匹配的记录"
|
||||||
|
).first.is_visible():
|
||||||
|
print(
|
||||||
|
" ⚠️ 当前查询范围内确认为空数据:系统提示【没有找到匹配的记录】,终止并关闭环境。"
|
||||||
|
)
|
||||||
|
page.locator(".tags-view-item", has_text="扫描记录查询").locator(
|
||||||
|
".el-icon-close"
|
||||||
|
).click()
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
print(" ⚠️ 发生渲染异常,未找到数据也未找到空记录提示。安全收尾...")
|
||||||
|
page.locator(".tags-view-item", has_text="扫描记录查询").locator(
|
||||||
|
".el-icon-close"
|
||||||
|
).click()
|
||||||
|
return
|
||||||
|
|
||||||
|
# 5. 执行导出流
|
||||||
|
print(">> 正在发起【导出】申请指令...")
|
||||||
|
ws_frame.locator('input[type="button"][id="export"]').click()
|
||||||
|
|
||||||
|
ws_frame.locator(".layui-layer-title", has_text="数据导出").wait_for(
|
||||||
|
state="visible", timeout=15000
|
||||||
|
)
|
||||||
|
export_frame = ws_frame.frame_locator('iframe[name="myFrame"]')
|
||||||
|
|
||||||
|
export_frame.locator(".allRight").click()
|
||||||
|
page.wait_for_timeout(400)
|
||||||
|
|
||||||
|
print(" >> 正在建立后台离线任务...")
|
||||||
|
task_success = False
|
||||||
|
for attempt in range(5):
|
||||||
|
export_frame.locator("#submitbutton", has_text="导出数据").click()
|
||||||
|
confirm_link = export_frame.get_by_role("link", name="确定")
|
||||||
|
try:
|
||||||
|
confirm_link.wait_for(state="visible", timeout=6000)
|
||||||
|
if export_frame.get_by_text("导出任务建立成功").is_visible():
|
||||||
|
print(" ✅ 判定通过:成功捕获到【导出任务建立成功】特征!")
|
||||||
|
confirm_link.click()
|
||||||
|
task_success = True
|
||||||
|
break
|
||||||
|
elif export_frame.get_by_text("请选择格式相应的导出字段").is_visible():
|
||||||
|
print(" ⚠️ 警告:检测到字段未全选,执行强补点击...")
|
||||||
|
confirm_link.click()
|
||||||
|
page.wait_for_timeout(500)
|
||||||
|
export_frame.locator(".allRight").click()
|
||||||
|
page.wait_for_timeout(500)
|
||||||
|
else:
|
||||||
|
confirm_link.click()
|
||||||
|
page.wait_for_timeout(1000)
|
||||||
|
except Exception:
|
||||||
|
page.wait_for_timeout(1000)
|
||||||
|
|
||||||
|
if not task_success:
|
||||||
|
raise RuntimeError(
|
||||||
|
"致命异常:连续 5 次尝试均无法成功建立实到数据离线任务。"
|
||||||
|
)
|
||||||
|
|
||||||
|
ws_frame.locator(".layui-layer-close1").click()
|
||||||
|
page.wait_for_timeout(500)
|
||||||
|
export_times.append(datetime.now())
|
||||||
|
|
||||||
|
print(">> 📤 任务提交流闭环,正在执行【扫描记录查询】工作台销毁...")
|
||||||
|
page.locator(".tags-view-item", has_text="扫描记录查询").locator(
|
||||||
|
".el-icon-close"
|
||||||
|
).click()
|
||||||
|
page.wait_for_timeout(500)
|
||||||
|
|
||||||
|
# 6. 收割下载
|
||||||
|
_yunda_poll_and_download_tasks(
|
||||||
|
page,
|
||||||
|
export_times,
|
||||||
|
target_task_title,
|
||||||
|
download_dir,
|
||||||
|
"韵达-实到货物数据.xlsx",
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"\n❌ 任务执行过程中发生异常: {e}")
|
||||||
|
|||||||
Reference in New Issue
Block a user