modified: amazon/__pycache__/approve.cpython-39.pyc

new file:   amazon/__pycache__/asin_status.cpython-39.pyc
	modified:   amazon/__pycache__/main.cpython-39.pyc
	modified:   amazon/__pycache__/match_action.cpython-39.pyc
	modified:   amazon/__pycache__/price_match.cpython-39.pyc
	modified:   amazon/approve.py
	modified:   amazon/asin_status.py
	modified:   amazon/main.py
	modified:   amazon/match_action.py
	modified:   amazon/price_match.py
	modified:   web_source/brand.html
	modified:   web_source/templates_backup/brand.html
This commit is contained in:
铭坤
2026-04-24 23:00:59 +08:00
parent 03e697f5d3
commit d272afae1c
12 changed files with 1632 additions and 1384 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+3 -2
View File
@@ -1040,7 +1040,8 @@ class ApproveTask:
for country_code in country_codes:
# 检查是否收到暂停请求
if task_id in runing_task and runing_task[task_id].get("stop_requested", False):
self.log(f"检测到任务 {task_id} 的暂停请求,停止处理国家", "WARNING")
self.log(f"检测到任务 {task_id} 的暂停请求,停止处理国家", "ERROR")
driver.close_store()
break
# 打开店铺
@@ -1058,7 +1059,7 @@ class ApproveTask:
import traceback
self.log(f"处理国家 {country_code} 失败: {str(e)}", "ERROR")
self.log(traceback.format_exc(), "ERROR")
if "与页面的连接已断开" in e:
if "与页面的连接已断开" in str(e):
iskill = True
# 更新已处理国家数
+712
View File
@@ -0,0 +1,712 @@
import json
import sys
import os
import io
# sys.stdout.reconfigure(encoding='utf-8')
import time
import re
import traceback
from datetime import datetime
from DrissionPage import Chromium, ChromiumOptions
import requests
from amazon.del_brand import AmamzonBase, kill_process
from amazon.tool import show_notification, get_shop_info, remove_special_characters, split_currency_values
from config import runing_task, runing_shop, base_dir, DELETE_BRAND_API_BASE
class AmzonePStatus(AmamzonBase):
mark_name = "状态查询"
def SwitchPage(self):
"""
切换至 管理所有库存页面
1、等待 //navigation-favorites-bar[@class="hydrated"] 出现
"""
navigation = self.tab.ele('xpath://navigation-favorites-bar[@class="hydrated"]')
navigation.wait.displayed(raise_err=False)
page_btn = navigation.sr('xpath://internal-fav-bar-links[@data-internal="navigation"]').sr(
'xpath://a[@data-page-id="ezdpc-gui-inventory-mons"]')
page_btn.wait.displayed(raise_err=False)
page_btn.click(timeout=5)
self.tab.wait.doc_loaded()
# 等待搜索框出现
search_region = self.tab.ele('xpath://div[@id="searchBoxContainer"]//kat-input-group')
search_region.wait.displayed(raise_err=False, timeout=60)
def search_asin(self, asin):
search_region = self.tab.ele('xpath://div[@id="searchBoxContainer"]//kat-input-group')
search_region.wait.displayed(raise_err=False)
time.sleep(0.6)
search_input = self.tab.ele("xpath://kat-input[contains(@class,'SearchBox-module__searchInput')]").sr(
'xpath://span[@class="container"]//input[@part="input"]')
search_input.input(asin, clear=True)
sku_ls = []
for _ in range(3):
search_btn = self.tab.ele("xpath://kat-icon[@name='search']")
search_btn.click()
load_ele = self.tab.ele("xpath://div[contains(@class,'Loader-module__loader')]")
# load_ele.wait.hidden(timeout=3, raise_err=False)
load_ele.wait.deleted(timeout=3, raise_err=False)
time.sleep(0.5)
sku_ls = self.tab.eles("xpath://div[@data-sku]", timeout=3)
if len(sku_ls) > 0:
break
return sku_ls
def search_asin_action(self, asin: str):
load_ele = self.tab.eles("xpath://div[contains(@class,'Loader-module__loader')]", timeout=5)
if len(load_ele) > 0:
load_ele[0].wait.deleted(timeout=3, raise_err=False)
time.sleep(0.5)
sku_ls = self.search_asin(asin=asin)
print(f"{self.mark_name}{asin} 搜索到 {len(sku_ls)} 个SKU")
def clear_tab(self):
all_tab = self.browser.get_tabs()
close_tab = []
for tab in all_tab:
tab_id = tab if isinstance(tab, str) else tab.tab_id
if self.tab.tab_id == tab_id:
continue
close_tab.append(tab)
print("需要关闭的标签页", close_tab)
print("当前操作的tab_id", self.tab.tab_id)
self.browser.close_tabs(close_tab)
def run_page_action(self, appoint_asin: str = None):
"""
miniprice_info :
{
"B0DSJGJBWV" : "19.81" # asin : 最低价
}
"""
print(f"{self.mark_name}】,开始执行")
num = 0
retry_num = 0
already_asin = set()
get_page_faild = 0
while retry_num < 3: # 最多重试3次
try:
print(self.mark_name, "指定asin操作", appoint_asin)
self.search_asin_action(asin=appoint_asin)
load_ele = self.tab.eles("xpath://div[contains(@class,'Loader-module__loader')]", timeout=5)
if len(load_ele) > 0:
load_ele[0].wait.deleted(timeout=3, raise_err=False)
time.sleep(0.5)
# 获取当前页码
try:
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
# 总页数
total_page = page_pamel[0].sr.eles(
'xpath:.//ul[@class="pages"]//span[@class="page__inner"][last()]')
if len(total_page) > 0:
total_page = total_page[-1].text
else:
total_page = 0
print(f"{self.mark_name}】当前页码: {current_page} / 总页数: {total_page}")
get_page_faild = 0
except Exception as e:
print("{self.mark_name}", "获取页码失败", e)
get_page_faild += 1
if get_page_faild > 2:
show_notification(f"{self.mark_name}】获取页码失败超3次停止任务!")
break
sku_ls = self.tab.eles("xpath://div[@data-sku]", timeout=10)
print(f"{self.mark_name}】获取到 {len(sku_ls)}")
# for sku_ele in sku_ls[0:2]:
if len(sku_ls) == 0:
yield (appoint_asin,"查询不到")
break
for sku_ele in sku_ls:
asin = sku_ele.ele(
'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
# 状态
status_ele = sku_ele.eles('xpath:.//div[contains(@class,"Status-module__container")]//kat-label')
if len(status_ele) > 0:
statu = status_ele[0].attr("emphasis")
else:
statu = "未获取到状态"
already_asin.add(asin)
yield (asin,statu)
print(f"{self.mark_name}",(asin,statu))
# 判断是否存在需要翻页的情况
page_pamel = self.tab.eles('xpath://kat-pagination', timeout=5)
if len(page_pamel) == 0:
break
next_page_btn = page_pamel[0].sr('xpath:.//span[@part="pagination-nav-right"]')
class_str = next_page_btn.attr('class')
if "end" in class_str:
break
next_page_btn.click()
num += 1
print(f"{self.mark_name}】【程序计算】正在翻页,已翻 {num} 页...")
already_asin = set()
except Exception as e:
print(f"{self.mark_name}】处理跟价操作异常", e)
traceback.print_exc()
retry_num += 1
self.tab.refresh()
self.tab.wait.doc_loaded(raise_err=False, timeout=120)
class StatusTask:
country_info = {
"DE": "德国",
"FR": "法国",
"ES": "西班牙",
"IT": "意大利",
"UK": "英国"
}
def __init__(self, user_info: dict = None):
"""初始化审批任务处理器
Args:
user_info: 用户信息字典,包含 company, username, password
"""
self.user_info = user_info or {}
self.running = True
def log(self, message: str, level: str = "INFO"):
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
if level == "ERROR":
show_notification(message, "error")
print(f"[{timestamp}] [PriceTask] [{level}] {message}")
def process_task(self, task_data: dict):
"""处理审批任务主入口
Args:
task_data: 任务数据
"""
try:
data = task_data.get("data", {})
task_id = data.get("taskId")
items = data.get("items", [])[0]
shop_name = items.get("shop_name")
queryAsins = items.get("queryAsins", [])
user_id = data.get("user_id")
stage_index = data.get("stage_index")
final_stage = bool(data.get("final_stage", True))
# 用于测试
limit = data.get("limit", None)
if not task_id:
self.log("任务ID为空,跳过", "WARNING")
return
# if not items:
# self.log("店铺列表为空,跳过", "WARNING")
# return
if not queryAsins:
self.log("queryAsins 列表为空,跳过", "WARNING")
return
self.log(f"开始处理审批任务 {task_id},共 1 个店铺,{len(queryAsins)} 个国家")
from config import runing_task
runing_task[task_id] = {
"status": "running",
"start_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"total_shops": 1,
"processed_shops": 0,
"total_countries": len(queryAsins),
"processed_countries": 0,
"total_asins": 0,
"processed_asins": 0,
"success_count": 0,
"failed_count": 0,
"stop_requested": False
}
# 检查是否收到暂停请求
if task_id in runing_task and runing_task[task_id].get("stop_requested", False):
self.log(f"检测到任务 {task_id} 的暂停请求,停止处理", "WARNING")
runing_task[task_id]["status"] = "stopped"
return
self.log(f"开始处理店铺: {shop_name}")
show_notification(f"开始处理店铺: {shop_name}", "info")
try:
self.process_shop(items, queryAsins, task_id, user_id, stage_index,
final_stage, limit=limit)
# self.process_shop(shop_item, country_codes, task_id,risk_listing_filter)
# 更新已处理店铺数
if task_id in runing_task:
runing_task[task_id]["processed_shops"] += 1
except Exception as e:
import traceback
self.log(f"处理店铺 {shop_name} 失败: {str(e)}", "ERROR")
self.log(traceback.format_exc(), "ERROR")
# 更新任务状态
if task_id in runing_task:
if runing_task[task_id].get("stop_requested", False):
runing_task[task_id]["status"] = "stopped"
self.log(f"任务 {task_id} 已被暂停!")
else:
runing_task[task_id]["status"] = "completed"
self.log(f"任务 {task_id} 处理完成!")
except Exception as e:
import traceback
self.log(f"任务处理失败: {traceback.format_exc()}", "ERROR")
if task_id:
from config import runing_task
if task_id in runing_task:
runing_task[task_id]["status"] = "failed"
runing_task[task_id]["error"] = str(e)
def open_shop(self, max_retries, company_name, shop_name, iskill=False):
error_info = ""
driver = None
for retry in range(max_retries):
try:
self.log(f"尝试打开店铺 {shop_name} (第 {retry + 1}/{max_retries} 次)")
if iskill:
self.log("重试前先杀掉浏览器进程...")
kill_process("v6")
kill_process("v5")
time.sleep(2)
# 组装用户信息并创建驱动
user_info = {
**self.user_info,
"company": company_name
}
driver = AmzonePStatus(user_info)
browser = driver.open_shop(shop_name)
if browser and browser != "店铺不存在":
self.log(f"成功打开店铺 {shop_name}")
else:
self.log(f"打开店铺失败: {browser}", "WARNING")
driver = None
continue
# 判断是否需要登录
need_login = driver.need_login()
print("【是否需要登录】:", need_login)
if need_login:
self.log(f"店铺 {shop_name} 需要登录,正在登录...")
# 获取店铺凭证
response = get_shop_info(shop_name)
print("【获取店铺凭证返回】:", response.text)
shop_data = response.json()
if not shop_data:
mes = f"获取店铺凭证失败,响应数据: {shop_data.get('message', '未知错误')}"
self.log(mes, "ERROR")
show_notification(mes, "ERROR")
continue
password = shop_data["data"]["password"]
login_success = driver.login(password)
if login_success:
self.log(f"店铺 {shop_name} 登录成功,正在重新打开店铺...")
browser = driver.open_shop(shop_name)
if browser and browser != "店铺不存在":
self.log(f"成功打开店铺 {shop_name} 登录后")
break
else:
self.log(f"登录后打开店铺失败: {browser}", "WARNING")
driver = None
else:
self.log(f"店铺 {shop_name} 登录失败", "WARNING")
driver = None
else:
break
except Exception as e:
import traceback
self.log(f"打开店铺异常: {traceback.format_exc()}", "INFO")
driver = None
error_info = str(e)
time.sleep(10)
# 如果还有重试机会,等待后继续
if retry < max_retries - 1:
time.sleep(3)
# 检查是否成功打开
if not driver or not browser or browser == "店铺不存在":
error_msg = f"店铺 {shop_name} 打开失败,已重试 {max_retries} 次,跳过该店铺,{error_info}"
self.log(error_msg, "ERROR")
# 从执行列表中移除
if shop_name in runing_shop:
del runing_shop[shop_name]
return driver
return driver
def process_shop(self, shop_item: dict, country_codes: list, task_id: int,
user_id=None, stage_index=None, final_stage: bool = True, limit: str = None):
"""处理单个店铺
Args:
shop_item: 店铺信息
country_codes: 国家代码列表
task_id: 任务ID
risk_listing_filter: 风险商品筛选条件
"""
shop_name = shop_item.get("shopName", "未知店铺")
company_name = shop_item.get("companyName", "")
if not company_name:
self.log(f"店铺 {shop_name} 的公司名称为空,跳过", "WARNING")
return
if task_id in runing_task:
runing_task[task_id]["current_shop"] = shop_name
# 将店铺添加到正在执行中的店铺列表
start_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
runing_shop[shop_name] = start_time
self.log(f"店铺 {shop_name} 已添加到执行列表,账号: {company_name},开始时间: {start_time}")
# 店铺打开重试最多3次
max_retries = 3
iskill = False
# 处理每个国家
for value in country_codes:
country_code = value.get("country")
all_asin = value.get("asins")
# 打开店铺
driver = self.open_shop(max_retries=max_retries, company_name=company_name,
shop_name=shop_name, iskill=iskill)
if driver is None:
self.log(f"任务 {task_id} 启动店铺失败,结束任务", "ERROR")
for country_code in country_codes:
self.post_result(task_id, shop_name, country_code, "", "", is_done=True)
return
# 检查是否收到暂停请求
if task_id in runing_task and runing_task[task_id].get("stop_requested", False):
self.log(f"检测到任务 {task_id} 的暂停请求,停止处理国家", "ERROR")
driver.close_store()
break
try:
self.process_country(driver, country_code, task_id, shop_name,all_asin=all_asin )
except Exception as e:
import traceback
self.log(f"处理国家 {country_code} 失败: {str(e)}", "ERROR")
self.log(traceback.format_exc(), "ERROR")
if "与页面的连接已断开" in str(e):
iskill = True
# 更新已处理国家数
if task_id in runing_task:
runing_task[task_id]["processed_countries"] += 1
# 关闭店铺
driver.close_store()
# 最后回传,标记完成
try:
# self.post_result(task_id, shop_name, country_code, "", "", is_done=True)
if final_stage:
self.post_result(task_id, shop_name, country_code, "", "", is_done=True)
else:
self.post_stage_finished(task_id, user_id, stage_index)
except Exception as e:
self.log(f"回传结果失败: {str(e)}", "ERROR")
# 从正在执行中的店铺列表中移除
if shop_name in runing_shop:
del runing_shop[shop_name]
self.log(f"店铺 {shop_name} 已从执行列表中移除")
def process_country(self, driver: AmzonePStatus, country_code: str, task_id: int, shop_name: str,
all_asin:list,
limit: str = None):
"""处理单个国家的审批任务
Args:
driver: AmzoneApprove驱动实例
country_code: 国家代码(如 UK, DE, FR 等)
task_id: 任务ID
shop_name: 店铺名称
risk_listing_filter: 风险商品筛选条件
"""
# 转换国家代码为中文名称
country_name = self.country_info.get(country_code, country_code)
info_mes = f"开始处理国家: {country_name} ({country_code})"
self.log(info_mes)
show_notification(info_mes, "info")
# 更新当前处理的国家
if task_id in runing_task:
runing_task[task_id]["current_country"] = country_name
# 切换国家,最多重试3次
max_retries = 3
switch_success = False
for retry in range(max_retries):
try:
self.log(f"尝试切换到国家 {country_name} (第 {retry + 1}/{max_retries} 次)")
if retry > 1:
# 刷新不行就重新打开店铺
self.log("重试前重新打开店铺...")
try:
driver.close_store()
time.sleep(3)
driver.open_shop(shop_name)
except Exception as e:
self.log(f"关闭重新打开店铺: {str(e)}", "WARNING")
# 如果不是第一次尝试,先刷新页面
if retry > 0:
self.log("重试前刷新页面...")
try:
driver.tab.refresh()
time.sleep(3)
except Exception as e:
self.log(f"刷新页面失败: {str(e)}", "WARNING")
switch_success = driver.SwitchingCountries(country_name)
if switch_success:
self.log(f"成功切换到国家 {country_name}")
break
else:
self.log(f"切换到国家 {country_name} 失败", "WARNING")
except Exception as e:
import traceback
self.log(f"切换国家 {country_name} 异常: {str(e)}", "ERROR")
self.log(traceback.format_exc(), "ERROR")
# 如果还有重试机会,等待后继续
if retry < max_retries - 1:
time.sleep(2)
# 如果切换失败,直接返回
if not switch_success:
error_message = f"切换到国家 {country_name} 失败,已重试 {max_retries} 次,跳过该国家"
self.log(error_message, "ERROR")
if task_id in runing_task:
runing_task[task_id]["processed_countries"] += 1
return
# 切换到库存管理页面
for retry in range(max_retries):
try:
driver.SwitchPage()
self.log(f"已切换到库存管理页面")
except Exception as e:
import traceback
self.log(f"切换页面失败: {str(e)}", "ERROR")
self.log(traceback.format_exc(), "ERROR")
if retry >= max_retries - 1:
if task_id in runing_task:
runing_task[task_id]["processed_countries"] += 1
self.log(f"切换页面失败重试退出", "ERROR")
return
# 处理所有需要审批的商品(通过yield获取结果)
# 指定 asin
for ap_asin in all_asin:
print(f"{driver.mark_name}】开始处理 ->",ap_asin)
for asin, status in driver.run_page_action(
appoint_asin=ap_asin
):
# 检查是否收到暂停请求
if task_id in runing_task and runing_task[task_id].get("stop_requested", False):
self.log(f"检测到任务 {task_id} 的暂停请求,停止处理ASIN", "WARNING")
break
self.log(f"ASIN {asin} 处理结果: {status}")
# 更新任务状态
if task_id in runing_task:
runing_task[task_id]["current_asin"] = asin
runing_task[task_id]["processed_asins"] += 1
runing_task[task_id]["failed_count"] += 1
# 回传结果到API
try:
self.post_result(task_id, shop_name, country_code, asin, status)
except Exception as e:
self.log(f"回传结果失败: {str(e)}", "ERROR")
self.log(f"国家 {country_name} 处理完成")
def post_stage_finished(self, task_id: int, user_id, stage_index):
# import requests
# from config import DELETE_BRAND_API_BASE
if user_id in (None, "", 0):
raise ValueError("user_id is required for stage completion callback")
if stage_index is None:
raise ValueError("stage_index is required for stage completion callback")
url = f"{DELETE_BRAND_API_BASE}/api/shop-match/tasks/{task_id}/stage-finished"
payload = {"stage_index": stage_index}
params = {"user_id": user_id}
max_retries = 3
for retry in range(max_retries):
try:
self.log(f"Attempting stage completion callback ({retry + 1}/{max_retries})")
response = requests.post(
url,
params=params,
json=payload,
headers={"Content-Type": "application/json"},
timeout=30,
verify=False,
)
self.log(f"Stage completion callback response: {response.text}")
data = response.json() if response.text else {}
if response.status_code == 200 and isinstance(data, dict) and data.get("success"):
self.log(f"Stage completion callback succeeded: task={task_id}, stage={stage_index}")
return
self.log(f"Stage completion callback failed, status={response.status_code}", "WARNING")
except Exception as e:
self.log(f"Stage completion callback exception: {str(e)}", "ERROR")
if retry < max_retries - 1:
time.sleep(2)
raise RuntimeError(f"Stage completion callback failed after retries: task={task_id}, stage={stage_index}")
def post_result(self, task_id: int, shop_name: str, country_code: str, asin: str, status: dict,
is_done: bool = False):
"""回传处理结果到API
Args:
task_id: 任务ID
shop_name: 店铺名称
country_code: 国家代码
asin: ASIN
status: 处理状态
"""
url = f"{DELETE_BRAND_API_BASE}/api/query-asin/tasks/{task_id}/result"
payload = {
"shops": [
{
"shopName": shop_name,
"countryResults": [
{
"country": country_code,
"items": [
{
"asin": asin,
"status": status
}
]
}
],
"shopDone": is_done,
"submissionId": f"{int(time.time())}"
}
]
}
if is_done:
payload["shops"][0]["success"] = is_done
max_retries = 3
for retry in range(max_retries):
try:
print("================【跟价】=====================")
self.log(f"尝试回传结果 (第 {retry + 1}/{max_retries} 次)")
self.log(f"回传URL: {url}")
self.log(f"回传数据: {payload}")
response = requests.post(
url,
json=payload,
headers={"Content-Type": "application/json"},
timeout=30,
verify=False
)
self.log(f"回传结果: {response.text}")
data = response.json() if response.text else {}
if response.status_code == 200 and isinstance(data, dict) and data.get("success"):
self.log(f"结果回传成功: {asin} - {status}")
return
else:
self.log(f"结果回传失败,状态码: {response.status_code}", "WARNING")
print("=====================================")
except Exception as e:
self.log(f"调用API异常: {str(e)}", "ERROR")
print("=====================================")
# 如果还有重试机会,等待后继续
if retry < max_retries - 1:
time.sleep(2)
self.log(f"已达到最大重试次数,结果回传最终失败", "ERROR")
raise RuntimeError("已达到最大重试次数,结果回传最终失败")
if __name__ == '__main__':
# 使用示例
user_info = {
"company": "rongchuang123",
"username": "自动化_Robot",
"password": "#20zsg25"
}
shop_name = "魏振峰"
country = "德国"
kill_process('v6')
driver = AmzonePStatus(user_info)
browser = driver.open_shop(shop_name)
sw_suc = driver.SwitchingCountries(country)
driver.SwitchPage()
risk_listing_filter = "Active"
_shopMallName = "WEIZHENFENG168"
ap_asin = "B0F1N18XFW"
skip_asin = []
for _ in range(3):
try:
sku_ls = driver.search(filter_type=risk_listing_filter)
break
except Exception as e:
print(e)
driver.tab.refresh()
if len(sku_ls) > 0:
print("有数据,开始操作")
for asin, status in driver.run_page_action(
current_shop_name=_shopMallName,
appoint_asin=ap_asin, skip_asin=skip_asin
):
print(f"ASIN {asin} 的处理结果: {status}")
print("已完成操作")
+5 -2
View File
@@ -9,6 +9,7 @@ from amazon.del_brand import AmazoneDriver, kill_process
from amazon.approve import ApproveTask
from amazon.match_action import MatchTak
from amazon.price_match import PriceTask
from amazon.asin_status import StatusTask
from amazon.tool import get_shop_info,show_notification
@@ -55,7 +56,8 @@ class TaskMonitor:
task_type_info = {
"product-risk-resolve-run" : "产品风险审批",
"shop-match-run" : "匹配价格",
"price-track-run" : "跟价"
"price-track-run" : "跟价",
"query-asin-run" : "状态查询"
}
try:
while self.running:
@@ -122,7 +124,8 @@ class TaskMonitor:
TASK_INFO = {
"产品风险审批" : ApproveTask,
"匹配价格" : MatchTak,
"跟价" : PriceTask
"跟价" : PriceTask,
"状态查询" : StatusTask
}
self.log(f"线程 {id(task_data)} 开始处理产品风险审批任务...")
# 创建ApproveTask实例并处理任务
+1 -1
View File
@@ -445,7 +445,7 @@ class MatchTak:
import traceback
self.log(f"处理国家 {country_code} 失败: {str(e)}", "ERROR")
self.log(traceback.format_exc(), "ERROR")
if "与页面的连接已断开" in e:
if "与页面的连接已断开" in str(e):
iskill = True
# 更新已处理国家数
+49 -30
View File
@@ -46,18 +46,30 @@ def calculate_target_price(
# 不是自己的购物车:直接将紫鸟的总和作为"第一名"价格,强制抛入阶梯跟价逻辑
return calculate_standard_competitor_pricing(my_price, total_price)
# # 第一名是自己, 第二名 Amazon US 卖家 的情况
shop_name_1 = front_end_data.get("top_sellers")[0].get("shop_name")
shop_name_2 = front_end_data.get("top_sellers")[1].get("shop_name") if len(front_end_data.get("top_sellers")) >=2 else ""
if shop_name_1 == current_shop_name and "Amazon" in shop_name_2:
price_2 = float(front_end_data.get("top_sellers")[1].get("price")) # 实际第二名价格
diff = abs(my_price - price_2)
if diff < 5:
return price_2 -3
elif 5.0 < diff <= 8.0:
return price_2 -3
# --- Step 3: 常规核心分流逻辑 (如果没有紫鸟后台数据) ---
# 分支 A:第一名是 Amazon US 卖家 (特殊强敌优先)
price_1 = float(front_end_data.get("top_sellers")[0].get("price")) # 实际第一名价格
if "Amazon." in cart_seller:
diff = abs(my_price - price_1)
if diff <= 5.0 or my_price > price_1:
return price_1 - 5.0
if diff <= 5.0 :
return None
elif 5.0 < diff <= 8.0:
return price_1 - 3.0
elif 8.0 < diff <= 12.0:
return None # 跳过,不跟价
elif diff > 8.0:
return price_1 - 6 # 跳过,不跟价
# 分支 B:不是 Amazon US,且目前是自己的购物车
@@ -78,7 +90,6 @@ def calculate_target_price(
else:
return None
# 分支 C:不是 Amazon US,也不是自己的购物车
else:
# 正常情况下的普通跟价,调用阶梯逻辑
@@ -104,9 +115,10 @@ def calculate_standard_competitor_pricing(my_current_price, target_competitor_pr
return base_target - 1.0
elif 1.5 <= diff <= 2.5:
return base_target - 1.0
elif diff > 2.5:
return my_current_price # 差距过大,跳过不跟价
elif 2.5 < diff <= 3 :
return None # 差距过大,跳过不跟价
elif diff > 3:
return base_target
@@ -586,18 +598,16 @@ class AmzonePriceMatch(AmamzonBase):
# 如果紫鸟里当前价格低于最低价则删除,否则跳过
if mode == "status" and miniprice_info.get(asin):
backend_price = float(miniprice_info.get(asin))
if float(current_price) < backend_price:
if float(current_price) <= backend_price:
# yield (asin, {
# "statu": "删除(当前价格低于最低价)",
# "deleteSkipAsin": True,
# "removeAsin": asin,
# })
yield (asin, {
"statu": "删除(当前价格低于最低价)",
"deleteSkipAsin": True,
"removeAsin": asin,
})
continue
else:
yield (asin, {
"statu": "跳过(当前价格不低于最低价)",
"deleteSkipAsin": True,
"removeAsin": asin,
"statu": "跳过(当前价格低于或等于最低价)",
"currentPrice": current_price,
"minimumPrice": bottom_price, # 最低价格
})
continue
@@ -924,6 +934,11 @@ class PriceTask:
skip_asins_by_country = shop_item.get("skip_asins_by_country",{})
asin_rows_by_country = shop_item.get("asin_rows_by_country",{})
skip_asin_details_by_country = shop_item.get("skip_asin_details_by_country",{})
minimum_price_by_country_and_asin = shop_item.get("minimum_price_by_country_and_asin",{})
if len(minimum_price_by_country_and_asin) > 0:
country_codes = minimum_price_by_country_and_asin.keys()
# 指定ASIN的情况
mode = shop_item.get("mode")
if not company_name:
@@ -955,20 +970,25 @@ class PriceTask:
# 检查是否收到暂停请求
if task_id in runing_task and runing_task[task_id].get("stop_requested", False):
self.log(f"检测到任务 {task_id} 的暂停请求,停止处理国家", "WARNING")
self.log(f"检测到任务 {task_id} 的暂停请求,停止处理国家", "ERROR")
driver.close_store()
break
skip_asin = skip_asins_by_country.get(country_code,[]) #需要跳过的asin
appoint_asin = asin_rows_by_country.get(country_code,[])
miniprice_info = {i.get('asin'):i.get('minimumPrice') for i in skip_asin_details_by_country.get(country_code,[])}
if mode == "status":
miniprice_info = {i.get('asin'):i.get('minimumPrice') for i in skip_asin_details_by_country.get(country_code,[])}
else:
miniprice_info = minimum_price_by_country_and_asin.get(country_code,{})
try:
self.process_country(driver, country_code, task_id, shop_name, risk_listing_filter,
shopMallName=shopMallName,skip_asin=skip_asin, limit=limit,
appoint_asin=appoint_asin,mode=mode,miniprice_info=miniprice_info)
appoint_asin=appoint_asin,mode=mode,miniprice_info=miniprice_info,
)
except Exception as e:
import traceback
self.log(f"处理国家 {country_code} 失败: {str(e)}", "ERROR")
self.log(traceback.format_exc(), "ERROR")
if "与页面的连接已断开" in e:
if "与页面的连接已断开" in str(e):
iskill = True
# 更新已处理国家数
if task_id in runing_task:
@@ -994,8 +1014,7 @@ class PriceTask:
def process_country(self, driver: AmzonePriceMatch, country_code: str, task_id: int, shop_name: str,
risk_listing_filter: str,shopMallName:str,skip_asin:list,appoint_asin:list,mode:str,
miniprice_info:dict={},
limit: str = None):
miniprice_info:dict={}, limit: str = None):
"""处理单个国家的审批任务
Args:
@@ -1113,7 +1132,7 @@ class PriceTask:
for i in range(max_range):
if len(appoint_asin) > i:
_shopMallName = appoint_asin[i]["shopMallName"]
ap_asin = appoint_asin[i]["shopMallName"]
ap_asin = appoint_asin[i]["asin"]
else:
_shopMallName = shopMallName
ap_asin = None
@@ -1278,11 +1297,11 @@ class PriceTask:
if __name__ == '__main__':
# 使用示例
user_info = {
"company": "rongchuang123",
"company": "尾号5578的公司115",
"username": "自动化_Robot",
"password": "#20zsg25"
}
shop_name = "魏振峰"
shop_name = "林建华"
country = "德国"
kill_process('v6')
driver = AmzonePriceMatch(user_info)
@@ -1291,7 +1310,7 @@ if __name__ == '__main__':
driver.SwitchPage()
risk_listing_filter = "Active"
_shopMallName = "WEIZHENFENG168"
ap_asin ="B0F1N18XFW"
ap_asin ="B0FHGQY18W"
skip_asin = []
for _ in range(3):
try:
@@ -1304,7 +1323,7 @@ if __name__ == '__main__':
print("有数据,开始操作")
for asin, status in driver.run_page_action(
current_shop_name=_shopMallName,
appoint_asin=ap_asin,skip_asin=skip_asin
appoint_asin=ap_asin,skip_asin=skip_asin,mode="asin"
):
print(f"ASIN {asin} 的处理结果: {status}")
print("已完成操作")
+2 -2
View File
@@ -413,8 +413,8 @@
<a class="nav-item" href="/new_web_source/product-risk.html">商品风险解决</a>
<a class="nav-item" href="/new_web_source/shop-match.html">定时匹配</a>
<a class="nav-item" href="/new_web_source/price-track.html">跟价</a>
<a class="nav-item" href="/new_web_source/patrol-delete.html">巡店删除</a>
<a class="nav-item" href="/new_web_source/query-asin.html">查询ASIN</a>
<span class="nav-item disabled">巡店删除</span>
<a class="nav-item" href="/new_web_source/query-asin.html">查询ASIN</a>
<span class="nav-item disabled">取款</span>
<span class="nav-item disabled">店铺状态查询</span>
</div>
File diff suppressed because it is too large Load Diff