Cleanup: Removed screenshots and unnecessary reference files

This commit is contained in:
2026-04-18 17:31:21 +08:00
parent e15ae99db8
commit bc163f372b
2 changed files with 1 additions and 230 deletions
+1 -11
View File
@@ -60,10 +60,7 @@ class ReportAutomation:
except Exception as e: except Exception as e:
logger.error(f"发生错误: {str(e)}") logger.error(f"发生错误: {str(e)}")
# 截图以供调试
await page.screenshot(path="error_screenshot.png")
finally: finally:
await asyncio.sleep(5) # 留出观察时间
await browser.close() await browser.close()
async def login_secsion(self, page): async def login_secsion(self, page):
@@ -157,14 +154,9 @@ class ReportAutomation:
# 等待数据请求完成 # 等待数据请求完成
logger.info("等待数据请求完成...") logger.info("等待数据请求完成...")
await asyncio.sleep(2) await asyncio.sleep(2)
# 截图确认日期设置后的状态
logger.info("保存日期设置确认截图: date_setting_check.png")
await page.screenshot(path="date_setting_check.png")
except Exception as e: except Exception as e:
logger.error(f"日期选择逻辑执行失败: {str(e)}") logger.error(f"日期选择逻辑执行失败: {str(e)}")
await page.screenshot(path="date_error.png")
raise e raise e
# 点击导出报表并捕获下载 # 点击导出报表并捕获下载
@@ -211,9 +203,7 @@ class ReportAutomation:
logger.info("上传成功,正在处理数据...") logger.info("上传成功,正在处理数据...")
except Exception: except Exception:
logger.warning("未检测到 '上传并分析' 文本,可能已完成或文本不同") logger.warning("未检测到 '上传并分析' 文本,可能已完成或文本不同")
# 截图保存结果
await page.screenshot(path="upload_result.png")
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser(description='报表自动化导出上传工具') parser = argparse.ArgumentParser(description='报表自动化导出上传工具')
-219
View File
@@ -1,219 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
secsion.com 报表导出脚本(给 OpenClaw/自动化调用)
功能:
1) 登录 https://secsion.com:8000/
2) 进入 /commodityStatistics
3) 选择开始/结束日期
4) 点击“导出报表”,保存 xlsx 到本地目录
推荐使用 Playwright(更稳定地处理下载与证书忽略)。
"""
from __future__ import annotations
import argparse
import os
import sys
import time
from dataclasses import dataclass
from datetime import datetime
from pathlib import Path
from typing import Optional
from urllib.parse import urlparse
import requests
from playwright.sync_api import TimeoutError as PWTimeoutError
from playwright.sync_api import sync_playwright
@dataclass(frozen=True)
class Config:
base_url: str = "https://secsion.com:8000"
login_url: str = "https://secsion.com:8000/login?redirect=%252Fhomepage"
report_url: str = "https://secsion.com:8000/commodityStatistics"
role: str = "店铺"
username: str = ""
password: str = ""
def _parse_date(s: str) -> str:
# 统一校验并格式化为 YYYY-MM-DD
dt = datetime.strptime(s, "%Y-%m-%d")
return dt.strftime("%Y-%m-%d")
def _ensure_dir(p: Path) -> None:
p.mkdir(parents=True, exist_ok=True)
def _download_via_requests(url: str, out_dir: Path, filename: Optional[str] = None) -> Path:
# 导出链接常见为 https://secsion.com:8082/xxx.xlsx(可能证书不受信任)
# verify=False 用于忽略证书(等价于浏览器“继续前往”)
resp = requests.get(url, stream=True, timeout=120, verify=False)
resp.raise_for_status()
if not filename:
path = urlparse(url).path
filename = Path(path).name or f"commodity_export_{int(time.time())}.xlsx"
if not filename.lower().endswith(".xlsx"):
filename += ".xlsx"
save_path = out_dir / filename
with open(save_path, "wb") as f:
for chunk in resp.iter_content(chunk_size=1024 * 128):
if chunk:
f.write(chunk)
return save_path
def export_report(
*,
cfg: Config,
start_date: str,
end_date: str,
out_dir: Path,
headless: bool = True,
timeout_ms: int = 30_000,
) -> Path:
_ensure_dir(out_dir)
with sync_playwright() as p:
browser = p.chromium.launch(headless=headless)
context = browser.new_context(ignore_https_errors=True, accept_downloads=True)
page = context.new_page()
# 1) 打开登录页
page.goto(cfg.login_url, timeout=timeout_ms, wait_until="domcontentloaded")
# 2) 选择角色(默认“店铺”)
# 页面是 radio,按可见文本定位
page.get_by_role("radio", name=cfg.role).check()
# 3) 输入账号密码
page.get_by_role("textbox", name="请输入用户名").fill(cfg.username)
page.get_by_role("textbox", name="请输入密码").fill(cfg.password)
# 4) 登录
page.get_by_role("button", name="登 录").click()
# 等待跳转(不强依赖具体 URL,避免页面改版)
page.wait_for_load_state("networkidle", timeout=timeout_ms)
# 5) 进入报表页
page.goto(cfg.report_url, timeout=timeout_ms, wait_until="domcontentloaded")
page.wait_for_load_state("networkidle", timeout=timeout_ms)
# 6) 设置日期范围
# 两个日期输入框都叫“请选择日期”,用 nth 区分
start_input = page.get_by_role("textbox", name="请选择日期").nth(0)
end_input = page.get_by_role("textbox", name="请选择日期").nth(1)
def set_date(input_box, date_str: str) -> None:
# 先尝试直接填值 + Enter(部分组件会生效)
input_box.click()
input_box.fill(date_str)
input_box.press("Enter")
page.wait_for_timeout(200)
# 若没有生效,则打开日历点击“日”单元格(更稳)
val = input_box.input_value()
if val != date_str:
input_box.click()
day = str(int(date_str.split("-")[2]))
# 月份不一致时这里可能需要先切换月份;多数情况下导出同月数据足够。
page.get_by_role("cell", name=day).click()
page.wait_for_timeout(200)
set_date(start_input, start_date)
set_date(end_input, end_date)
# 7) 导出
export_btn = page.get_by_role("button", name="导出报表")
# 尝试走 Playwright 的下载通道(最优)
try:
with page.expect_download(timeout=20_000) as d:
export_btn.click()
download = d.value
suggested = download.suggested_filename or f"commodity_export_{start_date}_{end_date}.xlsx"
if not suggested.lower().endswith(".xlsx"):
suggested += ".xlsx"
save_path = out_dir / suggested
download.save_as(str(save_path))
browser.close()
return save_path
except PWTimeoutError:
# 回退:有些情况下会打开一个新地址(.xlsx 链接)但不触发下载事件
export_btn.click()
page.wait_for_timeout(1500)
xlsx_url = None
for pg in context.pages:
if pg.url.lower().endswith(".xlsx"):
xlsx_url = pg.url
break
if not xlsx_url and page.url.lower().endswith(".xlsx"):
xlsx_url = page.url
if not xlsx_url:
browser.close()
raise RuntimeError("未捕获到导出的 xlsx 链接;请把页面导出后的实际跳转 URL 发我,我再适配。")
# 直链下载(忽略证书)
filename = f"commodity_export_{start_date}_{end_date}.xlsx"
save_path = _download_via_requests(xlsx_url, out_dir=out_dir, filename=filename)
browser.close()
return save_path
def main(argv: list[str]) -> int:
parser = argparse.ArgumentParser(
description="secsion.com 报表导出(支持某一天/时间段)。",
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
parser.add_argument("--start", required=False, help="开始日期 YYYY-MM-DD(若仅导出某一天,可只填 start)")
parser.add_argument("--end", required=False, help="结束日期 YYYY-MM-DD(缺省时与 start 相同)")
parser.add_argument("--out", default="./downloads", help="导出文件保存目录")
parser.add_argument("--headless", action="store_true", help="无头模式运行(CI/机器人推荐)")
parser.add_argument("--show", action="store_true", help="显示浏览器窗口(调试用,优先级高于 --headless)")
parser.add_argument("--role", default="店铺", help="登录角色:店铺编码/管理员/店铺/业务员")
parser.add_argument("--username", default=os.getenv("SECSION_USERNAME", ""), help="账号(也可用环境变量 SECSION_USERNAME")
parser.add_argument("--password", default=os.getenv("SECSION_PASSWORD", ""), help="密码(也可用环境变量 SECSION_PASSWORD")
args = parser.parse_args(argv)
# 交互式兜底(给 OpenClaw 也可以直接传参,不走交互)
start = args.start or input("请输入开始日期(YYYY-MM-DD): ").strip()
end = args.end or input("请输入结束日期(YYYY-MM-DD,回车=同开始日期): ").strip() or start
try:
start = _parse_date(start)
end = _parse_date(end)
except ValueError:
print("日期格式错误,请使用 YYYY-MM-DD,例如 2026-04-15", file=sys.stderr)
return 2
if not args.username or not args.password:
print("缺少账号或密码:请传 --username/--password 或设置环境变量 SECSION_USERNAME/SECSION_PASSWORD", file=sys.stderr)
return 2
cfg = Config(role=args.role, username=args.username, password=args.password)
out_dir = Path(args.out).expanduser().resolve()
headless = False if args.show else bool(args.headless)
try:
saved = export_report(cfg=cfg, start_date=start, end_date=end, out_dir=out_dir, headless=headless)
except Exception as e:
print(f"导出失败:{e}", file=sys.stderr)
return 1
print(str(saved))
return 0
if __name__ == "__main__":
raise SystemExit(main(sys.argv[1:]))