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

modified:   amazon/__pycache__/del_brand.cpython-39.pyc
	modified:   amazon/__pycache__/match_action.cpython-39.pyc
	modified:   amazon/approve.py
	modified:   amazon/del_brand.py
	modified:   amazon/match_action.py
	new file:   amazon/price_match.py
	modified:   main.py
This commit is contained in:
铭坤
2026-04-17 10:04:24 +08:00
parent 025ca6d4fd
commit ac07416352
8 changed files with 749 additions and 98 deletions

333
app/amazon/price_match.py Normal file
View File

@@ -0,0 +1,333 @@
import time
import re
import traceback
from config import runing_task, runing_shop
from datetime import datetime
from amazon.del_brand import AmamzonBase, kill_process
from amazon.tool import show_notification,get_shop_info
class ChromeAmzone:
mark_name = "亚马逊详情采集"
country_info = {
"英国": {
"url": "https://www.amazon.co.uk/dp/B0CJ8SNXXV",
"zip_code": "SW1A 1AA"
},
"德国": {
"url": "https://www.amazon.de/dp/B0CC8CW9G2?th=1",
"zip_code": "10115"
},
"法国": {
"url": "https://www.amazon.fr/dp/B0FRG1MJ8H?th=1",
"zip_code": "75001"
},
"西班牙": {
"url": "https://www.amazon.es/dp/B08ZXVNYNN",
"zip_code": "28001"
},
"意大利": {
"url": "https://www.amazon.it/dp/B0D1P17T2Q",
"zip_code": "20121"
}
}
def __init__(self):
"""
杀死当前谷歌浏览器进程,并使用 drissionpage 启动谷歌浏览器,使用系统安装的浏览器默认用户文件夹
"""
# 杀死现有的Chrome进程
print("正在关闭现有的Chrome浏览器进程...")
import os
os.system('taskkill /f /t /im chrome.exe')
time.sleep(2)
# 使用 DrissionPage 启动浏览器(使用默认用户数据)
from DrissionPage import Chromium, ChromiumOptions
print("正在启动Chrome浏览器...")
# 配置浏览器选项
co = ChromiumOptions()
# 使用系统默认的用户数据目录
# co.set_user_data_path(r'C:\Users\{}\AppData\Local\Google\Chrome\User Data'.format(os.getenv('USERNAME')))
self.browser = Chromium(co)
self.tab = self.browser.latest_tab
print("Chrome浏览器启动成功")
def accept_cookie(self):
pass
def run(self, country, asin):
"""
运行亚马逊详情采集任务
Args:
country: 国家名称(如:英国、德国、法国、西班牙、意大利)
asin: 亚马逊商品ASIN码
Returns:
dict: 包含采集到的数据
"""
try:
# 验证国家是否支持
if country not in self.country_info:
error_msg = f"不支持的国家: {country},支持的国家有: {list(self.country_info.keys())}"
print(error_msg)
show_notification(error_msg, "error")
return None
# 获取国家配置
country_config = self.country_info[country]
zip_code = country_config["zip_code"]
# 1. 根据国家和ASIN拼接链接
base_url = country_config["url"]
# 提取域名部分
domain = base_url.split("/dp/")[0]
# 拼接新的URL
product_url = f"{domain}/dp/{asin}"
print(f"正在访问: {product_url}")
# 打开链接
self.tab.get(product_url)
time.sleep(3) # 等待页面初步加载
self.tab.wait.doc_loaded(timeout=30, raise_err=False)
# 2. 切换国家/设置邮编
print(f"正在检查并设置邮编: {zip_code}")
self._set_zip_code(zip_code)
# 3. 抓取数据
print("正在抓取商品数据...")
data = self._scrape_data()
# 添加基本信息
data['country'] = country
data['asin'] = asin
data['url'] = product_url
data['timestamp'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
print(f"数据抓取完成: {data}")
return data
except Exception as e:
error_msg = f"运行出错: {traceback.format_exc()}"
print(error_msg)
show_notification(f"采集失败: {str(e)}", "error")
return None
def _set_zip_code(self, zip_code):
"""
设置邮编
Args:
zip_code: 目标邮编
"""
try:
# 检查当前邮编
zip_display = self.tab.ele('xpath://div[@id="glow-ingress-block"]', timeout=10)
if zip_display:
current_text = zip_display.text
print(f"当前地址信息: {current_text}")
# 检查是否已经包含目标邮编
if zip_code in current_text:
print(f"邮编已经设置为: {zip_code},无需修改")
return True
# 需要设置邮编
print(f"正在设置邮编为: {zip_code}")
# 点击地址选择按钮
location_link = self.tab.ele('xpath://a[@id="nav-global-location-popover-link"]', timeout=10)
if not location_link:
print("找不到地址设置按钮")
return False
location_link.click()
time.sleep(1)
# 等待邮编输入框出现
zip_input = self.tab.ele('xpath://input[@id="GLUXZipUpdateInput"]', timeout=10)
if not zip_input:
print("找不到邮编输入框")
return False
# 输入邮编
zip_input.input(zip_code, clear=True)
time.sleep(0.5)
# 点击提交按钮
submit_btn = self.tab.ele('xpath://input[@aria-labelledby="GLUXZipUpdate-announce"]', timeout=10)
if not submit_btn:
print("找不到提交按钮")
return False
submit_btn.click()
# 等待提交按钮消失(表示请求已发送)
print("等待邮编更新...")
time.sleep(2)
# 等待页面加载完成
self.tab.wait.doc_loaded(timeout=30, raise_err=False)
time.sleep(2)
# 验证邮编是否设置成功
zip_display_after = self.tab.ele('xpath://div[@id="glow-ingress-block"]', timeout=10)
if zip_display_after:
updated_text = zip_display_after.text
print(f"更新后的地址信息: {updated_text}")
if zip_code in updated_text:
print(f"邮编设置成功: {zip_code}")
return True
else:
print(f"邮编设置可能失败,当前显示: {updated_text}")
return False
return True
except Exception as e:
print(f"设置邮编时出错: {traceback.format_exc()}")
return False
def _scrape_data(self):
"""
抓取商品数据
Returns:
dict: 抓取到的数据
"""
data = {
'top_sellers': [], # 前两名卖家信息
'cart_seller': None # 购物车所属卖家
}
try:
# 等待页面加载
time.sleep(3)
# 1. 获取前两名卖家的价格和库存(来自 sellersprite 插件)
print("正在抓取卖家排名数据...")
surplus_tables = self.tab.eles(
'xpath://div[@id="sellersprite-extension-Inventory-surplus-count"]//div[@class="surplus-table"]',
timeout=10
)
if surplus_tables:
print(f"找到 {len(surplus_tables)} 个卖家数据")
# 只获取前两个
for idx, table in enumerate(surplus_tables[:2]):
try:
# 提取价格和库存信息
# 注意需要根据实际的HTML结构调整选择器
text_content = table.text
print(f"{idx+1}名卖家数据: {text_content}")
seller_info = {
'rank': idx + 1,
'raw_data': text_content
}
# 尝试提取更结构化的数据
# 这里需要根据实际HTML结构来解析
# 可能需要查找子元素
try:
# 示例:查找价格和库存的具体子节点
price_ele = table.ele('xpath:.//span[contains(@class,"price")]', timeout=2)
stock_ele = table.ele('xpath:.//span[contains(@class,"stock")]', timeout=2)
if price_ele:
seller_info['price'] = price_ele.text.strip()
if stock_ele:
seller_info['stock'] = stock_ele.text.strip()
except:
# 如果找不到具体元素,就使用原始文本
pass
data['top_sellers'].append(seller_info)
except Exception as e:
print(f"解析第{idx+1}名卖家数据失败: {str(e)}")
else:
print("未找到 sellersprite 插件数据,可能插件未启用")
# 2. 获取购物车所属卖家
print("正在抓取购物车卖家信息...")
cart_seller = self.tab.ele(
'xpath://div[@data-csa-c-content-id="desktop-merchant-info"]//a[@id="sellerProfileTriggerId"]',
timeout=10
)
if cart_seller:
seller_name = cart_seller.text.strip()
print(f"购物车所属卖家: {seller_name}")
data['cart_seller'] = seller_name
else:
print("未找到购物车卖家信息")
# 尝试其他可能的选择器
try:
alt_seller = self.tab.ele('xpath://a[@id="sellerProfileTriggerId"]', timeout=5)
if alt_seller:
data['cart_seller'] = alt_seller.text.strip()
print(f"购物车所属卖家(备用方式): {data['cart_seller']}")
except:
pass
return data
except Exception as e:
print(f"抓取数据时出错: {traceback.format_exc()}")
return data
def close(self):
"""关闭浏览器"""
try:
if self.browser:
self.browser.quit()
print("浏览器已关闭")
except Exception as e:
print(f"关闭浏览器时出错: {str(e)}")
class AmzonePriceMatch(AmamzonBase):
mark_name = "跟价"
pass
if __name__ == '__main__':
# 使用示例
print("=" * 50)
print("亚马逊详情采集示例")
print("=" * 50)
try:
# 创建ChromeAmzone实例
chrome = ChromeAmzone()
# 示例1采集英国站点的商品信息
print("\n示例1采集英国站点商品")
result1 = chrome.run(country="英国", asin="B0CJ8SNXXV")
if result1:
print(f"采集成功: {result1}")
# 示例2采集德国站点的商品信息
print("\n示例2采集德国站点商品")
result2 = chrome.run(country="德国", asin="B0CC8CW9G2")
if result2:
print(f"采集成功: {result2}")
# 关闭浏览器
print("\n正在关闭浏览器...")
chrome.close()
except Exception as e:
print(f"运行出错: {traceback.format_exc()}")