Files
ewoooc/scripts/archive/update_product_images.py
ogt 1b4f3a7bbe
Some checks failed
CD Pipeline / deploy (push) Failing after 59s
feat: EwoooC 初始化 — 完整專案推版至 Gitea
- 建立 Gitea Actions CD pipeline (.gitea/workflows/cd.yaml)
- 部署模式: rsync Python 檔案至 188 → docker restart (volume mount)
- Dockerfile/requirements 變動時自動重建 Docker image
- 部署通知: Telegram (開始/成功/失敗)
- 健康檢查: https://mo.wooo.work/health (最多 5 次重試)
- 同步最新 CLAUDE.md / ADR-008 / memory (2026-04-19)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 01:21:13 +08:00

175 lines
6.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
商品圖片 URL 批次更新工具
功能:將所有商品的圖片 URL 更新為 MOMO CDN 標準格式
格式https://m.momoshop.com.tw/moscdn/goods/{i_code}_m.webp
"""
from database.manager import DatabaseManager
from database.models import Product
from logger_manager import SystemLogger
from datetime import datetime
log = SystemLogger("ImageURLUpdater").get_logger()
def get_image_path(i_code):
"""
將 i_code 轉換為圖片路徑
規則:從右往左取 3位/3位/剩餘第一部分補0到4位
例如12092813 → 813/092/12 → 0012/092/813
"""
i_code_str = str(i_code)
# 從右往左切分
part3 = i_code_str[-3:] if len(i_code_str) >= 3 else i_code_str.zfill(3) # 最後3位
part2 = i_code_str[-6:-3] if len(i_code_str) > 3 else '000' # 中間3位
part1 = i_code_str[:-6] if len(i_code_str) > 6 else '0' # 前面剩餘
part1 = part1.zfill(4) # 第一部分補0到4位
part2 = part2.zfill(3) # 第二部分補0到3位 (如果需要)
return f'{part1}/{part2}/{part3}'
def update_all_product_images():
"""批次更新所有商品的圖片 URL"""
db = DatabaseManager()
session = db.get_session()
try:
log.info("=" * 80)
log.info("🖼️ 開始批次更新商品圖片 URL")
log.info("=" * 80)
# 查詢所有商品
all_products = session.query(Product).all()
total_count = len(all_products)
log.info(f"📊 總商品數: {total_count}")
# 統計變數
updated_count = 0
no_change_count = 0
error_count = 0
log.info("\n🔄 開始處理商品...")
print() # 空行,讓輸出更清晰
for idx, product in enumerate(all_products, 1):
try:
# 構造標準圖片 URL (使用新格式)
# https://img.momoshop.com.tw/goodsimg/0012/092/813/12092813_OL_m.webp
path = get_image_path(product.i_code)
new_image_url = f"https://img.momoshop.com.tw/goodsimg/{path}/{product.i_code}_OL_m.webp"
# 判斷是否需要更新
needs_update = False
if product.image_url is None:
# 情況 1: 沒有圖片 URL
needs_update = True
reason = "無圖片 URL"
elif product.image_url != new_image_url:
# 情況 2: 圖片 URL 格式不正確
needs_update = True
reason = "格式需更新"
if needs_update:
old_url = product.image_url if product.image_url else ""
product.image_url = new_image_url
product.updated_at = datetime.now()
updated_count += 1
if updated_count % 100 == 0:
log.info(f" ✅ 已更新 {updated_count}/{total_count} 件商品...")
# 詳細記錄(每 500 件顯示一次詳情)
if updated_count % 500 == 1 or updated_count <= 5:
log.debug(f" [{idx}/{total_count}] {reason}")
log.debug(f" 商品: {product.name[:40]}...")
log.debug(f" i_code: {product.i_code}")
log.debug(f" 舊 URL: {old_url[:60]}..." if len(str(old_url)) > 60 else f" 舊 URL: {old_url}")
log.debug(f" 新 URL: {new_image_url}")
else:
no_change_count += 1
except Exception as e:
error_count += 1
log.error(f" ❌ 處理失敗 | i_code: {product.i_code} | 商品: {product.name[:30]} | Error: {e}")
# 提交變更
log.info("\n💾 提交資料庫變更...")
session.commit()
# 輸出統計結果
log.info("\n" + "=" * 80)
log.info("📊 處理結果統計")
log.info("=" * 80)
log.info(f" 總商品數: {total_count}")
log.info(f" ✅ 已更新: {updated_count} ({updated_count/total_count*100:.1f}%)")
log.info(f" ⏭️ 無需更新: {no_change_count} ({no_change_count/total_count*100:.1f}%)")
log.info(f" ❌ 處理失敗: {error_count}")
log.info("=" * 80)
if updated_count > 0:
log.info(f"✅ 成功更新 {updated_count} 件商品的圖片 URL")
else:
log.info("✅ 所有商品圖片 URL 已是最新格式,無需更新")
return {
'total': total_count,
'updated': updated_count,
'no_change': no_change_count,
'error': error_count
}
except Exception as e:
session.rollback()
log.error(f"❌ 批次更新失敗: {e}")
raise
finally:
session.close()
if __name__ == "__main__":
try:
result = update_all_product_images()
# 驗證結果
print("\n" + "=" * 80)
print("🔍 驗證更新結果...")
print("=" * 80)
db = DatabaseManager()
session = db.get_session()
try:
# 檢查還有多少商品沒有圖片 URL
products_without_image = session.query(Product).filter(Product.image_url.is_(None)).count()
# 檢查使用標準格式的商品數
standard_pattern = "https://m.momoshop.com.tw/moscdn/goods/%"
products_with_standard_url = session.query(Product).filter(
Product.image_url.like(standard_pattern)
).count()
total_products = session.query(Product).count()
print(f"無圖片 URL 商品: {products_without_image} ({products_without_image/total_products*100:.1f}%)")
print(f"標準格式商品: {products_with_standard_url} ({products_with_standard_url/total_products*100:.1f}%)")
print("=" * 80)
if products_without_image == 0:
print("✅ 驗證成功:所有商品都有圖片 URL")
else:
print(f"⚠️ 仍有 {products_without_image} 件商品沒有圖片 URL")
finally:
session.close()
except KeyboardInterrupt:
print("\n⚠️ 使用者中斷執行")
except Exception as e:
print(f"\n❌ 執行失敗: {e}")
raise