Files
crawler-plugin/app/amazon/price_match.py
铭坤 f87c37528b modified: amazon/match_action.py
modified:   amazon/price_match.py
	modified:   config.py
2026-04-19 00:18:28 +08:00

365 lines
13 KiB
Python
Raw 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.
import time
import re
import traceback
from datetime import datetime
from DrissionPage import Chromium, ChromiumOptions
from amazon.del_brand import AmamzonBase, kill_process
from amazon.tool import show_notification,get_shop_info
from config import runing_task, runing_shop,base_dir
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)
print("正在启动Chrome浏览器...")
# sellersprite_plug_path = os.path.join(base_dir,"app_resource","sellersprite-extension-mv3")
sellersprite_plug_path = os.path.join("D:\\私单交付\\maixiang_AI\\","app_resource","sellersprite-extension-mv3")
print(sellersprite_plug_path)
# 配置浏览器选项
co = ChromiumOptions()
# co.use_system_user_path(on_off=True)
co.set_user_data_path(r"D:\私单交付\maixiang_AI\user_data\chrome_data")
co.set_local_port(port=19890)
co.add_extension(sellersprite_plug_path)
# co.set_argument('--disable-features=DisableLoadExtensionCommandLineSwitch')
# co.set_argument('--load-extension',sellersprite_plug_path)
co.set_browser_path(r'D:\私单交付\maixiang_AI\app_resource\chrome-win\chrome.exe')
# 使用系统默认的用户数据目录
# 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 close_init_popup(self):
"""
关闭所有的初始化弹窗
"""
self.tab.wait.doc_loaded(timeout=60,raise_err=True)
footbar = self.tab.eles('xpath://footer[@class="el-dialog__footer"]',timeout=5)
if len(footbar) > 0:
do_not_remind = footbar[0].eles('xpath:.//input[@class="el-checkbox__original"]')
if len(do_not_remind) > 0:
do_not_remind[0].check()
resume_immediately = footbar[0].eles('xpath:.//button')
if len(resume_immediately) > 0:
resume_immediately[0].click()
self.tab.wait.doc_loaded(timeout=60,raise_err=True)
accept_btn = self.tab.eles('xpath://input[@id="sp-cc-accept"]',timeout=10)
if len(accept_btn) > 0:
accept_btn[0].click()
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)
self.close_init_popup()
# 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()}")