modified: .env

modified:   amazon/__pycache__/approve.cpython-39.pyc
	modified:   amazon/__pycache__/detail_spider.cpython-39.pyc
	modified:   amazon/__pycache__/price_match.cpython-39.pyc
	modified:   amazon/approve.py
	modified:   amazon/detail_spider.py
	modified:   amazon/price_match.py
	modified:   assets/convert.js
	modified:   assets/dedupe.js
	modified:   assets/delete-brand.js
	modified:   assets/split.js
	modified:   blueprints/__pycache__/admin.cpython-39.pyc
	modified:   blueprints/__pycache__/brand.cpython-39.pyc
	modified:   blueprints/__pycache__/main.cpython-39.pyc
	modified:   blueprints/main.py
	modified:   brand_spider/__pycache__/main.cpython-39.pyc
	modified:   new_web_source/convert.html
	modified:   new_web_source/dedupe.html
	modified:   new_web_source/delete-brand.html
	modified:   new_web_source/split.html
	modified:   tool/__pycache__/devices.cpython-39.pyc
This commit is contained in:
铭坤
2026-04-28 15:21:57 +08:00
parent 0b57aea5f6
commit 42bdd59c71
21 changed files with 8054 additions and 6638 deletions

View File

@@ -13,7 +13,7 @@ client_name=ShuFuAI
# java_api_base=http://47.111.163.154:18080
java_api_base=http://127.0.0.1:18080
# java_api_base=http://8.136.19.173:18080
# java_api_base=http://127.0.0.1:18080
java_api_base=http://8.136.19.173:18080

View File

@@ -475,7 +475,8 @@ class AmzoneApprove(AmamzonBase):
retry_num = 0
already_asin = set()
now_page = None
while retry_num < 3: # 最多重试3次
max_retry_num = 5
while retry_num < max_retry_num: # 最多重试3次
# if num > 3: #测试
# return
# 等待加载完成
@@ -505,8 +506,11 @@ class AmzoneApprove(AmamzonBase):
sku_ls = self.tab.eles("xpath://div[@data-sku]",timeout=10)
print(f"获取到 {len(sku_ls)}")
if len(sku_ls) == 0:
print(f"搜索不出SKU停止")
break
retry_num += 1
print(f"没有获取到 ASIN 商品,重试{retry_num}/{max_retry_num}")
self.tab.refresh()
self.tab.wait.doc_loaded(raise_err=False, timeout=120)
continue
# for sku_ele in sku_ls[0:2]:
for sku_ele in sku_ls[1:]:
# solve_problem = sku_ele.eles('xpath:.//kat-link[@label="解决商品信息问题"]')

File diff suppressed because it is too large Load Diff

View File

@@ -28,7 +28,7 @@ class RepricingLogic:
if is_first_time:
return rank1_price - 0.3
diff = abs(my_price - rank1_price)
diff = my_price - rank1_price
# 精简了原图中长串的阶梯逻辑
if diff <= 0.3:
@@ -47,7 +47,7 @@ class RepricingLogic:
情况2已经是自己购物车
逻辑:判断与第二名的差价,如果拉开足够差距,则稍微降一点点(减0.5)保持优势,防止卖太便宜。
"""
diff = abs(rank2_price - my_price)
diff = rank2_price - my_price
# 1. 绝对差价2欧以上
if diff >= 2.0:
@@ -66,7 +66,7 @@ class RepricingLogic:
"""
情况3不是自己购物车 (常规情况)
"""
diff = abs(my_price - rank1_price)
diff = my_price - rank1_price
if diff <= 0.3:
return rank1_price - 0.5
@@ -84,7 +84,7 @@ class RepricingLogic:
"""
情况4第一名是 Amazon US 卖家
"""
diff = abs(my_price - amz_us_price)
diff = my_price - amz_us_price
if diff <= 3:
return amz_us_price - 2
@@ -100,7 +100,7 @@ class RepricingLogic:
"""
情况5自己是第一名第二名是 Amazon US 卖家
"""
diff = abs(amz_us_price - my_price)
diff = amz_us_price - my_price
if diff <= 7:
return None # 相差5以内跳过 (保持原价)
@@ -127,7 +127,12 @@ def calculate_target_price(
# --- Step 2: 紫鸟后台特殊判定 (最高优先级) ---
if recommended_shipping > 0:
price_1 = float(front_end_data.get("top_sellers")[0].get("price")) # 实际第一名价格
return RepricingLogic.situation_1_general_decrease(my_price,price_1,is_my_buybox)
if is_my_buybox:
price_col = price_1
else:
price_col = recommended_price + recommended_shipping
print(f"【紫鸟后台价格】{is_my_buybox} 推荐价格: {recommended_price},推荐运费: {recommended_shipping},总和: {price_col}")
return RepricingLogic.situation_1_general_decrease(my_price,price_col,is_my_buybox)
# backend_base_price = recommended_price
# backend_shipping = recommended_shipping
# total_price = backend_base_price + backend_shipping
@@ -151,7 +156,7 @@ def calculate_target_price(
# 分支 A第一名是 Amazon US 卖家 (特殊强敌优先)
price_1 = float(front_end_data.get("top_sellers")[0].get("price")) # 实际第一名价格
if "Amazon" in shop_name_1:
return RepricingLogic.isituation_4_encounter_amz_us_1st(my_price,price_1)
return RepricingLogic.situation_4_encounter_amz_us_1st(my_price,price_1)
# 分支 B不是 Amazon US且目前是自己的购物车
@@ -619,6 +624,11 @@ class AmzonePriceMatch(AmamzonBase):
page_pamel = self.tab.eles('xpath://kat-pagination', timeout=5)
if len(page_pamel) > 0:
current_page = page_pamel[0].sr('xpath:.//ul[@class="pages"]//li[@aria-current="true"]').text
#测试=====
# if int(current_page) > 3:
# break
# 测试===========
# yield (None,{"page":int(current_page.strip())})
# 总页数
total_page = page_pamel[0].sr.eles(
@@ -653,9 +663,9 @@ class AmzonePriceMatch(AmamzonBase):
'xpath:.//div[contains(@class,"JanusSplitBox-module__container")]//div[contains(@class,"JanusSplitBox-module__panel--") and contains(string(.),"ASIN")]/..//div[last()]',
timeout=3).text
print(f"{self.mark_name}】ASIN {asin} 找到....")
if asin in already_asin:
print(f"{self.mark_name}{asin} 已经处理过了,跳过")
continue
# if asin in already_asin:
# print(f"【{self.mark_name}】{asin} 已经处理过了,跳过")
# continue
if asin in skip_asin:
yield (asin, {
"statu": "跳过,需要跳过的ASIN"
@@ -1391,11 +1401,11 @@ class PriceTask:
if __name__ == '__main__':
# 使用示例
# user_info = {
# "company": "尾号5578的公司115",
# "company": "rongchuang123",
# "username": "自动化_Robot",
# "password": "#20zsg25"
# }
# shop_name = "刘建煌"
# shop_name = "郭亚芳"
# country = "德国"
# kill_process('v6')
# driver = AmzonePriceMatch(user_info)
@@ -1403,8 +1413,8 @@ if __name__ == '__main__':
# sw_suc = driver.SwitchingCountries(country)
# driver.SwitchPage()
# risk_listing_filter = "Active"
# _shopMallName = "Jianhuang 888"
# ap_asin ="B0BGHRP6BS"
# _shopMallName = "yafang123"
# ap_asin ="B0BTHBJDKG"
# skip_asin = []
# for _ in range(3):
# try:
@@ -1422,12 +1432,14 @@ if __name__ == '__main__':
# print(f"ASIN {asin} 的处理结果: {status}")
# print("已完成操作")
front_end_data = {"top_sellers": [{"rank": 1, "price": "36.81", "stock": "5", "shop_name": "Windera"}, {"rank": 2, "price": "36.50", "stock": "100", "shop_name": "Jianhuang 888"}], "cart_seller": "Windera", "timestamp": "2026-04-25 09:32:58"}
current_Price = 36.50
current_shop_name = "Jianhuang 888"
recommended_price = 36.81
recommended_shipping = 0
calculate_target_price(
front_end_data = {'top_sellers': [{'rank': 1, 'price': '50.24', 'stock': '26', 'shop_name': 'yafang123'}, {'rank': 2, 'price': '44.35', 'stock': '100', 'shop_name': 'QinPimy'}], 'cart_seller': 'Amazon US', 'timestamp': '2026-04-27 16:17:42'}
current_Price = 44.35
current_shop_name = "yafang123"
recommended_price = 44.35
recommended_shipping =0.0
res = calculate_target_price(
front_end_data, current_Price, current_shop_name,
recommended_price, recommended_shipping
)
print(res)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -2,7 +2,7 @@
主页面蓝图首页、home、图片工作台、品牌页、静态文件、Logo
"""
import os
from flask import Blueprint, send_file, render_template_string
from flask import Blueprint, send_file
from app_common import (
get_db,
@@ -23,38 +23,6 @@ from config import base_url,version,JAVA_API_BASE
main_bp = Blueprint('main', __name__)
def _resolve_asset_filename(filename):
"""Resolve hashed Vite assets without maintaining hardcoded alias tables."""
safe_name = os.path.basename(filename)
exact_path = os.path.join(ASSETS_DIR, safe_name)
if os.path.isfile(exact_path):
return safe_name
base_name, ext = os.path.splitext(safe_name)
if not base_name or not ext:
return safe_name
parts = base_name.split('-')
if len(parts) < 2:
return safe_name
try:
asset_names = os.listdir(ASSETS_DIR)
except OSError:
return safe_name
for prefix_length in range(len(parts) - 1, 0, -1):
prefix = '-'.join(parts[:prefix_length])
matches = [
asset_name for asset_name in asset_names
if asset_name.endswith(ext) and asset_name.startswith(prefix)
]
if len(matches) == 1:
return matches[0]
return safe_name
@main_bp.route('/')
def index():
if session.get('user_id') and _is_session_user_valid():
@@ -85,41 +53,9 @@ def wb():
@main_bp.route('/brand')
@login_required
def brand_page():
repo_brand_path = os.path.abspath(os.path.join(BASE_DIR, '..', 'web_source', 'brand.html'))
if os.path.isfile(repo_brand_path):
try:
with open(repo_brand_path, 'rb') as f:
raw = f.read()
try:
from html_crypto import decrypt
content = decrypt(raw).decode('utf-8')
except Exception:
if raw[:7] == b'gAAAAAB':
raise
content = raw.decode('utf-8', errors='replace')
return render_template_string(content, user_id=session.get('user_id'))
except Exception:
pass
return _render_html('brand.html', user_id=session.get('user_id'))
@main_bp.route('/brand/legacy')
@login_required
def brand_page_legacy():
legacy_path = os.path.join(BASE_DIR, 'web_source', 'templates_backup', 'brand.html')
if not os.path.isfile(legacy_path):
return '', 404
with open(legacy_path, 'rb') as f:
content = f.read().decode('utf-8', errors='replace')
content = content.replace(
'<header class="top-bar">',
'<header class="top-bar" style="display:none !important;">',
1,
)
content = content.replace('height: calc(100vh - 56px);', 'height: 100vh;', 1)
return render_template_string(content, user_id=session.get('user_id'))
@main_bp.route('/static/<path:filename>')
@@ -136,7 +72,6 @@ def serve_static(filename):
@main_bp.route('/assets/<path:filename>')
def serve_assets(filename):
"""提供 static 目录及子目录下的静态文件访问。"""
filename = _resolve_asset_filename(filename)
filepath = os.path.normpath(os.path.join(ASSETS_DIR, filename))
static_abs = os.path.abspath(ASSETS_DIR)
file_abs = os.path.abspath(filepath)
@@ -147,19 +82,14 @@ def serve_assets(filename):
@main_bp.route('/new_web_source/<path:filename>')
def serve_new_web_source(filename):
"""提供 new_web_source 目录下的静态页面文件访问。"""
candidate_dirs = [
os.path.abspath(os.path.join(BASE_DIR, 'new_web_source')),
os.path.abspath(os.path.join(BASE_DIR, '..', 'new_web_source')),
]
for static_abs in candidate_dirs:
filepath = os.path.normpath(os.path.join(static_abs, filename))
"""提供 static 目录及子目录下的静态文件访问。"""
filepath = os.path.normpath(os.path.join("new_web_source", filename))
static_abs = os.path.abspath("new_web_source")
file_abs = os.path.abspath(filepath)
if not file_abs.startswith(static_abs):
continue
if os.path.isfile(file_abs):
return send_file(file_abs, as_attachment=False)
if not file_abs.startswith(static_abs) or not os.path.isfile(file_abs):
return '', 404
return send_file(file_abs, as_attachment=False)
@main_bp.route('/logo.jpg', methods=['GET'])

View File

@@ -5,10 +5,10 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>格式转换 - 数富AI</title>
<script type="module" crossorigin src="/assets/convert.js"></script>
<link rel="modulepreload" crossorigin href="/assets/pywebview-Bt854mYs.js">
<link rel="modulepreload" crossorigin href="/assets/brand-5-W0Wonr.js">
<link rel="modulepreload" crossorigin href="/assets/pywebview-C66x_2Dh.js">
<link rel="modulepreload" crossorigin href="/assets/brand-BZije8D7.js">
<link rel="stylesheet" crossorigin href="/assets/pywebview-Dp5dN8OO.css">
<link rel="stylesheet" crossorigin href="/assets/convert-7wWJ02Tw.css">
<link rel="stylesheet" crossorigin href="/assets/convert-BKSNvX8i.css">
</head>
<body>
<div id="app"></div>

View File

@@ -5,10 +5,10 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>数据去重 - 数富AI</title>
<script type="module" crossorigin src="/assets/dedupe.js"></script>
<link rel="modulepreload" crossorigin href="/assets/pywebview-Bt854mYs.js">
<link rel="modulepreload" crossorigin href="/assets/brand-5-W0Wonr.js">
<link rel="modulepreload" crossorigin href="/assets/pywebview-C66x_2Dh.js">
<link rel="modulepreload" crossorigin href="/assets/brand-BZije8D7.js">
<link rel="stylesheet" crossorigin href="/assets/pywebview-Dp5dN8OO.css">
<link rel="stylesheet" crossorigin href="/assets/dedupe-BpNHwt51.css">
<link rel="stylesheet" crossorigin href="/assets/dedupe-DNlVfFj-.css">
</head>
<body>
<div id="app"></div>

View File

@@ -5,10 +5,10 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>删除品牌 - 数富AI</title>
<script type="module" crossorigin src="/assets/delete-brand.js"></script>
<link rel="modulepreload" crossorigin href="/assets/pywebview-Bt854mYs.js">
<link rel="modulepreload" crossorigin href="/assets/brand-5-W0Wonr.js">
<link rel="modulepreload" crossorigin href="/assets/pywebview-C66x_2Dh.js">
<link rel="modulepreload" crossorigin href="/assets/brand-BZije8D7.js">
<link rel="stylesheet" crossorigin href="/assets/pywebview-Dp5dN8OO.css">
<link rel="stylesheet" crossorigin href="/assets/delete-brand-CWLpe7lu.css">
<link rel="stylesheet" crossorigin href="/assets/delete-brand-BP3XWKAC.css">
</head>
<body>
<div id="app"></div>

View File

@@ -5,10 +5,10 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>数据拆分 - 数富AI</title>
<script type="module" crossorigin src="/assets/split.js"></script>
<link rel="modulepreload" crossorigin href="/assets/pywebview-Bt854mYs.js">
<link rel="modulepreload" crossorigin href="/assets/brand-5-W0Wonr.js">
<link rel="modulepreload" crossorigin href="/assets/pywebview-C66x_2Dh.js">
<link rel="modulepreload" crossorigin href="/assets/brand-BZije8D7.js">
<link rel="stylesheet" crossorigin href="/assets/pywebview-Dp5dN8OO.css">
<link rel="stylesheet" crossorigin href="/assets/split-CRUIYKS6.css">
<link rel="stylesheet" crossorigin href="/assets/split-BoBVrLdC.css">
</head>
<body>
<div id="app"></div>