This commit is contained in:
HuangHai
2026-01-15 10:06:08 +08:00
parent 98e890a693
commit ccac3e889c
13 changed files with 35 additions and 20 deletions

View File

@@ -2,7 +2,7 @@
# 采集配置 # 采集配置
SCROLL_DISTANCE_RATIO = 0.3 SCROLL_DISTANCE_RATIO = 0.3
MAX_STATIONS_COUNT = 3 MAX_STATIONS_COUNT = 30
FIRST_RUN_ONLY_ONE_STATION = False FIRST_RUN_ONLY_ONE_STATION = False
# 场站去重过期时间(秒),在此时间内重复出现的场站不会再次点击进入详情页 # 场站去重过期时间(秒),在此时间内重复出现的场站不会再次点击进入详情页
REDIS_STATION_EXPIRE = 120 REDIS_STATION_EXPIRE = 120

View File

@@ -11,7 +11,7 @@ from typing import Any, Dict, List, Optional, Set
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s") logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if project_root not in sys.path: if project_root not in sys.path:
sys.path.append(project_root) sys.path.append(project_root)
@@ -187,7 +187,7 @@ class DorisExcelExporter:
if getattr(self.db, "engine", None): if getattr(self.db, "engine", None):
await self.db.engine.dispose() await self.db.engine.dispose()
async def fetch_current_station_rows(self) -> List[Dict[str, Any]]: async def fetch_current_station_rows(self, operator: str) -> List[Dict[str, Any]]:
sql = """ sql = """
SELECT SELECT
p.station_hash, p.station_hash,
@@ -210,10 +210,10 @@ class DorisExcelExporter:
ON p.station_hash = s.station_hash AND s.is_current = 1 ON p.station_hash = s.station_hash AND s.is_current = 1
LEFT JOIN t_station_price_schedule_scd pr LEFT JOIN t_station_price_schedule_scd pr
ON p.station_hash = pr.station_hash AND pr.is_current = 1 ON p.station_hash = pr.station_hash AND pr.is_current = 1
WHERE p.is_current = 1 WHERE p.is_current = 1 AND p.operator = :operator
ORDER BY p.station_name ORDER BY p.station_name
""" """
return await self.db.find(sql) return await self.db.find(sql, {"operator": operator})
def _build_station_sheet(ws, row: Dict[str, Any]): def _build_station_sheet(ws, row: Dict[str, Any]):
@@ -409,12 +409,12 @@ def _build_station_sheet(ws, row: Dict[str, Any]):
_set_column_widths(ws, {1: 20, 2: 20, 3: 16, 4: 16, 5: 16, 6: 25}) _set_column_widths(ws, {1: 20, 2: 20, 3: 16, 4: 16, 5: 16, 6: 25})
def _build_summary_sheet(ws, rows: List[Dict[str, Any]]): def _build_summary_sheet(ws, rows: List[Dict[str, Any]], operator: str):
ws.title = "场站总览" ws.title = "场站总览"
ws.sheet_properties.tabColor = "4472C4" # Tab color matches theme ws.sheet_properties.tabColor = "4472C4" # Tab color matches theme
# Row 1: Main Title # Row 1: Main Title
title_cell = ws.cell(row=1, column=1, value="新电途充电场站数据总览") title_cell = ws.cell(row=1, column=1, value=f"{operator}充电场站数据总览")
title_cell.font = TITLE_FONT title_cell.font = TITLE_FONT
title_cell.alignment = Alignment(horizontal="center", vertical="center") title_cell.alignment = Alignment(horizontal="center", vertical="center")
ws.merge_cells(start_row=1, start_column=1, end_row=1, end_column=10) ws.merge_cells(start_row=1, start_column=1, end_row=1, end_column=10)
@@ -448,11 +448,11 @@ def _build_summary_sheet(ws, rows: List[Dict[str, Any]]):
ws.freeze_panes = ws["A3"] ws.freeze_panes = ws["A3"]
async def export_excel(output_path: str, *, limit: Optional[int] = None) -> str: async def export_excel(operator: str, output_path: str, *, limit: Optional[int] = None) -> str:
exporter = DorisExcelExporter(db_url=DB_URL) exporter = DorisExcelExporter(db_url=DB_URL)
await exporter.init() await exporter.init()
try: try:
rows = await exporter.fetch_current_station_rows() rows = await exporter.fetch_current_station_rows(operator)
finally: finally:
await exporter.close() await exporter.close()
@@ -464,13 +464,13 @@ async def export_excel(output_path: str, *, limit: Optional[int] = None) -> str:
if not rows: if not rows:
ws = wb.active ws = wb.active
ws.title = "无数据" ws.title = "无数据"
ws.cell(row=1, column=1, value="未查询到任何场站数据") ws.cell(row=1, column=1, value=f"未查询到 {operator} 的任何场站数据")
wb.save(output_path) wb.save(output_path)
return output_path return output_path
# 1. 创建总览页 # 1. 创建总览页
summary_ws = wb.active summary_ws = wb.active
_build_summary_sheet(summary_ws, rows) _build_summary_sheet(summary_ws, rows, operator)
# 2. 为每个场站创建独立页 # 2. 为每个场站创建独立页
existing_titles: Set[str] = {"场站总览"} existing_titles: Set[str] = {"场站总览"}
@@ -487,18 +487,33 @@ async def main():
# 配置:默认导出所有数据,如果需要测试少量数据,可以将 None 改为数字,如 10 # 配置:默认导出所有数据,如果需要测试少量数据,可以将 None 改为数字,如 10
limit = None limit = None
# 构建默认输出路径 # 供应商列表
operators = ["新电途", "特来电", "驿来特", "艾特吉易充"]
# 构建默认输出目录
ts = datetime.now().strftime("%Y%m%d_%H%M%S") ts = datetime.now().strftime("%Y%m%d_%H%M%S")
output_filename = f"./Excel/station_export_{ts}.xlsx" export_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Excel", ts)
output_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), output_filename) if not os.path.exists(export_dir):
os.makedirs(export_dir, exist_ok=True)
logger.info(f"开始导出 Excel...") logger.info(f"开始批量导出 Excel...")
logger.info(f"目标文件: {output_path}") logger.info(f"输出目录: {export_dir}")
if limit is not None:
logger.info(f"限制导出记录数: {limit}")
final_path = await export_excel(output_path, limit=limit) for operator in operators:
logger.info(f"Excel 导出完成: {final_path}") output_filename = f"{operator}_{ts}.xlsx"
output_path = os.path.join(export_dir, output_filename)
logger.info(f"--- 正在导出 {operator} ---")
if limit is not None:
logger.info(f"限制导出记录数: {limit}")
try:
final_path = await export_excel(operator, output_path, limit=limit)
logger.info(f"{operator} 导出完成: {final_path}")
except Exception as e:
logger.error(f"{operator} 导出失败: {e}")
logger.info("所有导出任务已结束。")
if __name__ == "__main__": if __name__ == "__main__":