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
334 lines
12 KiB
Python
334 lines
12 KiB
Python
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()}")
|
||
|
||
|
||
|