初始化
This commit is contained in:
4
lib/__init__.py
Normal file
4
lib/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
from core import browsers
|
||||
from lib.module import example
|
||||
|
||||
Server: example.SpiderModule
|
||||
BIN
lib/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
lib/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
lib/__pycache__/get_goods.cpython-312.pyc
Normal file
BIN
lib/__pycache__/get_goods.cpython-312.pyc
Normal file
Binary file not shown.
BIN
lib/__pycache__/gether.cpython-312.pyc
Normal file
BIN
lib/__pycache__/gether.cpython-312.pyc
Normal file
Binary file not shown.
BIN
lib/__pycache__/shopyy.cpython-312.pyc
Normal file
BIN
lib/__pycache__/shopyy.cpython-312.pyc
Normal file
Binary file not shown.
BIN
lib/__pycache__/shopyy_verify.cpython-312.pyc
Normal file
BIN
lib/__pycache__/shopyy_verify.cpython-312.pyc
Normal file
Binary file not shown.
131
lib/gether.py
Normal file
131
lib/gether.py
Normal file
@@ -0,0 +1,131 @@
|
||||
import os
|
||||
import traceback
|
||||
import concurrent.futures
|
||||
from utils import files, messages, clash, formats
|
||||
import lib
|
||||
from core import Config, types
|
||||
from lib.model import goods
|
||||
|
||||
def get_category_urls():
|
||||
category_urls_path = f"{lib.Server.__urls_folder__}/categorys.txt"
|
||||
if os.path.exists(category_urls_path):
|
||||
return
|
||||
|
||||
category_urls = lib.Server.get_category_urls()
|
||||
for urls in category_urls:
|
||||
if 'http' not in urls:
|
||||
continue
|
||||
files.save_line(category_urls_path, urls)
|
||||
|
||||
def get_goods_urls(categorys_len: int = 3):
|
||||
goods_urls_path = f"{lib.Server.__urls_folder__}/goods.txt"
|
||||
category_urls_path = f"{lib.Server.__urls_folder__}/categorys.txt"
|
||||
if Config.home_mode:
|
||||
goods_urls_path = goods_urls_path.replace('.txt', '(home).txt')
|
||||
category_urls_path = category_urls_path.replace('.txt', '(home).txt')
|
||||
|
||||
category_index = {}
|
||||
category_urls = files.load_lines(category_urls_path)
|
||||
|
||||
if os.path.exists(goods_urls_path):
|
||||
old_goods_urls = files.load_lines(goods_urls_path)
|
||||
for old_goods_url in old_goods_urls:
|
||||
category = old_goods_url.split('#')[-1]
|
||||
category_index[category] = None
|
||||
|
||||
index = 0
|
||||
max_len = len(category_urls)
|
||||
for category_url in category_urls:
|
||||
category = category_url.split('#')[-1]
|
||||
category_url = '#'.join(category_url.split('#')[:-1])
|
||||
|
||||
index += 1
|
||||
if 'https' not in category_url:
|
||||
continue
|
||||
if Config.skip_category and Config.home_mode == False and len(category.split('/')) < categorys_len:
|
||||
continue
|
||||
if category in category_index:
|
||||
continue
|
||||
|
||||
try:
|
||||
goods_urls = lib.Server.get_goods_urls(category_url)
|
||||
goods_category_urls = []
|
||||
for goods_url in goods_urls:
|
||||
goods_category_urls.append(f"{goods_url}#{category}")
|
||||
|
||||
files.add_list(goods_urls_path, goods_category_urls)
|
||||
except Exception as e:
|
||||
files.add_text(f"{lib.Server.__errors_folder__}/category_errors.log", f"{category_url}:\n[{e}] {traceback.format_exc()}")
|
||||
messages.sendError(str(e))
|
||||
messages.sendInfo(f"{index}/{max_len} {len(goods_urls)}条")
|
||||
if Config.home_mode == False:
|
||||
formats.de_repeat_urls(goods_urls_path)
|
||||
|
||||
def get_goods_info():
|
||||
p_urls = {}
|
||||
def workers(goods_urls, index):
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=lib.Server.worker_num) as executor:
|
||||
futures = []
|
||||
for goods_url in goods_urls:
|
||||
if goods_url in p_urls:
|
||||
continue
|
||||
future = executor.submit(lib.Server.get_goods_info, goods_url)
|
||||
futures.append(future)
|
||||
|
||||
results: list[types.GoodsInfo] = []
|
||||
for future_index, future in enumerate(futures):
|
||||
index += 1
|
||||
try:
|
||||
result = future.result() # 阻塞直到该任务完成
|
||||
except Exception as e:
|
||||
try:
|
||||
files.add_text(f"{lib.Server.__errors_folder__}/goods_errors.log", f"{goods_urls[future_index]}:\n[{e}] {traceback.format_exc()}")
|
||||
except:
|
||||
pass
|
||||
messages.sendWarn(f"{goods_urls[future_index]} 出错")
|
||||
continue
|
||||
|
||||
results.append(result)
|
||||
messages.sendInfo(f"{index}/{max_len}")
|
||||
|
||||
for goods_info in results:
|
||||
try:
|
||||
GoodsModel.add_goods(*goods_info.to_db_data())
|
||||
for p_url in goods_info.p_urls:
|
||||
p_urls[p_url] = None
|
||||
except Exception as e:
|
||||
messages.sendWarn(f"{e}")
|
||||
|
||||
return index
|
||||
|
||||
goods_urls = files.load_lines(f"{lib.Server.__urls_folder__}/goods.txt")
|
||||
messages.sendInfo('读取url完成')
|
||||
|
||||
messages.sendInfo('读取上次存档')
|
||||
GoodsModel = goods.GoodsModel(lib.Server.__database_path__)
|
||||
excel_index = GoodsModel.select_goods_to_dict()
|
||||
messages.sendInfo('读取完成')
|
||||
|
||||
de_save_url = []
|
||||
for goods_url in goods_urls:
|
||||
if goods_url in excel_index:
|
||||
continue
|
||||
if 'http' not in goods_url:
|
||||
continue
|
||||
de_save_url.append(goods_url)
|
||||
goods_urls = de_save_url
|
||||
del excel_index
|
||||
|
||||
max_len = len(goods_urls)
|
||||
index = 1
|
||||
for i in range(0, len(goods_urls), lib.Server.bitch):
|
||||
index = workers(goods_urls=goods_urls[i:i+lib.Server.bitch], index=index)
|
||||
if lib.Server.switch_clash:
|
||||
try:
|
||||
clash.change_proxy()
|
||||
except:
|
||||
pass
|
||||
if lib.Server.reflush_browsers:
|
||||
if lib.Server.worker_num > 1:
|
||||
lib.Server.reflush_browser()
|
||||
messages.sendInfo("已保存")
|
||||
BIN
lib/model/__pycache__/goods.cpython-312.pyc
Normal file
BIN
lib/model/__pycache__/goods.cpython-312.pyc
Normal file
Binary file not shown.
417
lib/model/goods.py
Normal file
417
lib/model/goods.py
Normal file
@@ -0,0 +1,417 @@
|
||||
#############################################################################
|
||||
|
||||
# Author: Cerys
|
||||
# Update: 2026-02-06
|
||||
|
||||
#############################################################################
|
||||
|
||||
import os
|
||||
import orjson
|
||||
from core import excels, types
|
||||
from utils import db, messages, files, formats
|
||||
|
||||
class GoodsModel:
|
||||
def __init__(self, db_path: str):
|
||||
"""
|
||||
商品模型
|
||||
|
||||
:param db_path: 数据库文件路径(不存在则自动创建并初始化表)
|
||||
|
||||
"""
|
||||
self.__source_folder__ = "sources"
|
||||
|
||||
create_table = False
|
||||
if os.path.exists(db_path) == False:
|
||||
create_table = True
|
||||
|
||||
self.Db = db.Db(db_path)
|
||||
if create_table:
|
||||
self.__create_table__()
|
||||
|
||||
def __create_table__(self):
|
||||
table_sql = '''
|
||||
PRAGMA foreign_keys = false;
|
||||
|
||||
DROP TABLE IF EXISTS "goods";
|
||||
CREATE TABLE "goods" (
|
||||
"spu" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"brand" TEXT,
|
||||
"attr" TEXT NOT NULL,
|
||||
"desc" TEXT,
|
||||
"item1" TEXT,
|
||||
"item2" TEXT,
|
||||
"item3" TEXT,
|
||||
"price" NUMBER NOT NULL,
|
||||
"old_price" NUMBER NOT NULL,
|
||||
"images" blob NOT NULL,
|
||||
"url" TEXT NOT NULL,
|
||||
"other_data" blob DEFAULT "{}",
|
||||
PRIMARY KEY ("spu")
|
||||
);
|
||||
|
||||
DROP TABLE IF EXISTS "goods_son";
|
||||
CREATE TABLE "goods_son" (
|
||||
"spu" TEXT NOT NULL,
|
||||
"item1" TEXT,
|
||||
"item2" TEXT,
|
||||
"item3" TEXT,
|
||||
"price" NUMBER NOT NULL,
|
||||
"old_price" NUMBER NOT NULL,
|
||||
"images" blob NOT NULL,
|
||||
"url" TEXT,
|
||||
"other_data" blob DEFAULT "{}"
|
||||
);
|
||||
|
||||
CREATE INDEX "search_spu"
|
||||
ON "goods_son" (
|
||||
"spu" ASC
|
||||
);
|
||||
|
||||
PRAGMA foreign_keys = true;
|
||||
'''
|
||||
self.Db.execute_script(table_sql)
|
||||
|
||||
def add_goods(self, main_info: dict, son_infos: list = []):
|
||||
"""
|
||||
添加商品
|
||||
|
||||
:param main_info: 主表信息
|
||||
:param son_infos: 变体信息列表
|
||||
|
||||
"""
|
||||
if main_info['attr'] == 'M' and len(son_infos) == 0:
|
||||
raise Exception(f"变体丢失 {main_info}")
|
||||
if len(main_info['images']) == 0:
|
||||
raise Exception('无图片')
|
||||
|
||||
self.Db.table('goods').insert(main_info, True)
|
||||
self.Db.table('goods_son').insert_all(son_infos)
|
||||
|
||||
def is_repeat(self, url):
|
||||
"""
|
||||
判断是否需要合并
|
||||
|
||||
:param url: 商品链接
|
||||
|
||||
"""
|
||||
count = self.Db.table('goods_son').where('url', url).count()
|
||||
if count > 1:
|
||||
return True
|
||||
return False
|
||||
|
||||
def select_goods_to_lists(self) -> list[dict]:
|
||||
"""获取商品列表(包含变体)"""
|
||||
messages.sendInfo('开始查询')
|
||||
db_data = self.Db.table('goods').join('goods_son', 'goods.spu = goods_son.spu').select(
|
||||
'''
|
||||
goods.spu,
|
||||
goods.title,
|
||||
goods.brand,
|
||||
goods.attr,
|
||||
goods.desc,
|
||||
goods.item1 as main_item1,
|
||||
goods.item2 as main_item2,
|
||||
goods.item3 as main_item3,
|
||||
goods.price,
|
||||
goods.old_price,
|
||||
goods.images,
|
||||
goods.url,
|
||||
goods.other_data,
|
||||
goods_son.item1 as son_item1,
|
||||
goods_son.item2 as son_item2,
|
||||
goods_son.item3 as son_item3,
|
||||
goods_son.price as son_price,
|
||||
goods_son.old_price as son_old_price,
|
||||
goods_son.images as son_images,
|
||||
goods_son.url as son_url,
|
||||
goods_son.other_data as son_other_data
|
||||
'''
|
||||
)
|
||||
messages.sendInfo('查询完成')
|
||||
return db_data
|
||||
|
||||
def select_goods_to_dict(self, key: str = 'url') -> dict:
|
||||
"""
|
||||
获取商品列表并转换为字典格式
|
||||
|
||||
:param key: 字典的键
|
||||
|
||||
"""
|
||||
db_data = self.select_goods_to_lists()
|
||||
dict_data = {}
|
||||
for item in db_data:
|
||||
if item[key] in dict_data:
|
||||
dict_data[item[key]]['son_lists'].append({
|
||||
'attr_items': [item['son_item1'], item['son_item2'], item['son_item3']],
|
||||
'price': item['son_price'],
|
||||
'old_price': item['son_old_price'],
|
||||
'images': orjson.loads(item['son_images']),
|
||||
'url': item['son_url'],
|
||||
'son_other_data': orjson.loads(item['son_other_data'])
|
||||
})
|
||||
else:
|
||||
dict_data[item[key]] = {
|
||||
'spu': item['spu'],
|
||||
'title': item['title'],
|
||||
'brand': item['brand'],
|
||||
'desc': item['desc'],
|
||||
'attr': item['attr'],
|
||||
'attr_items': [item['main_item1'], item['main_item2'], item['main_item3']],
|
||||
'price': item['price'],
|
||||
'old_price': item['old_price'],
|
||||
'images': orjson.loads(item['images']),
|
||||
'url': item['url'],
|
||||
'other_data': orjson.loads(item['other_data'])
|
||||
}
|
||||
if item['attr'] == 'M':
|
||||
if item['son_price'] == None:
|
||||
continue
|
||||
dict_data[item[key]]['son_lists'] = [
|
||||
{
|
||||
'attr_items': [item['son_item1'], item['son_item2'], item['son_item3']],
|
||||
'price': item['son_price'],
|
||||
'old_price': item['son_old_price'],
|
||||
'images': orjson.loads(item['son_images']),
|
||||
'url': item['son_url'],
|
||||
'son_other_data': orjson.loads(item['son_other_data'])
|
||||
}
|
||||
]
|
||||
return dict_data
|
||||
|
||||
def select_goods_to_goodsinfo(self) -> list[types.GoodsInfo]:
|
||||
"""获取商品列表并转换为GoodsInfo对象列表"""
|
||||
db_data = self.select_goods_to_lists()
|
||||
index_data = {}
|
||||
for item in db_data:
|
||||
if item['spu'] in index_data:
|
||||
index_data[item['spu']].p_lists.append(
|
||||
types.GoodsInfo.GoodsInfoP(
|
||||
attr_items = [item['son_item1'], item['son_item2'], item['son_item3']],
|
||||
price = item['son_price'],
|
||||
old_price = item['son_old_price'],
|
||||
images = orjson.loads(item['son_images']),
|
||||
url = item['son_url'],
|
||||
other_data = orjson.loads(item['son_other_data'])
|
||||
)
|
||||
)
|
||||
else:
|
||||
try:
|
||||
index_data[item['spu']] = types.GoodsInfo(
|
||||
spu = item['spu'],
|
||||
title = item['title'],
|
||||
brand = item['brand'],
|
||||
attr = item['attr'],
|
||||
desc = item['desc'],
|
||||
attr_items = [item['main_item1'], item['main_item2'], item['main_item3']],
|
||||
price = item['price'],
|
||||
old_price = item['old_price'],
|
||||
images = orjson.loads(item['images']),
|
||||
url = item['url'],
|
||||
other_data = orjson.loads(item['other_data'])
|
||||
)
|
||||
if item['attr'] == 'M':
|
||||
index_data[item['spu']].p_lists.append(
|
||||
types.GoodsInfo.GoodsInfoP(
|
||||
attr_items = [item['son_item1'], item['son_item2'], item['son_item3']],
|
||||
price = item['son_price'],
|
||||
old_price = item['son_old_price'],
|
||||
images = orjson.loads(item['son_images']),
|
||||
url = item['son_url'],
|
||||
other_data = orjson.loads(item['son_other_data'])
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
messages.sendError(e)
|
||||
return list(index_data.values())
|
||||
|
||||
def to_amazon_xlsx(self, goods_url_path: str, save_path: str):
|
||||
"""
|
||||
整数据库导出为亚马逊导入表格
|
||||
|
||||
:param save_path: 保存路径
|
||||
:param goods_url_path: 未去重商品链接路径
|
||||
|
||||
"""
|
||||
goods_data = self.select_goods_to_dict()
|
||||
goods_urls = files.load_lines(goods_url_path)
|
||||
WookBook = excels.WorkBook(
|
||||
f'{self.__source_folder__}/amazon商品模板.xlsx',
|
||||
save_path
|
||||
)
|
||||
|
||||
for goods_url in goods_urls:
|
||||
key = '#'.join(goods_url.split('#')[:-1])
|
||||
if key not in goods_data:
|
||||
continue
|
||||
|
||||
spu = formats.url_to_spu(key)
|
||||
category = goods_url.split('#')[-1]
|
||||
|
||||
WookBook.add_row_of_list([
|
||||
goods_data[key]['title'],
|
||||
spu,
|
||||
goods_data[key]['other_data']['popover'],
|
||||
goods_data[key]['other_data']['popover_num'],
|
||||
0,
|
||||
goods_data[key]['price'],
|
||||
goods_data[key]['old_price'],
|
||||
orjson.dumps(goods_data[key]['images']),
|
||||
goods_data[key]['url'],
|
||||
category
|
||||
])
|
||||
|
||||
# for goods_info in goods_info_data:
|
||||
# WookBook.add_row_of_list([
|
||||
# goods_info.title,
|
||||
# goods_info.price,
|
||||
# goods_info.images[0],
|
||||
# goods_info.other_data['popover'],
|
||||
# goods_info.other_data['popover_num'],
|
||||
# goods_info.url,
|
||||
# orjson.dumps(goods_info.images)
|
||||
# ])
|
||||
|
||||
WookBook.save()
|
||||
WookBook.close()
|
||||
|
||||
def to_shopyy_xlsx(self, save_path: str, save_bitch: int = 150000, shift_urls_path: str = ''):
|
||||
"""
|
||||
整数据库导出为Shopyy导入表格
|
||||
|
||||
:param save_path: 保存路径
|
||||
:param repeat: 是否合并商品
|
||||
:param save_bitch: 超过多少行时自动分割
|
||||
|
||||
"""
|
||||
def get_wookbook(bitch_index: int):
|
||||
return excels.WorkBook(
|
||||
f'{self.__source_folder__}/shopyy商品模板.xlsx',
|
||||
save_path.replace('.xlsx', f'_{bitch_index}.xlsx')
|
||||
)
|
||||
|
||||
def get_shift_url():
|
||||
shift_urls = {}
|
||||
if shift_urls_path:
|
||||
urls = files.load_lines(shift_urls_path)
|
||||
for url in urls:
|
||||
if url == '':
|
||||
continue
|
||||
shift_urls[url] = None
|
||||
return shift_urls
|
||||
|
||||
goods_info_data = self.select_goods_to_goodsinfo()
|
||||
bitch = 1
|
||||
shift_urls = get_shift_url()
|
||||
WookBook = get_wookbook(bitch)
|
||||
|
||||
count = len(goods_info_data)
|
||||
for index, goods_info in enumerate(goods_info_data):
|
||||
messages.sendInfo(f"{index}/{count}")
|
||||
if shift_urls_path and goods_info.url not in shift_urls:
|
||||
continue
|
||||
|
||||
rows_data = goods_info.to_shopyy_row_data()
|
||||
for row_data in rows_data:
|
||||
WookBook.add_row_of_list(row_data)
|
||||
if WookBook.start_row > save_bitch:
|
||||
WookBook.save()
|
||||
WookBook.close()
|
||||
bitch += 1
|
||||
WookBook = get_wookbook(bitch)
|
||||
|
||||
WookBook.save()
|
||||
WookBook.close()
|
||||
|
||||
def to_woo_csv(self, goods_url_path: str, save_path: str):
|
||||
"""
|
||||
整数据库导出为woo商品CSV表格
|
||||
|
||||
:param goods_url_path: 未去重链接txt路径
|
||||
:param save_path: 保存路径
|
||||
|
||||
"""
|
||||
goods_urls = files.load_lines(goods_url_path)
|
||||
category_data = {}
|
||||
for goods_url in goods_urls:
|
||||
category_name = goods_url.split('#')[-1].replace('/', '>')
|
||||
goods_url = '#'.join(goods_url.split('#')[:-1])
|
||||
category_data[goods_url] = category_name
|
||||
goods_info_data = self.select_goods_to_goodsinfo()
|
||||
|
||||
bitch = 0
|
||||
save_data = []
|
||||
for goods_info in goods_info_data:
|
||||
rows_data = goods_info.to_woo_row_data(category_data[goods_info.url])
|
||||
save_data += rows_data
|
||||
if len(save_data) > 10000:
|
||||
excels.save_lists_to_csv(save_data, save_path.replace('.csv', f"{bitch}.csv"), r'sources\woo商品模板.csv')
|
||||
save_data = []
|
||||
bitch += 1
|
||||
excels.save_lists_to_csv(save_data, save_path.replace('.csv', f"{bitch}.csv"), r'sources\woo商品模板.csv')
|
||||
|
||||
def import_shopyy_xlsx(self, excel_path: str):
|
||||
"""
|
||||
导入shopyy表格为数据库数据
|
||||
|
||||
:param excel_path: 表格路径
|
||||
"""
|
||||
shopyy_data = excels.read_excel_to_dict(excel_path)
|
||||
for url, main_goods_info in shopyy_data.items():
|
||||
main_info = {
|
||||
'spu': main_goods_info.spu,
|
||||
'title': main_goods_info.title,
|
||||
'brand': main_goods_info.category_name,
|
||||
'attr': main_goods_info.attribute,
|
||||
'desc': main_goods_info.desc,
|
||||
'price': main_goods_info.price,
|
||||
'old_price': main_goods_info.old_price,
|
||||
'images': orjson.dumps(main_goods_info.images),
|
||||
'url': main_goods_info.url,
|
||||
'other_data': orjson.dumps({})
|
||||
}
|
||||
for index, item_name in enumerate(main_goods_info.attribute_items):
|
||||
if item_name:
|
||||
main_info[f"item{index+1}"] = item_name
|
||||
|
||||
son_infos = []
|
||||
for p_info in main_goods_info.p_lists:
|
||||
item = {
|
||||
'spu': p_info.spu,
|
||||
'price': p_info.price,
|
||||
'old_price': p_info.old_price,
|
||||
'images': orjson.dumps(p_info.images),
|
||||
'url': p_info.url,
|
||||
'other_data': orjson.dumps({}),
|
||||
'item1': None,
|
||||
'item2': None,
|
||||
'item3': None
|
||||
}
|
||||
for index, item_name in enumerate(p_info.attribute_items):
|
||||
if item_name:
|
||||
item[f"item{index+1}"] = item_name
|
||||
son_infos.append(item)
|
||||
|
||||
self.add_goods(main_info, son_infos)
|
||||
|
||||
def splice_db(self, db_folder: str):
|
||||
"""
|
||||
拼接指定文件夹下所有数据库文件
|
||||
|
||||
:param db_folder: 数据库文件夹路径
|
||||
|
||||
"""
|
||||
db_lists = os.listdir(db_folder)
|
||||
db_index = self.select_goods_to_dict()
|
||||
for db_name in db_lists:
|
||||
splice_db = GoodsModel(f"{db_folder}/{db_name}")
|
||||
goods_lists = splice_db.select_goods_to_goodsinfo()
|
||||
for goods_info in goods_lists:
|
||||
if goods_info.url in db_index:
|
||||
continue
|
||||
try:
|
||||
self.add_goods(*goods_info.to_db_data())
|
||||
except Exception as e:
|
||||
messages.sendError(f"{e} {goods_info.spu}")
|
||||
db_index[goods_info.url] = None
|
||||
messages.sendInfo(db_name)
|
||||
BIN
lib/module/__pycache__/agatameble.cpython-312.pyc
Normal file
BIN
lib/module/__pycache__/agatameble.cpython-312.pyc
Normal file
Binary file not shown.
BIN
lib/module/__pycache__/ancientnutrition.cpython-312.pyc
Normal file
BIN
lib/module/__pycache__/ancientnutrition.cpython-312.pyc
Normal file
Binary file not shown.
BIN
lib/module/__pycache__/bricomarche.cpython-312.pyc
Normal file
BIN
lib/module/__pycache__/bricomarche.cpython-312.pyc
Normal file
Binary file not shown.
BIN
lib/module/__pycache__/condom69.cpython-312.pyc
Normal file
BIN
lib/module/__pycache__/condom69.cpython-312.pyc
Normal file
Binary file not shown.
BIN
lib/module/__pycache__/dk_one.cpython-312.pyc
Normal file
BIN
lib/module/__pycache__/dk_one.cpython-312.pyc
Normal file
Binary file not shown.
BIN
lib/module/__pycache__/example.cpython-312.pyc
Normal file
BIN
lib/module/__pycache__/example.cpython-312.pyc
Normal file
Binary file not shown.
BIN
lib/module/__pycache__/friskybusiness.cpython-312.pyc
Normal file
BIN
lib/module/__pycache__/friskybusiness.cpython-312.pyc
Normal file
Binary file not shown.
BIN
lib/module/__pycache__/peek_cloppenburg.cpython-312.pyc
Normal file
BIN
lib/module/__pycache__/peek_cloppenburg.cpython-312.pyc
Normal file
Binary file not shown.
BIN
lib/module/__pycache__/peek_cloppenburg_nl.cpython-312.pyc
Normal file
BIN
lib/module/__pycache__/peek_cloppenburg_nl.cpython-312.pyc
Normal file
Binary file not shown.
BIN
lib/module/__pycache__/ssfshop.cpython-312.pyc
Normal file
BIN
lib/module/__pycache__/ssfshop.cpython-312.pyc
Normal file
Binary file not shown.
BIN
lib/module/__pycache__/taketoys.cpython-312.pyc
Normal file
BIN
lib/module/__pycache__/taketoys.cpython-312.pyc
Normal file
Binary file not shown.
BIN
lib/module/__pycache__/tfashion.cpython-312.pyc
Normal file
BIN
lib/module/__pycache__/tfashion.cpython-312.pyc
Normal file
Binary file not shown.
176
lib/module/agatameble.py
Normal file
176
lib/module/agatameble.py
Normal file
@@ -0,0 +1,176 @@
|
||||
from core import spiders, types
|
||||
from utils import formats, messages
|
||||
|
||||
class SpiderModule(spiders.Spiders):
|
||||
project_name = "agatameble"
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
self.project_name,
|
||||
bitch = 30,
|
||||
worker_num = 1,
|
||||
switch_clash = False,
|
||||
reflush_browser = False
|
||||
)
|
||||
|
||||
def get_category_urls(self) -> list[str]:
|
||||
category_urls = []
|
||||
|
||||
self.tab.get('https://www.agatameble.pl/')
|
||||
one_menu_eles = self.tab.eles('xpath=//*[@id="root"]/main/div[5]/div[3]/nav/div')
|
||||
for one_menu_ele in one_menu_eles:
|
||||
one_link_ele = one_menu_ele.ele('@tag()=a')
|
||||
one_url = one_link_ele.attr('href')
|
||||
one_name = one_link_ele.text.replace('/', '-')
|
||||
category_urls.append(f"{one_url}#{one_name}")
|
||||
messages.sendInfo(one_name)
|
||||
|
||||
two_menu_eles = one_menu_ele.eles('xpath=div/div[1]/div')
|
||||
for two_menu_ele in two_menu_eles:
|
||||
two_link_ele = two_menu_ele.ele('@tag()=a')
|
||||
two_url = two_link_ele.attr('href')
|
||||
two_name = two_link_ele.text.replace('/', '-')
|
||||
category_urls.append(f"{two_url}#{one_name}/{two_name}")
|
||||
|
||||
three_menu_eles = two_menu_ele.eles('xpath=ul/li')
|
||||
for three_menu_ele in three_menu_eles:
|
||||
three_link_ele = three_menu_ele.ele('@tag()=a')
|
||||
three_url = three_link_ele.attr('href')
|
||||
three_name = three_link_ele.text.replace('/', '-')
|
||||
category_urls.append(f"{three_url}#{one_name}/{two_name}/{three_name}")
|
||||
|
||||
return category_urls
|
||||
|
||||
def get_goods_urls(self, category_url: str) -> list[str]:
|
||||
self.tab.get(f"{category_url}")
|
||||
goods_urls = []
|
||||
|
||||
while True:
|
||||
try:
|
||||
self.tab.scroll.to_bottom()
|
||||
self.tab.ele('xpath=//*[@id="contentContainer"]/div/article/div[2]/div[2]/div/div/a').click()
|
||||
except:
|
||||
break
|
||||
|
||||
goods_eles = self.tab.eles('xpath=//*[@id="contentContainer"]/div/article/div[2]/div[2]/section/div/div/div')
|
||||
for goods_ele in goods_eles:
|
||||
goods_link_ele = goods_ele.ele('xpath=a')
|
||||
goods_urls.append(goods_link_ele.attr('href'))
|
||||
|
||||
return goods_urls
|
||||
|
||||
def get_goods_info(self, url) -> types.GoodsInfo:
|
||||
def get_image_urls():
|
||||
image_urls = []
|
||||
|
||||
tab.ele('xpath=//*[@id="contentContainer"]/form/div[1]/section/div/div[2]/button[1]').click()
|
||||
image_eles = tab.eles('xpath=//*[@id="root"]/div/section/div[2]/div/aside/div[2]/div/div/div/div[1]/div/div/div/div')
|
||||
for image_ele in image_eles:
|
||||
image_link_ele = image_ele.ele('xpath=div/img[2]')
|
||||
image_urls.append(image_link_ele.attr('src').replace('width=', '').replace('height=', ''))
|
||||
|
||||
return image_urls
|
||||
|
||||
tab = self.browser.new_tab(url)
|
||||
tab.set.window.max()
|
||||
spu = formats.url_to_spu(url)
|
||||
|
||||
try:
|
||||
brand = ''
|
||||
try:
|
||||
brand = tab.ele('xpath=//*[@id="contentContainer"]/form/div[2]/div[1]/h1/div[1]', timeout=10).text
|
||||
except:
|
||||
pass
|
||||
if brand == '':
|
||||
title = tab.ele('xpath=//*[@id="contentContainer"]/form/div[2]/div[1]/h1').text
|
||||
else:
|
||||
title = tab.ele('xpath=//*[@id="contentContainer"]/form/div[2]/div[1]/h1/div[2]').text
|
||||
|
||||
desc = ""
|
||||
desc_eles = tab.eles('xpath=//*[@id="contentContainer"]/form/div[1]/div/div')[:3]
|
||||
for desc_ele in desc_eles:
|
||||
desc += formats.clean_html(desc_ele.html)
|
||||
|
||||
price = float(f"{tab.ele('xpath=//*[@id="contentContainer"]/form/div[2]/section[2]/div[1]/div[2]/span[1]').text}.{tab.ele('xpath=//*[@id="contentContainer"]/form/div[2]/section[2]/div[1]/div[2]/span[3]').text}")
|
||||
old_price = price
|
||||
|
||||
main_images = get_image_urls()
|
||||
|
||||
goods_info = types.GoodsInfo(
|
||||
title=title,
|
||||
desc=desc,
|
||||
brand=brand,
|
||||
url=url,
|
||||
spu=spu,
|
||||
price=price,
|
||||
old_price=old_price,
|
||||
)
|
||||
|
||||
m_data = []
|
||||
attr_items = []
|
||||
color_urls = [url]
|
||||
color_eles = tab.eles('xpath=//*[@id="contentContainer"]/form/div[2]/div[2]/div/ul/li')
|
||||
for color_ele in color_eles[1:]:
|
||||
color_link_ele = color_ele.ele('xpath=a')
|
||||
color_urls.append(color_link_ele.attr('href'))
|
||||
if len(color_urls) > 1:
|
||||
m_data = ["Color"]
|
||||
|
||||
if len(color_urls) > 1:
|
||||
for color_url in color_urls:
|
||||
color_images = main_images
|
||||
if color_url != url:
|
||||
tab.get(color_url)
|
||||
if brand == '':
|
||||
title = tab.ele('xpath=//*[@id="contentContainer"]/form/div[2]/div[1]/h1').text
|
||||
else:
|
||||
title = tab.ele('xpath=//*[@id="contentContainer"]/form/div[2]/div[1]/h1/div[2]').text
|
||||
color_images = get_image_urls()
|
||||
|
||||
price = float(f"{tab.ele('xpath=//*[@id="contentContainer"]/form/div[2]/section[2]/div[1]/div[2]/span[1]').text}.{tab.ele('xpath=//*[@id="contentContainer"]/form/div[2]/section[2]/div[1]/div[2]/span[3]').text}")
|
||||
old_price = price
|
||||
|
||||
try:
|
||||
item_name = tab.ele('xpath=//*[@id="contentContainer"]/form/div[2]/div[2]/div/ul/li[1]/div[2]/p').text
|
||||
except:
|
||||
continue
|
||||
attr_items.append({
|
||||
'url': color_url,
|
||||
'items': [item_name],
|
||||
'price': price,
|
||||
'old_price': old_price,
|
||||
'images': color_images
|
||||
})
|
||||
|
||||
if len(attr_items) == 0:
|
||||
goods_info.attr = 'S'
|
||||
goods_info.attr_items = []
|
||||
goods_info.images = main_images
|
||||
goods_info.p_lists = []
|
||||
else:
|
||||
goods_info.attr = 'M'
|
||||
goods_info.attr_items = m_data
|
||||
for attr_item in attr_items:
|
||||
goods_info.p_lists.append(types.GoodsInfo.GoodsInfoP(
|
||||
url=attr_item['url'],
|
||||
attr_items=attr_item['items'],
|
||||
price=attr_item['price'],
|
||||
old_price=attr_item['old_price'],
|
||||
images=attr_item['images'],
|
||||
))
|
||||
for image_url in attr_item['images']:
|
||||
if image_url not in main_images:
|
||||
main_images.append(image_url)
|
||||
goods_info.images = main_images
|
||||
goods_info.p_urls = color_urls
|
||||
except Exception as e:
|
||||
try:
|
||||
tab.close()
|
||||
except:
|
||||
pass
|
||||
raise Exception(e)
|
||||
try:
|
||||
tab.close()
|
||||
except:
|
||||
pass
|
||||
return goods_info
|
||||
325
lib/module/ancientnutrition.py
Normal file
325
lib/module/ancientnutrition.py
Normal file
@@ -0,0 +1,325 @@
|
||||
from core import spiders, types
|
||||
from utils import formats, messages
|
||||
|
||||
class SpiderModule(spiders.Spiders):
|
||||
project_name = "ancientnutrition"
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
self.project_name,
|
||||
bitch = 30,
|
||||
worker_num = 1,
|
||||
switch_clash = False,
|
||||
reflush_browser = False
|
||||
)
|
||||
|
||||
def get_category_urls(self) -> list[str]:
|
||||
category_urls = []
|
||||
|
||||
self.tab.get('https://ancientnutrition.com/')
|
||||
one_menu_eles = self.tab.eles('xpath=//*[@id="__next"]/div[4]/div[1]/div[1]/div')
|
||||
for index, one_menu_ele in enumerate(one_menu_eles[1:]):
|
||||
one_link_ele = one_menu_ele.ele('xpath=div/a')
|
||||
one_url = one_link_ele.attr('href')
|
||||
one_name = one_link_ele.text.replace('/', '-')
|
||||
category_urls.append(f"{one_url}#{one_name}")
|
||||
messages.sendInfo(one_name)
|
||||
|
||||
print(index+2)
|
||||
two_menu_eles = self.tab.eles(f'xpath=//*[@id="__next"]/div[4]/div[{index+2}]/div/div/div[2]/div/a')
|
||||
for two_menu_ele in two_menu_eles:
|
||||
two_link_ele = two_menu_ele
|
||||
two_url = two_link_ele.attr('href')
|
||||
two_name = two_link_ele.text.replace('/', '-')
|
||||
category_urls.append(f"{two_url}#{one_name}/{two_name}")
|
||||
|
||||
# three_menu_eles = two_menu_ele.eles('xpath=ul/li')
|
||||
# for three_menu_ele in three_menu_eles:
|
||||
# three_link_ele = three_menu_ele.ele('@tag()=a')
|
||||
# three_url = three_link_ele.attr('href')
|
||||
# three_name = three_link_ele.text.replace('/', '-')
|
||||
# category_urls.append(f"{three_url}#{one_name}/{two_name}/{three_name}")
|
||||
|
||||
return category_urls
|
||||
|
||||
def get_goods_urls(self, category_url: str) -> list[str]:
|
||||
self.tab.get(f"{category_url}")
|
||||
goods_urls = []
|
||||
|
||||
while True:
|
||||
try:
|
||||
self.tab.scroll.to_bottom()
|
||||
self.tab.ele('text=Load More').click()
|
||||
except:
|
||||
break
|
||||
|
||||
goods_eles = self.tab.eles('xpath=//*[@id="__next"]/div[9]/div/div[2]/div[2]/div')
|
||||
for goods_ele in goods_eles:
|
||||
try:
|
||||
goods_link_ele = goods_ele.ele('@tag()=a')
|
||||
except Exception as e:
|
||||
continue
|
||||
goods_urls.append(goods_link_ele.attr('href'))
|
||||
|
||||
return goods_urls
|
||||
|
||||
def get_goods_info(self, url) -> types.GoodsInfo:
|
||||
def get_image_urls():
|
||||
image_urls = []
|
||||
|
||||
image_eles = tab.eles('xpath=//*[@id="__next"]/div[8]/div[1]/div/div[2]/div[1]/div/div[2]/div/div[1]/div')
|
||||
for image_ele in image_eles:
|
||||
image_link_ele = image_ele.ele('xpath=div/span/img')
|
||||
image_urls.append(image_link_ele.attr('src').replace('_150x150', '_1450x1450'))
|
||||
|
||||
return image_urls
|
||||
|
||||
tab = self.browser.new_tab(url)
|
||||
tab.set.window.max()
|
||||
spu = formats.url_to_spu(url)
|
||||
|
||||
try:
|
||||
brand = ''
|
||||
# try:
|
||||
# brand = tab.ele('xpath=//*[@id="contentContainer"]/form/div[2]/div[1]/h1/div[1]', timeout=10).text
|
||||
# except:
|
||||
# pass
|
||||
# if brand == '':
|
||||
# title = tab.ele('xpath=//*[@id="contentContainer"]/form/div[2]/div[1]/h1').text
|
||||
# else:
|
||||
title = tab.ele('@tag()=h1').text
|
||||
|
||||
desc = formats.clean_html(tab.ele('#productDescription').html)
|
||||
|
||||
price = float(tab.ele('xpath=//*[@id="__next"]/div[8]/div[1]/div/div[2]/div[2]/div/div[1]/div/span/span[1]').text.replace('$', ''))
|
||||
old_price = float(tab.ele('xpath=//*[@id="__next"]/div[8]/div[1]/div/div[2]/div[2]/div/div[1]/div/span/span[2]/span[1]').text.replace('$', ''))
|
||||
|
||||
main_images = get_image_urls()
|
||||
|
||||
goods_info = types.GoodsInfo(
|
||||
title=title,
|
||||
desc=desc,
|
||||
brand=brand,
|
||||
url=url,
|
||||
spu=spu,
|
||||
price=price,
|
||||
old_price=old_price,
|
||||
)
|
||||
|
||||
m_data = []
|
||||
attr_items = []
|
||||
try:
|
||||
tab.ele('text=Select Flavor').click()
|
||||
m_data.append('Flavor')
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
tab.ele('text=Select Size').click()
|
||||
m_data.append('Size')
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
tab.ele('text=Select Quantity').click()
|
||||
m_data.append('Quantity')
|
||||
except:
|
||||
pass
|
||||
|
||||
if 'Flavor' in m_data:
|
||||
tab.ele('xpath=//*[@id="__next"]/div[8]/div[1]/div/div[2]/div[2]/div/div[3]/div/div').click()
|
||||
color_eles = tab.eles('xpath=//*[@id="__next"]/div[8]/div[1]/div/div[2]/div[2]/div/div[3]/div/div[2]/div')
|
||||
color_xpaths = []
|
||||
for color_ele in color_eles:
|
||||
color_xpaths.append(color_ele.xpath)
|
||||
|
||||
for color_xpath in color_xpaths:
|
||||
while True:
|
||||
tab.ele('xpath=//*[@id="__next"]/div[8]/div[1]/div/div[2]/div[2]/div/div[3]/div/div').click()
|
||||
try:
|
||||
color_ele = tab.ele(f"xpath={color_xpath}")
|
||||
color_name = color_ele.text
|
||||
break
|
||||
except:
|
||||
tab.get(url)
|
||||
color_ele.click()
|
||||
tab.wait(3)
|
||||
color_images = get_image_urls()
|
||||
if 'Size' in m_data:
|
||||
try:
|
||||
size_eles = tab.eles(f"xpath={tab.ele('text=Select Size').xpath.replace('/span[1]', '/div/div')}")
|
||||
except:
|
||||
size_name = 'Default'
|
||||
if 'Quantity' in m_data:
|
||||
quantity_eles = tab.eles(f"xpath={tab.ele('text=Select Quantity').xpath.replace('/span[1]', '/div/div')}")
|
||||
for quantity_index, quantity_ele in enumerate(quantity_eles):
|
||||
try:
|
||||
quantity_ele = tab.ele(f"xpath={tab.ele('text=Select Quantity').xpath.replace('/span[1]', f'/div/div[{quantity_index+1}]')}")
|
||||
quantity_name = quantity_ele.text
|
||||
except:
|
||||
continue
|
||||
quantity_ele.click()
|
||||
tab.wait(2)
|
||||
price = float(tab.ele('xpath=//*[@id="__next"]/div[8]/div[1]/div/div[2]/div[2]/div/div[1]/div/span/span[1]').text.replace('$', ''))
|
||||
old_price = float(tab.ele('xpath=//*[@id="__next"]/div[8]/div[1]/div/div[2]/div[2]/div/div[1]/div/span/span[2]/span[1]').text.replace('$', ''))
|
||||
attr_items.append({
|
||||
'url': tab.url,
|
||||
'items': [color_name, size_name, quantity_name],
|
||||
'price': price,
|
||||
'old_price': old_price,
|
||||
'images': color_images
|
||||
})
|
||||
else:
|
||||
price = float(tab.ele('xpath=//*[@id="__next"]/div[8]/div[1]/div/div[2]/div[2]/div/div[1]/div/span/span[1]').text.replace('$', ''))
|
||||
old_price = float(tab.ele('xpath=//*[@id="__next"]/div[8]/div[1]/div/div[2]/div[2]/div/div[1]/div/span/span[2]/span[1]').text.replace('$', ''))
|
||||
attr_items.append({
|
||||
'url': tab.url,
|
||||
'items': [color_name, size_name],
|
||||
'price': price,
|
||||
'old_price': old_price,
|
||||
'images': color_images
|
||||
})
|
||||
size_xpaths = []
|
||||
for size_ele in size_eles:
|
||||
try:
|
||||
size_xpaths.append(size_ele.xpath)
|
||||
except:
|
||||
continue
|
||||
|
||||
for size_xpath in size_xpaths:
|
||||
try:
|
||||
size_ele = tab.ele(f"xpath={size_xpath}")
|
||||
size_name = size_ele.text
|
||||
except:
|
||||
continue
|
||||
size_ele.click()
|
||||
tab.wait(3)
|
||||
color_images = get_image_urls()
|
||||
if 'Quantity' in m_data:
|
||||
quantity_eles = tab.eles(f"xpath={tab.ele('text=Select Quantity').xpath.replace('/span[1]', '/div/div')}")
|
||||
for quantity_index, quantity_ele in enumerate(quantity_eles):
|
||||
try:
|
||||
quantity_ele = tab.ele(f"xpath={tab.ele('text=Select Quantity').xpath.replace('/span[1]', f'/div/div[{quantity_index+1}]')}")
|
||||
quantity_name = quantity_ele.text
|
||||
except:
|
||||
continue
|
||||
quantity_ele.click()
|
||||
tab.wait(2)
|
||||
price = float(tab.ele('xpath=//*[@id="__next"]/div[8]/div[1]/div/div[2]/div[2]/div/div[1]/div/span/span[1]').text.replace('$', ''))
|
||||
old_price = float(tab.ele('xpath=//*[@id="__next"]/div[8]/div[1]/div/div[2]/div[2]/div/div[1]/div/span/span[2]/span[1]').text.replace('$', ''))
|
||||
attr_items.append({
|
||||
'url': tab.url,
|
||||
'items': [color_name, size_name, quantity_name],
|
||||
'price': price,
|
||||
'old_price': old_price,
|
||||
'images': color_images
|
||||
})
|
||||
else:
|
||||
price = float(tab.ele('xpath=//*[@id="__next"]/div[8]/div[1]/div/div[2]/div[2]/div/div[1]/div/span/span[1]').text.replace('$', ''))
|
||||
old_price = float(tab.ele('xpath=//*[@id="__next"]/div[8]/div[1]/div/div[2]/div[2]/div/div[1]/div/span/span[2]/span[1]').text.replace('$', ''))
|
||||
attr_items.append({
|
||||
'url': tab.url,
|
||||
'items': [color_name, size_name],
|
||||
'price': price,
|
||||
'old_price': old_price,
|
||||
'images': color_images
|
||||
})
|
||||
else:
|
||||
price = float(tab.ele('xpath=//*[@id="__next"]/div[8]/div[1]/div/div[2]/div[2]/div/div[1]/div/span/span[1]').text.replace('$', ''))
|
||||
old_price = float(tab.ele('xpath=//*[@id="__next"]/div[8]/div[1]/div/div[2]/div[2]/div/div[1]/div/span/span[2]/span[1]').text.replace('$', ''))
|
||||
attr_items.append({
|
||||
'url': tab.url,
|
||||
'items': [color_name],
|
||||
'price': price,
|
||||
'old_price': old_price,
|
||||
'images': color_images
|
||||
})
|
||||
else:
|
||||
color_images = []
|
||||
if 'Size' in m_data:
|
||||
size_eles = tab.eles(f"xpath={tab.ele('text=Select Size').xpath.replace('/span[1]', '/div/div')}")
|
||||
size_xpaths = []
|
||||
for size_ele in size_eles:
|
||||
try:
|
||||
size_xpaths.append(size_ele.xpath)
|
||||
except:
|
||||
continue
|
||||
|
||||
for size_xpath in size_xpaths:
|
||||
try:
|
||||
size_ele = tab.ele(f"xpath={size_xpath}")
|
||||
size_name = size_ele.text
|
||||
except:
|
||||
continue
|
||||
size_ele.click()
|
||||
tab.wait(2)
|
||||
color_images = get_image_urls()
|
||||
if 'Quantity' in m_data:
|
||||
quantity_eles = tab.eles(f"xpath={tab.ele('text=Select Quantity').xpath.replace('/span[1]', '/div/div')}")
|
||||
for quantity_index, quantity_ele in enumerate(quantity_eles):
|
||||
try:
|
||||
quantity_ele = tab.ele(f"xpath={tab.ele('text=Select Quantity').xpath.replace('/span[1]', f'/div/div[{quantity_index+1}]')}")
|
||||
quantity_name = quantity_ele.text
|
||||
except:
|
||||
continue
|
||||
quantity_ele.click()
|
||||
tab.wait(2)
|
||||
price = float(tab.ele('xpath=//*[@id="__next"]/div[8]/div[1]/div/div[2]/div[2]/div/div[1]/div/span/span[1]').text.replace('$', ''))
|
||||
old_price = float(tab.ele('xpath=//*[@id="__next"]/div[8]/div[1]/div/div[2]/div[2]/div/div[1]/div/span/span[2]/span[1]').text.replace('$', ''))
|
||||
attr_items.append({
|
||||
'url': tab.url,
|
||||
'items': [size_name, quantity_name],
|
||||
'price': price,
|
||||
'old_price': old_price,
|
||||
'images': color_images
|
||||
})
|
||||
else:
|
||||
if 'Quantity' in m_data:
|
||||
quantity_eles = tab.eles(f"xpath={tab.ele('text=Select Quantity').xpath.replace('/span[1]', '/div/div')}")
|
||||
for quantity_index, quantity_ele in enumerate(quantity_eles):
|
||||
try:
|
||||
quantity_ele = tab.ele(f"xpath={tab.ele('text=Select Quantity').xpath.replace('/span[1]', f'/div/div[{quantity_index+1}]')}")
|
||||
quantity_name = quantity_ele.text
|
||||
except:
|
||||
continue
|
||||
quantity_ele.click()
|
||||
tab.wait(2)
|
||||
price = float(tab.ele('xpath=//*[@id="__next"]/div[8]/div[1]/div/div[2]/div[2]/div/div[1]/div/span/span[1]').text.replace('$', ''))
|
||||
old_price = float(tab.ele('xpath=//*[@id="__next"]/div[8]/div[1]/div/div[2]/div[2]/div/div[1]/div/span/span[2]/span[1]').text.replace('$', ''))
|
||||
attr_items.append({
|
||||
'url': tab.url,
|
||||
'items': [quantity_name],
|
||||
'price': price,
|
||||
'old_price': old_price,
|
||||
'images': color_images
|
||||
})
|
||||
|
||||
if len(attr_items) == 0:
|
||||
goods_info.attr = 'S'
|
||||
goods_info.attr_items = []
|
||||
goods_info.images = main_images
|
||||
goods_info.p_lists = []
|
||||
else:
|
||||
goods_info.attr = 'M'
|
||||
goods_info.attr_items = m_data
|
||||
for attr_item in attr_items:
|
||||
goods_info.p_lists.append(types.GoodsInfo.GoodsInfoP(
|
||||
url=attr_item['url'],
|
||||
attr_items=attr_item['items'],
|
||||
price=attr_item['price'],
|
||||
old_price=attr_item['old_price'],
|
||||
images=attr_item['images'],
|
||||
))
|
||||
for image_url in attr_item['images']:
|
||||
if image_url not in main_images:
|
||||
main_images.append(image_url)
|
||||
goods_info.images = main_images
|
||||
except Exception as e:
|
||||
try:
|
||||
tab.close()
|
||||
except:
|
||||
pass
|
||||
raise Exception(e)
|
||||
try:
|
||||
tab.close()
|
||||
except:
|
||||
pass
|
||||
return goods_info
|
||||
201
lib/module/bricomarche.py
Normal file
201
lib/module/bricomarche.py
Normal file
@@ -0,0 +1,201 @@
|
||||
from core import spiders, types
|
||||
from utils import formats, messages
|
||||
from DrissionPage.common import Keys
|
||||
|
||||
class SpiderModule(spiders.Spiders):
|
||||
project_name = "bricomarche"
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
self.project_name,
|
||||
bitch = 5,
|
||||
worker_num = 1,
|
||||
switch_clash = False,
|
||||
reflush_browser = False
|
||||
)
|
||||
self.tab.get('https://www.bricomarche.pl/')
|
||||
# input('wait:')
|
||||
|
||||
def get_category_urls(self) -> list[str]:
|
||||
category_urls = []
|
||||
|
||||
self.tab.get('https://www.bricomarche.pl/')
|
||||
one_menu_eles = self.tab.eles('xpath=//*[@id="root"]/main/div[5]/div[3]/nav/div')
|
||||
for one_menu_ele in one_menu_eles:
|
||||
one_link_ele = one_menu_ele.ele('@tag()=a')
|
||||
one_url = one_link_ele.attr('href')
|
||||
one_name = one_link_ele.text.replace('/', '-')
|
||||
category_urls.append(f"{one_url}#{one_name}")
|
||||
messages.sendInfo(one_name)
|
||||
|
||||
two_menu_eles = one_menu_ele.eles('xpath=div/div[1]/div')
|
||||
for two_menu_ele in two_menu_eles:
|
||||
two_link_ele = two_menu_ele.ele('@tag()=a')
|
||||
two_url = two_link_ele.attr('href')
|
||||
two_name = two_link_ele.text.replace('/', '-')
|
||||
category_urls.append(f"{two_url}#{one_name}/{two_name}")
|
||||
|
||||
three_menu_eles = two_menu_ele.eles('xpath=ul/li')
|
||||
for three_menu_ele in three_menu_eles:
|
||||
three_link_ele = three_menu_ele.ele('@tag()=a')
|
||||
three_url = three_link_ele.attr('href')
|
||||
three_name = three_link_ele.text.replace('/', '-')
|
||||
category_urls.append(f"{three_url}#{one_name}/{two_name}/{three_name}")
|
||||
|
||||
return category_urls
|
||||
|
||||
def get_goods_urls(self, category_url: str) -> list[str]:
|
||||
page = 1
|
||||
limit = 100
|
||||
self.tab.get(f"{category_url}?page={page}&limit={limit}")
|
||||
if self.tab.ele('@tag()=h2').text == '执行安全验证':
|
||||
self.tab.wait(10)
|
||||
self.tab.actions.type((Keys.TAB, Keys.SPACE))
|
||||
goods_urls = []
|
||||
|
||||
while True:
|
||||
try:
|
||||
self.tab.scroll.to_bottom()
|
||||
goods_eles = self.tab.eles('xpath=//*[@id="spark"]/div[2]/div/section/div/div/main/div[2]/section/div')
|
||||
for goods_ele in goods_eles:
|
||||
goods_link_ele = goods_ele.ele('@tag()=a')
|
||||
goods_urls.append(goods_link_ele.attr('href'))
|
||||
if len(goods_eles) == 0:
|
||||
break
|
||||
except:
|
||||
break
|
||||
page += 1
|
||||
self.tab.get(f"{category_url}?page={page}&limit={limit}")
|
||||
if self.tab.ele('@tag()=h2').text == '执行安全验证':
|
||||
self.tab.wait(10)
|
||||
self.tab.actions.type((Keys.TAB, Keys.SPACE))
|
||||
|
||||
return goods_urls
|
||||
|
||||
def get_goods_info(self, url) -> types.GoodsInfo:
|
||||
def get_image_urls():
|
||||
image_urls = []
|
||||
|
||||
image_eles = tab.eles('xpath=//*[@id="spark"]/div[2]/div/main/div/div[2]/section[1]/div/div[1]/div/div/div/div/div')
|
||||
for image_ele in image_eles:
|
||||
image_link_ele = image_ele.ele('xpath=button/div/img')
|
||||
image_urls.append(image_link_ele.attr('src').replace('gallery_100_91', 'gallery'))
|
||||
|
||||
return image_urls
|
||||
|
||||
tab = self.browser.new_tab(url)
|
||||
while True:
|
||||
try:
|
||||
if tab.ele('@tag()=h2').text == '执行安全验证':
|
||||
tab.wait(10)
|
||||
tab.actions.type((Keys.TAB, Keys.SPACE))
|
||||
tab.wait(5)
|
||||
else:
|
||||
break
|
||||
except:
|
||||
break
|
||||
tab.set.window.max()
|
||||
spu = formats.url_to_spu(url)
|
||||
|
||||
try:
|
||||
brand = ''
|
||||
# try:
|
||||
# brand = tab.ele('xpath=//*[@id="contentContainer"]/form/div[2]/div[1]/h1/div[1]', timeout=10).text
|
||||
# except:
|
||||
# pass
|
||||
|
||||
title = tab.ele('@tag()=h1', timeout=10).text
|
||||
|
||||
desc = ""
|
||||
try:
|
||||
desc = formats.clean_html(tab.ele('.attributes').html)
|
||||
except:
|
||||
pass
|
||||
|
||||
# try:
|
||||
price_ele = tab.ele('.main-price')
|
||||
price = float(f"{price_ele.ele('.whole').text}{price_ele.ele('.cents').text.replace(' zł', '')}")
|
||||
# except:
|
||||
# price = 0.0
|
||||
old_price = price
|
||||
|
||||
main_images = get_image_urls()
|
||||
|
||||
goods_info = types.GoodsInfo(
|
||||
title=title,
|
||||
desc=desc,
|
||||
brand=brand,
|
||||
url=url,
|
||||
spu=spu,
|
||||
price=price,
|
||||
old_price=old_price,
|
||||
)
|
||||
|
||||
m_data = []
|
||||
attr_items = []
|
||||
# color_urls = [url]
|
||||
# color_eles = tab.eles('xpath=//*[@id="contentContainer"]/form/div[2]/div[2]/div/ul/li')
|
||||
# for color_ele in color_eles[1:]:
|
||||
# color_link_ele = color_ele.ele('xpath=a')
|
||||
# color_urls.append(color_link_ele.attr('href'))
|
||||
# if len(color_urls) > 1:
|
||||
# m_data = ["Color"]
|
||||
|
||||
# if len(color_urls) > 1:
|
||||
# for color_url in color_urls:
|
||||
# color_images = main_images
|
||||
# if color_url != url:
|
||||
# tab.get(color_url)
|
||||
# if brand == '':
|
||||
# title = tab.ele('xpath=//*[@id="contentContainer"]/form/div[2]/div[1]/h1').text
|
||||
# else:
|
||||
# title = tab.ele('xpath=//*[@id="contentContainer"]/form/div[2]/div[1]/h1/div[2]').text
|
||||
# color_images = get_image_urls()
|
||||
|
||||
# price = float(f"{tab.ele('xpath=//*[@id="contentContainer"]/form/div[2]/section[2]/div[1]/div[2]/span[1]').text}.{tab.ele('xpath=//*[@id="contentContainer"]/form/div[2]/section[2]/div[1]/div[2]/span[3]').text}")
|
||||
# old_price = price
|
||||
|
||||
# try:
|
||||
# item_name = tab.ele('xpath=//*[@id="contentContainer"]/form/div[2]/div[2]/div/ul/li[1]/div[2]/p').text
|
||||
# except:
|
||||
# continue
|
||||
# attr_items.append({
|
||||
# 'url': color_url,
|
||||
# 'items': [item_name],
|
||||
# 'price': price,
|
||||
# 'old_price': old_price,
|
||||
# 'images': color_images
|
||||
# })
|
||||
|
||||
if len(attr_items) == 0:
|
||||
goods_info.attr = 'S'
|
||||
goods_info.attr_items = []
|
||||
goods_info.images = main_images
|
||||
goods_info.p_lists = []
|
||||
else:
|
||||
goods_info.attr = 'M'
|
||||
goods_info.attr_items = m_data
|
||||
for attr_item in attr_items:
|
||||
goods_info.p_lists.append(types.GoodsInfo.GoodsInfoP(
|
||||
url=attr_item['url'],
|
||||
attr_items=attr_item['items'],
|
||||
price=attr_item['price'],
|
||||
old_price=attr_item['old_price'],
|
||||
images=attr_item['images'],
|
||||
))
|
||||
for image_url in attr_item['images']:
|
||||
if image_url not in main_images:
|
||||
main_images.append(image_url)
|
||||
goods_info.images = main_images
|
||||
# goods_info.p_urls = color_urls
|
||||
except Exception as e:
|
||||
try:
|
||||
tab.close()
|
||||
except:
|
||||
pass
|
||||
raise Exception(e)
|
||||
try:
|
||||
tab.close()
|
||||
except:
|
||||
pass
|
||||
return goods_info
|
||||
136
lib/module/condom69.py
Normal file
136
lib/module/condom69.py
Normal file
@@ -0,0 +1,136 @@
|
||||
from core import spiders, types
|
||||
from utils import formats, messages
|
||||
|
||||
class SpiderModule(spiders.Spiders):
|
||||
project_name = "condom69"
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
self.project_name,
|
||||
bitch = 30,
|
||||
worker_num = 5,
|
||||
switch_clash = False,
|
||||
reflush_browser = False
|
||||
)
|
||||
self.tab.get('https://www.condom69.net/')
|
||||
# input('wait:')
|
||||
|
||||
def get_category_urls(self) -> list[str]:
|
||||
category_urls = []
|
||||
|
||||
one_menu_eles = self.tab.eles('xpath=//*[@id="nav-one"]/li')
|
||||
for one_menu_ele in one_menu_eles[:-1]:
|
||||
one_link_ele = one_menu_ele.ele('xpath=a')
|
||||
one_url = one_link_ele.attr('href')
|
||||
one_name = one_link_ele.text.replace('/', '-')
|
||||
category_urls.append(f"{one_url}#{one_name}")
|
||||
messages.sendInfo(one_name)
|
||||
|
||||
two_menu_eles = one_menu_ele.eles('xpath=div/ul/li', timeout=1)
|
||||
for two_index, two_menu_ele in enumerate(two_menu_eles):
|
||||
two_link_ele = two_menu_ele.ele('xpath=div/a')
|
||||
two_url = two_link_ele.attr('href')
|
||||
two_name = two_link_ele.text.replace('/', '-').replace(',', ',').replace('#', ' ')
|
||||
category_urls.append(f"{two_url}#{one_name}/{two_name}")
|
||||
|
||||
# try:
|
||||
# three_menu_eles = self.tab.ele(f'xpath=//*[@id="__next"]/div[1]/header/div/div[2]/nav/div[{two_index+1}]/div/div[1]').eles('@tag()=li')
|
||||
# except:
|
||||
# continue
|
||||
# for three_menu_ele in three_menu_eles:
|
||||
# three_link_ele = three_menu_ele.ele('@tag()=a')
|
||||
# three_url = three_link_ele.attr('href')
|
||||
# three_name = three_link_ele.text.replace('/', '-')
|
||||
# category_urls.append(f"{three_url}#{one_name}/{two_name}/{three_name}")
|
||||
|
||||
return category_urls
|
||||
|
||||
def get_goods_urls(self, category_url: str) -> list[str]:
|
||||
page = 1
|
||||
self.tab.get(f"{category_url}&pg={page}")
|
||||
|
||||
#####获取页数####
|
||||
|
||||
#################
|
||||
|
||||
goods_urls = []
|
||||
url_index = {}
|
||||
while True:
|
||||
self.tab.scroll.to_bottom()
|
||||
goods_eles = self.tab.eles('.divProdItemImg2Inner')
|
||||
page_urls = []
|
||||
for goods_ele in goods_eles:
|
||||
goods_url = f"{goods_ele.ele('xpath=a').attr('href')}"
|
||||
if goods_url not in url_index:
|
||||
page_urls.append(goods_url)
|
||||
url_index[goods_url] = None
|
||||
if len(page_urls) > 0:
|
||||
goods_urls += page_urls
|
||||
else:
|
||||
break
|
||||
page += 1
|
||||
self.tab.get(f"{category_url}&pg={page}")
|
||||
|
||||
messages.sendInfo(f"{len(goods_urls)} 个")
|
||||
|
||||
return goods_urls
|
||||
|
||||
def get_goods_info(self, url) -> types.GoodsInfo:
|
||||
def get_image_urls():
|
||||
image_urls = []
|
||||
image_eles = tab.eles('xpath=/html/body/form/div[3]/div[2]/div/div[2]/div/div/div[2]/div[2]/div[3]/div/div[2]/div/div/div[1]/div[1]/div[2]/div')
|
||||
|
||||
for image_ele in image_eles:
|
||||
image_url = image_ele.ele('xpath=div/div/a/img').attr('src')
|
||||
image_urls.append(image_url)
|
||||
return image_urls
|
||||
|
||||
tab = self.browser.new_tab(url)
|
||||
tab.set.window.max()
|
||||
spu = formats.url_to_spu(url)
|
||||
|
||||
try:
|
||||
h1_ele = tab.ele('xpath=/html/body/form/div[3]/div[2]/div/div[2]/div/div/div[2]/div[2]/div[3]/div/div[2]/div/div/div[1]/div[2]/div/div[1]')
|
||||
brand = ''
|
||||
try:
|
||||
brand = tab.ele('xpath=/html/body/form/div[3]/div[2]/div/div[2]/div/div/div[2]/div[2]/div[3]/div/div[2]/div/div/div[1]/div[2]/div/div[2]/div[1]/table/tbody/tr/td[3]/a').text
|
||||
except:
|
||||
pass
|
||||
title = h1_ele.text
|
||||
|
||||
desc = ""
|
||||
try:
|
||||
desc = formats.clean_html(tab.ele('.ctl00_cphContent_ucUsrIndProduct_pnlIndProdDesc').html)
|
||||
except:
|
||||
pass
|
||||
|
||||
price = tab.ele('xpath=/html/body/form/div[3]/div[2]/div/div[2]/div/div/div[2]/div[2]/div[3]/div/div[2]/div/div/div[1]/div[2]/div/div[2]/div[3]/div[1]/div[2]/span').text.replace(',', '')
|
||||
old_price = price
|
||||
|
||||
main_images = get_image_urls()
|
||||
|
||||
goods_info = types.GoodsInfo(
|
||||
title=title,
|
||||
desc=desc,
|
||||
brand=brand,
|
||||
url=url,
|
||||
spu=spu,
|
||||
price=price,
|
||||
old_price=old_price,
|
||||
)
|
||||
|
||||
goods_info.attr = 'S'
|
||||
goods_info.attr_items = []
|
||||
goods_info.images = main_images
|
||||
goods_info.p_lists = []
|
||||
except Exception as e:
|
||||
try:
|
||||
tab.close()
|
||||
except:
|
||||
pass
|
||||
raise Exception(e)
|
||||
try:
|
||||
tab.close()
|
||||
except:
|
||||
pass
|
||||
return goods_info
|
||||
210
lib/module/dk_one.py
Normal file
210
lib/module/dk_one.py
Normal file
@@ -0,0 +1,210 @@
|
||||
from core import spiders, types
|
||||
from utils import formats, messages
|
||||
|
||||
class SpiderModule(spiders.Spiders):
|
||||
project_name = "dk_one"
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
self.project_name,
|
||||
bitch = 30,
|
||||
worker_num = 1,
|
||||
switch_clash = False,
|
||||
reflush_browser = False
|
||||
)
|
||||
|
||||
def get_category_urls(self) -> list[str]:
|
||||
category_urls = []
|
||||
|
||||
self.tab.get('https://www.dk_one.com/')
|
||||
one_menu_eles = self.tab.eles('xpath=/html/body/div[5]/header/div[2]/div[2]/div/div[1]/div[1]/ul/li')
|
||||
for one_menu_ele in one_menu_eles:
|
||||
one_link_ele = one_menu_ele.ele('@tag()=a')
|
||||
one_url = one_link_ele.attr('href')
|
||||
one_name = one_link_ele.text.replace('/', '-')
|
||||
if one_name == '라이프':
|
||||
continue
|
||||
category_urls.append(f"{one_url}#{one_name}")
|
||||
messages.sendInfo(one_name)
|
||||
|
||||
two_menu_eles = one_menu_ele.eles('xpath=div/div/div[1]/ul/li')
|
||||
for two_menu_ele in two_menu_eles:
|
||||
two_link_ele = two_menu_ele.ele('@tag()=a')
|
||||
two_url = two_link_ele.attr('href')
|
||||
two_name = two_link_ele.text.replace('/', '-')
|
||||
if two_name == '메인':
|
||||
continue
|
||||
category_urls.append(f"{two_url}#{one_name}/{two_name}")
|
||||
two_menu_eles = one_menu_ele.eles('xpath=div/div/div[2]/ul/li')
|
||||
for two_menu_ele in two_menu_eles:
|
||||
two_link_ele = two_menu_ele.ele('@tag()=a')
|
||||
two_url = two_link_ele.attr('href')
|
||||
two_name = two_link_ele.text.replace('/', '-')
|
||||
if two_name == '메인':
|
||||
continue
|
||||
category_urls.append(f"{two_url}#{one_name}/Top Brand/{two_name}")
|
||||
|
||||
# three_menu_eles = two_menu_ele.eles('xpath=ul/li')
|
||||
# for three_menu_ele in three_menu_eles:
|
||||
# three_link_ele = three_menu_ele.ele('@tag()=a')
|
||||
# three_url = three_link_ele.attr('href')
|
||||
# three_name = three_link_ele.text.replace('/', '-')
|
||||
# category_urls.append(f"{three_url}#{one_name}/{two_name}/{three_name}")
|
||||
|
||||
return category_urls
|
||||
|
||||
def get_goods_urls(self, category_url: str) -> list[str]:
|
||||
self.tab.get(category_url)
|
||||
goods_urls = []
|
||||
goods_eles = self.tab.eles('xpath=//*[@id="prodList"]/div')
|
||||
for goods_ele in goods_eles:
|
||||
goods_link_ele = goods_ele.ele('.prod-link')
|
||||
goods_urls.append(goods_link_ele.attr('href'))
|
||||
|
||||
return goods_urls
|
||||
|
||||
def get_goods_info(self, url) -> types.GoodsInfo:
|
||||
def get_image_urls(tab):
|
||||
image_urls = []
|
||||
image_eles = tab.ele('#prod-img').eles('@tag()=img')
|
||||
for image_ele in image_eles:
|
||||
image_urls.append(image_ele.attr('src'))
|
||||
return image_urls
|
||||
|
||||
tab = self.browser.new_tab(url)
|
||||
tab.set.window.max()
|
||||
spu = formats.url_to_spu(url)
|
||||
|
||||
try:
|
||||
brand = ''
|
||||
# try:
|
||||
# brand = tab.ele('xpath=//*[@id="contentContainer"]/form/div[2]/div[1]/h1/div[1]', timeout=10).text
|
||||
# except:
|
||||
# pass
|
||||
# if brand == '':
|
||||
# title = tab.ele('xpath=//*[@id="contentContainer"]/form/div[2]/div[1]/h1').text
|
||||
# else:
|
||||
title = tab.ele('.page-title').text
|
||||
|
||||
try:
|
||||
desc = formats.clean_html(tab.ele('@@class=tab-content@@id=tabContent0202').html)
|
||||
except:
|
||||
desc = ''
|
||||
|
||||
price = float(tab.ele('.price-group').ele('.val').text.replace(',', ''))
|
||||
try:
|
||||
old_price = float(tab.ele('.price-group origin').text.replace(',', ''))
|
||||
except:
|
||||
old_price = price
|
||||
|
||||
main_images = get_image_urls(tab)
|
||||
|
||||
goods_info = types.GoodsInfo(
|
||||
title=title,
|
||||
desc=desc,
|
||||
brand=brand,
|
||||
url=url,
|
||||
spu=spu,
|
||||
price=price,
|
||||
old_price=old_price,
|
||||
images=main_images
|
||||
)
|
||||
|
||||
m_data = []
|
||||
color_data = {}
|
||||
color_eles = []
|
||||
# 颜色
|
||||
tab.ele('.opt-color')
|
||||
m_data.append('컬러')
|
||||
color_eles = tab.ele('.color-list-wrap').eles('.prod-color-rdo')
|
||||
|
||||
m_data.append('사이즈')
|
||||
|
||||
for color_ele in color_eles:
|
||||
color_input_onclick = color_ele.ele('@tag()=input').attr('onclick')
|
||||
have_url = False
|
||||
if 'location.href=' in color_input_onclick:
|
||||
color_url = 'https://dk-on.com' + formats.re_search(color_input_onclick, r"location\.href\s*=\s*'([^']*)'")
|
||||
color_name = color_url.split('/')[-1]
|
||||
have_url = True
|
||||
elif 'fnColorClicked' in color_input_onclick:
|
||||
color_url = goods_info.url
|
||||
color_name = color_ele.ele('@tag()=input').attr('value')
|
||||
color_ele.click()
|
||||
else:
|
||||
color_url = goods_info.url
|
||||
color_name = goods_info.title.split(' / ')[-1]
|
||||
|
||||
color_data[color_name] = {'url': color_url, 'have_url': have_url, 'ele': color_ele}
|
||||
goods_info.p_urls.append(color_url)
|
||||
|
||||
real_color_data = {}
|
||||
|
||||
|
||||
for color_name, color_item in color_data.items():
|
||||
color_tab = tab
|
||||
if color_item['have_url']:
|
||||
color_tab = self.browser.new_tab()
|
||||
|
||||
size_data = []
|
||||
if color_item['have_url']:
|
||||
color_tab.get(color_item['url'])
|
||||
else:
|
||||
color_item['ele'].click()
|
||||
color_tab.wait(1)
|
||||
color_item['price'] = str(color_tab.ele('.price-group').ele('.val').text.replace(',', ''))
|
||||
try:
|
||||
color_item['old_price'] = str(color_tab.ele('.price-group origin').text.replace(',', ''))
|
||||
except:
|
||||
color_item['old_price'] = color_item['price']
|
||||
|
||||
# 颜色对应商品图
|
||||
color_item['images'] = get_image_urls(tab = color_tab)
|
||||
|
||||
# 颜色对应尺码
|
||||
radio_eles = color_tab.ele('.prod-size-list').eles('.prod-size')
|
||||
for radio_ele in radio_eles:
|
||||
value = radio_ele.ele('@tag()=label').text
|
||||
if value == None:
|
||||
continue
|
||||
size_data.append(value)
|
||||
color_item['size'] = size_data
|
||||
|
||||
real_color_data[color_tab.ele('.page-title').text.split(' / ')[-1]] = color_item
|
||||
color_data = real_color_data
|
||||
|
||||
goods_info.attr = 'M'
|
||||
goods_info.title = goods_info.title.split(' / ')[0]
|
||||
goods_info.attr_items = m_data
|
||||
for color_name, color_item in color_data.items():
|
||||
for color_image in color_item['images']:
|
||||
if color_image in goods_info.images:
|
||||
continue
|
||||
goods_info.images.append(color_image)
|
||||
|
||||
# if color_data:
|
||||
item_data = []
|
||||
for color_name, color_item in color_data.items():
|
||||
for size in color_item['size']:
|
||||
item_data.append([color_name, size])
|
||||
for attribute_items in item_data:
|
||||
goods_info.p_lists.append(types.GoodsInfo.GoodsInfoP(
|
||||
attr_items=attribute_items,
|
||||
price=color_data[attribute_items[0]]['price'],
|
||||
old_price=color_data[attribute_items[0]]['price'],
|
||||
images=color_data[attribute_items[0]]['images'],
|
||||
))
|
||||
|
||||
except Exception as e:
|
||||
try:
|
||||
tab.close()
|
||||
color_tab.close()
|
||||
except:
|
||||
pass
|
||||
raise Exception(e)
|
||||
try:
|
||||
tab.close()
|
||||
color_tab.close()
|
||||
except:
|
||||
pass
|
||||
return goods_info
|
||||
86
lib/module/example.py
Normal file
86
lib/module/example.py
Normal file
@@ -0,0 +1,86 @@
|
||||
from core import spiders, types
|
||||
from utils import formats, messages
|
||||
|
||||
class SpiderModule(spiders.Spiders):
|
||||
project_name = "example"
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
self.project_name,
|
||||
bitch = 10,
|
||||
worker_num = 1,
|
||||
switch_clash = False,
|
||||
reflush_browser = False
|
||||
)
|
||||
|
||||
def get_category_urls(self) -> list[str]:
|
||||
category_urls = []
|
||||
|
||||
pass
|
||||
|
||||
return category_urls
|
||||
|
||||
def get_goods_urls(self, category_url: str) -> list[str]:
|
||||
self.tab.get(f"{category_url}")
|
||||
goods_urls = []
|
||||
|
||||
pass
|
||||
|
||||
return goods_urls
|
||||
|
||||
def get_goods_info(self, url) -> types.GoodsInfo:
|
||||
def get_image_urls():
|
||||
image_urls = []
|
||||
pass
|
||||
return image_urls
|
||||
|
||||
tab = self.browser.new_tab(url)
|
||||
tab.set.window.max()
|
||||
spu = formats.url_to_spu(url)
|
||||
|
||||
desc = "简介"
|
||||
brand = "品牌"
|
||||
title = "标题"
|
||||
price = 0.00
|
||||
old_price = price
|
||||
|
||||
main_images = get_image_urls()
|
||||
|
||||
goods_info = types.GoodsInfo(
|
||||
title=title,
|
||||
desc=desc,
|
||||
brand=brand,
|
||||
url=url,
|
||||
spu=spu,
|
||||
price=price,
|
||||
old_price=old_price,
|
||||
)
|
||||
|
||||
m_data = []
|
||||
attr_items = []
|
||||
|
||||
if len(attr_items) == 0:
|
||||
goods_info.attr = 'S'
|
||||
goods_info.attr_items = []
|
||||
goods_info.images = main_images
|
||||
goods_info.p_lists = []
|
||||
else:
|
||||
goods_info.attr = 'M'
|
||||
goods_info.attr_items = m_data
|
||||
for attr_item in attr_items:
|
||||
goods_info.p_lists.append(types.GoodsInfo.GoodsInfoP(
|
||||
attr_items=attr_item['items'],
|
||||
price=attr_item['price'],
|
||||
old_price=attr_item['old_price'],
|
||||
images=attr_item['images']
|
||||
))
|
||||
for image_url in attr_item['images']:
|
||||
if image_url not in main_images:
|
||||
main_images.append(image_url)
|
||||
goods_info.images = main_images
|
||||
|
||||
try:
|
||||
tab.close()
|
||||
except:
|
||||
pass
|
||||
return goods_info
|
||||
141
lib/module/friskybusiness.py
Normal file
141
lib/module/friskybusiness.py
Normal file
@@ -0,0 +1,141 @@
|
||||
from core import spiders, types
|
||||
from utils import formats, messages
|
||||
|
||||
class SpiderModule(spiders.Spiders):
|
||||
project_name = "friskybusiness"
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
self.project_name,
|
||||
bitch = 30,
|
||||
worker_num = 5,
|
||||
switch_clash = False,
|
||||
reflush_browser = False
|
||||
)
|
||||
self.tab.get('https://friskybusiness.sg/')
|
||||
# input('wait:')
|
||||
|
||||
def get_category_urls(self) -> list[str]:
|
||||
category_urls = []
|
||||
|
||||
one_menu_eles = self.tab.eles('xpath=/html/body/header/height-observer/x-header/nav[2]/ul/li')
|
||||
for one_index, one_menu_ele in enumerate(one_menu_eles[:-1]):
|
||||
|
||||
one_link_ele = one_menu_ele.ele('@tag()=summary')
|
||||
one_url = one_link_ele.attr('data-follow-link')
|
||||
one_name = one_link_ele.text.replace('/', '-')
|
||||
category_urls.append(f"{one_url}#{one_name}")
|
||||
messages.sendInfo(one_name)
|
||||
|
||||
if one_index == 0 or one_index == 6:
|
||||
two_menu_eles = one_menu_ele.eles('xpath=mega-menu-disclosure/details/div/div/a')
|
||||
else:
|
||||
two_menu_eles = one_menu_ele.eles('xpath=mega-menu-disclosure/details/div/ul/li', timeout=1)
|
||||
for two_index, two_menu_ele in enumerate(two_menu_eles):
|
||||
if one_index == 0 or one_index == 6:
|
||||
two_link_ele = two_menu_ele
|
||||
else:
|
||||
two_link_ele = two_menu_ele.ele('@tag()=a')
|
||||
two_url = two_link_ele.attr('href')
|
||||
two_name = two_link_ele.text.replace('/', '-').replace(',', ',').replace('#', ' ')
|
||||
category_urls.append(f"{two_url}#{one_name}/{two_name}")
|
||||
|
||||
try:
|
||||
three_menu_eles = two_menu_ele.eles(f'xpath=div/ul/li')
|
||||
except:
|
||||
continue
|
||||
for three_menu_ele in three_menu_eles:
|
||||
three_link_ele = three_menu_ele.ele('@tag()=a')
|
||||
three_url = three_link_ele.attr('href')
|
||||
three_name = three_link_ele.text.replace('/', '-').replace(',', ',').replace('#', ' ')
|
||||
category_urls.append(f"{three_url}#{one_name}/{two_name}/{three_name}")
|
||||
|
||||
return category_urls
|
||||
|
||||
def get_goods_urls(self, category_url: str) -> list[str]:
|
||||
page = 1
|
||||
self.tab.get(f"{category_url}?page={page}")
|
||||
goods_urls = []
|
||||
|
||||
#####获取页数####
|
||||
|
||||
#################
|
||||
|
||||
goods_urls = []
|
||||
while True:
|
||||
self.tab.scroll.to_bottom()
|
||||
try:
|
||||
goods_eles = self.tab.eles('#:snize-product-', timeout=5)
|
||||
for goods_ele in goods_eles:
|
||||
goods_url = f"{goods_ele.ele('@tag()=a').attr('href')}"
|
||||
goods_urls.append(goods_url)
|
||||
if len(goods_eles) == 0:
|
||||
break
|
||||
except:
|
||||
break
|
||||
page += 1
|
||||
self.tab.get(f"{category_url}?page={page}")
|
||||
|
||||
messages.sendInfo(f"{len(goods_urls)} 个")
|
||||
|
||||
return goods_urls
|
||||
|
||||
def get_goods_info(self, url) -> types.GoodsInfo:
|
||||
def get_image_urls():
|
||||
image_urls = []
|
||||
image_eles = tab.eles('xpath=/html/body/main/section[1]/div/div/product-rerender/div/product-gallery/safe-sticky/product-gallery-navigation/button')
|
||||
|
||||
for image_ele in image_eles[-1:]:
|
||||
image_url = image_ele.ele('xpath=img').attr('src')
|
||||
image_urls.append(image_url)
|
||||
return image_urls
|
||||
|
||||
tab = self.browser.new_tab(url)
|
||||
tab.set.window.max()
|
||||
spu = formats.url_to_spu(url)
|
||||
|
||||
try:
|
||||
h1_ele = tab.ele('@tag()=h1')
|
||||
brand = ''
|
||||
title = h1_ele.text
|
||||
|
||||
desc = ""
|
||||
try:
|
||||
desc = formats.clean_html(tab.ele('.liquid').html)
|
||||
except:
|
||||
pass
|
||||
|
||||
price_list = tab.ele('.price-list price-list--product')
|
||||
price = price_list.ele('@tag()=sale-price').ele('.money').text.replace('$', '').replace(',', '')
|
||||
try:
|
||||
old_price = price_list.ele('@tag()=compare-at-price').ele('.money').text.replace('$', '').replace(',', '')
|
||||
except:
|
||||
old_price = price
|
||||
|
||||
main_images = get_image_urls()
|
||||
|
||||
goods_info = types.GoodsInfo(
|
||||
title=title,
|
||||
desc=desc,
|
||||
brand=brand,
|
||||
url=url,
|
||||
spu=spu,
|
||||
price=price,
|
||||
old_price=old_price,
|
||||
)
|
||||
|
||||
goods_info.attr = 'S'
|
||||
goods_info.attr_items = []
|
||||
goods_info.images = main_images
|
||||
goods_info.p_lists = []
|
||||
except Exception as e:
|
||||
try:
|
||||
tab.close()
|
||||
except:
|
||||
pass
|
||||
raise Exception(e)
|
||||
try:
|
||||
tab.close()
|
||||
except:
|
||||
pass
|
||||
return goods_info
|
||||
217
lib/module/peek_cloppenburg.py
Normal file
217
lib/module/peek_cloppenburg.py
Normal file
@@ -0,0 +1,217 @@
|
||||
from core import spiders, types
|
||||
from utils import formats, messages
|
||||
|
||||
class SpiderModule(spiders.Spiders):
|
||||
project_name = "peek-cloppenburg"
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
self.project_name,
|
||||
bitch = 30,
|
||||
worker_num = 5,
|
||||
switch_clash = False,
|
||||
reflush_browser = False
|
||||
)
|
||||
|
||||
def get_category_urls(self) -> list[str]:
|
||||
category_urls = []
|
||||
|
||||
self.tab.get('https://www.peek-cloppenburg.at/')
|
||||
one_menu_eles = self.tab.ele('@data-testid=header-links').eles('@tag()=a')
|
||||
for one_menu_ele in one_menu_eles:
|
||||
one_link_ele = one_menu_ele
|
||||
one_url = one_link_ele.attr('href')
|
||||
one_name = one_link_ele.text.replace('/', '-')
|
||||
category_urls.append(f"{one_url}#{one_name}")
|
||||
messages.sendInfo(one_name)
|
||||
one_link_ele.click()
|
||||
self.tab.wait(3)
|
||||
|
||||
two_menu_eles = self.tab.eles('xpath=//*[@id="__next"]/div[1]/header/div[2]/div[2]/nav/a', timeout=1)
|
||||
for two_index, two_menu_ele in enumerate(two_menu_eles):
|
||||
two_link_ele = two_menu_ele
|
||||
two_url = two_link_ele.attr('href')
|
||||
two_name = two_link_ele.text.replace('/', '-')
|
||||
category_urls.append(f"{two_url}#{one_name}/{two_name}")
|
||||
|
||||
try:
|
||||
three_menu_eles = self.tab.ele(f'xpath=//*[@id="__next"]/div[1]/header/div[2]/div[2]/nav/div[{two_index+1}]/div/div[1]').eles('@tag()=li')
|
||||
except:
|
||||
continue
|
||||
for three_menu_ele in three_menu_eles:
|
||||
three_link_ele = three_menu_ele.ele('@tag()=a')
|
||||
three_url = three_link_ele.attr('href')
|
||||
three_name = three_link_ele.text.replace('/', '-')
|
||||
category_urls.append(f"{three_url}#{one_name}/{two_name}/{three_name}")
|
||||
|
||||
return category_urls
|
||||
|
||||
def get_goods_urls(self, category_url: str) -> list[str]:
|
||||
self.tab.get(f"{category_url}?page=1")
|
||||
goods_urls = []
|
||||
|
||||
max_page = 1
|
||||
#####获取页数####
|
||||
try:
|
||||
max_page = int(self.tab.eles('@data-testid=pagination-item')[-1].text)
|
||||
except:
|
||||
pass
|
||||
#################
|
||||
|
||||
goods_urls = []
|
||||
if max_page > 1:
|
||||
for page in range(1, max_page+1):
|
||||
if page > 1:
|
||||
self.tab.get(f"{category_url}?page={page}&userId=123456")
|
||||
|
||||
goods_eles = self.tab.eles('xpath=//*[@id="__next"]/div[2]/div/section/div/div[2]/div[5]/div/section[1]/section/div/div')
|
||||
for goods_ele in goods_eles:
|
||||
goods_url = f"{goods_ele.ele('@tag()=a').attr('href')}"
|
||||
goods_urls.append(goods_url)
|
||||
messages.sendInfo(f"{page}/{max_page}")
|
||||
else:
|
||||
goods_eles = self.tab.eles('xpath=//*[@id="__next"]/div[2]/div/section/div/div[2]/div[5]/div/section[1]/section/div/div')
|
||||
for goods_ele in goods_eles:
|
||||
goods_url = f"{goods_ele.ele('@tag()=a').attr('href')}"
|
||||
goods_urls.append(goods_url)
|
||||
|
||||
return goods_urls
|
||||
|
||||
def get_goods_info(self, url) -> types.GoodsInfo:
|
||||
def get_image_urls():
|
||||
image_urls = []
|
||||
image_eles = tab.ele('#photoswipe-gallery').eles('@tag()=a')
|
||||
|
||||
for image_ele in image_eles:
|
||||
image_url = image_ele.attr('href')
|
||||
image_urls.append(image_url)
|
||||
return image_urls
|
||||
|
||||
def get_size_eles():
|
||||
try:
|
||||
eles = tab.ele('.option-picker mt-2 ').eles('@tag()=li')
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
eles = tab.ele('.option-picker mt-2 long-label ').eles('@tag()=li')
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
eles = tab.ele('.option-picker mt-2 out-of-stock').eles('@tag()=li')
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
eles = tab.ele('.option-picker mt-2 long-label out-of-stock').eles('@tag()=li')
|
||||
except:
|
||||
pass
|
||||
return eles
|
||||
|
||||
tab = self.browser.new_tab(url)
|
||||
tab.set.window.max()
|
||||
spu = formats.url_to_spu(url)
|
||||
|
||||
try:
|
||||
h1_eles = tab.ele('@tag()=h1', timeout=10).eles('@tag()=span')
|
||||
brand = ''
|
||||
try:
|
||||
brand = h1_eles[0].text
|
||||
title = h1_eles[1].text
|
||||
except:
|
||||
title = tab.ele('@tag()=h1').text
|
||||
|
||||
desc = ""
|
||||
try:
|
||||
desc = formats.clean_html(f"{tab.ele('#accordion-panel-material-care').html}{tab.ele('#accordion-panel-details').html}")
|
||||
except:
|
||||
pass
|
||||
|
||||
price = tab.ele('.:text-pdp-price-primary-xs font-bold').text.split(' ')[0].replace(',', '.')
|
||||
try:
|
||||
old_price = tab.ele('.line-through').text.split(' ')[0].replace(',', '.')
|
||||
except:
|
||||
old_price = price
|
||||
|
||||
main_images = get_image_urls()
|
||||
|
||||
goods_info = types.GoodsInfo(
|
||||
title=title,
|
||||
desc=desc,
|
||||
brand=brand,
|
||||
url=url,
|
||||
spu=spu,
|
||||
price=price,
|
||||
old_price=old_price,
|
||||
)
|
||||
|
||||
m_data = []
|
||||
attr_items = []
|
||||
color_urls = []
|
||||
try:
|
||||
color_eles = tab.ele('.pt-6 xl:pt-8 -mr-6 md:mr-0').eles('@tag()=li')
|
||||
m_data.append('Farbe')
|
||||
for color_ele in color_eles:
|
||||
color_url = color_ele.ele('@tag()=a').attr('href')
|
||||
color_urls.append(color_url)
|
||||
except:
|
||||
pass
|
||||
m_data.append('Größe')
|
||||
|
||||
if len(color_urls) > 0:
|
||||
for color_url in color_urls:
|
||||
color_images = main_images
|
||||
if color_url != url:
|
||||
tab.get(color_url)
|
||||
color_images = get_image_urls()
|
||||
|
||||
price = tab.ele('.:text-pdp-price-primary-xs font-bold').text.split(' ')[0].replace(',', '')
|
||||
try:
|
||||
old_price = tab.ele('.line-through').text.split(' ')[0].replace(',', '')
|
||||
except:
|
||||
old_price = price
|
||||
|
||||
color_name = tab.ele('.text-cp-md font-bold').ele('xpath=text()[3]')
|
||||
|
||||
size_eles = get_size_eles()
|
||||
for size_ele in size_eles:
|
||||
size_name = size_ele.ele('.text-cp-md truncate').text
|
||||
|
||||
attr_items.append({
|
||||
'url': color_url,
|
||||
'items': [color_name, size_name],
|
||||
'price': price,
|
||||
'old_price': old_price,
|
||||
'images': color_images
|
||||
})
|
||||
|
||||
if len(attr_items) == 0:
|
||||
goods_info.attr = 'S'
|
||||
goods_info.attr_items = []
|
||||
goods_info.images = main_images
|
||||
goods_info.p_lists = []
|
||||
else:
|
||||
goods_info.attr = 'M'
|
||||
goods_info.attr_items = m_data
|
||||
for attr_item in attr_items:
|
||||
goods_info.p_lists.append(types.GoodsInfo.GoodsInfoP(
|
||||
url=attr_item['url'],
|
||||
attr_items=attr_item['items'],
|
||||
price=attr_item['price'],
|
||||
old_price=attr_item['old_price'],
|
||||
images=attr_item['images'],
|
||||
))
|
||||
for image_url in attr_item['images']:
|
||||
if image_url not in main_images:
|
||||
main_images.append(image_url)
|
||||
goods_info.images = main_images
|
||||
goods_info.p_urls = color_urls
|
||||
except Exception as e:
|
||||
try:
|
||||
tab.close()
|
||||
except:
|
||||
pass
|
||||
raise Exception(e)
|
||||
try:
|
||||
tab.close()
|
||||
except:
|
||||
pass
|
||||
return goods_info
|
||||
213
lib/module/peek_cloppenburg_nl.py
Normal file
213
lib/module/peek_cloppenburg_nl.py
Normal file
@@ -0,0 +1,213 @@
|
||||
from core import spiders, types
|
||||
from utils import formats, messages
|
||||
|
||||
class SpiderModule(spiders.Spiders):
|
||||
project_name = "peek-cloppenburg-nl"
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
self.project_name,
|
||||
bitch = 30,
|
||||
worker_num = 5,
|
||||
switch_clash = False,
|
||||
reflush_browser = False
|
||||
)
|
||||
|
||||
def get_category_urls(self) -> list[str]:
|
||||
category_urls = []
|
||||
|
||||
self.tab.get('https://www.peek-cloppenburg.nl/')
|
||||
one_menu_eles = self.tab.ele('@data-testid=header-links').eles('@tag()=a')
|
||||
for one_menu_ele in one_menu_eles:
|
||||
one_link_ele = one_menu_ele
|
||||
one_url = one_link_ele.attr('href')
|
||||
one_name = one_link_ele.text.replace('/', '-')
|
||||
category_urls.append(f"{one_url}#{one_name}")
|
||||
messages.sendInfo(one_name)
|
||||
one_link_ele.click()
|
||||
self.tab.wait(3)
|
||||
|
||||
two_menu_eles = self.tab.eles('xpath=//*[@id="__next"]/div[1]/header/div/div[2]/nav/a', timeout=1)
|
||||
for two_index, two_menu_ele in enumerate(two_menu_eles):
|
||||
two_link_ele = two_menu_ele
|
||||
two_url = two_link_ele.attr('href')
|
||||
two_name = two_link_ele.text.replace('/', '-')
|
||||
category_urls.append(f"{two_url}#{one_name}/{two_name}")
|
||||
|
||||
try:
|
||||
three_menu_eles = self.tab.ele(f'xpath=//*[@id="__next"]/div[1]/header/div/div[2]/nav/div[{two_index+1}]/div/div[1]').eles('@tag()=li')
|
||||
except:
|
||||
continue
|
||||
for three_menu_ele in three_menu_eles:
|
||||
three_link_ele = three_menu_ele.ele('@tag()=a')
|
||||
three_url = three_link_ele.attr('href')
|
||||
three_name = three_link_ele.text.replace('/', '-')
|
||||
category_urls.append(f"{three_url}#{one_name}/{two_name}/{three_name}")
|
||||
|
||||
return category_urls
|
||||
|
||||
def get_goods_urls(self, category_url: str) -> list[str]:
|
||||
self.tab.get(f"{category_url}?page=1")
|
||||
goods_urls = []
|
||||
|
||||
max_page = 1
|
||||
#####获取页数####
|
||||
try:
|
||||
max_page = int(self.tab.eles('@data-testid=pagination-item')[-1].text)
|
||||
except:
|
||||
pass
|
||||
#################
|
||||
|
||||
goods_urls = []
|
||||
if max_page > 1:
|
||||
for page in range(1, max_page+1):
|
||||
if page > 1:
|
||||
self.tab.get(f"{category_url}?page={page}&userId=123456")
|
||||
|
||||
goods_eles = self.tab.eles('xpath=//*[@id="__next"]/div[2]/div/section/div/div[2]/div[5]/div/section[1]/section/div/div')
|
||||
for goods_ele in goods_eles:
|
||||
goods_url = f"{goods_ele.ele('@tag()=a').attr('href')}"
|
||||
goods_urls.append(goods_url)
|
||||
messages.sendInfo(f"{page}/{max_page}")
|
||||
else:
|
||||
goods_eles = self.tab.eles('xpath=//*[@id="__next"]/div[2]/div/section/div/div[2]/div[5]/div/section[1]/section/div/div')
|
||||
for goods_ele in goods_eles:
|
||||
goods_url = f"{goods_ele.ele('@tag()=a').attr('href')}"
|
||||
goods_urls.append(goods_url)
|
||||
|
||||
return goods_urls
|
||||
|
||||
def get_goods_info(self, url) -> types.GoodsInfo:
|
||||
def get_image_urls():
|
||||
image_urls = []
|
||||
image_eles = tab.ele('#photoswipe-gallery').eles('@tag()=a')
|
||||
|
||||
for image_ele in image_eles:
|
||||
image_url = image_ele.attr('href')
|
||||
image_urls.append(image_url)
|
||||
return image_urls
|
||||
|
||||
def get_size_eles():
|
||||
try:
|
||||
eles = tab.ele('.option-picker mt-2 ').eles('@tag()=li')
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
eles = tab.ele('.option-picker mt-2 long-label ').eles('@tag()=li')
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
eles = tab.ele('.option-picker mt-2 out-of-stock').eles('@tag()=li')
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
eles = tab.ele('.option-picker mt-2 long-label out-of-stock').eles('@tag()=li')
|
||||
except:
|
||||
pass
|
||||
return eles
|
||||
|
||||
tab = self.browser.new_tab(url)
|
||||
tab.set.window.max()
|
||||
spu = formats.url_to_spu(url)
|
||||
|
||||
try:
|
||||
h1_eles = tab.ele('@tag()=h1').eles('@tag()=span')
|
||||
brand = h1_eles[0].text
|
||||
title = h1_eles[1].text
|
||||
|
||||
desc = ""
|
||||
try:
|
||||
desc = formats.clean_html(f"{tab.ele('#accordion-panel-material-care').html}{tab.ele('#accordion-panel-details').html}")
|
||||
except:
|
||||
pass
|
||||
|
||||
price = tab.ele('.:text-pdp-price-primary-xs font-bold').text.split(' ')[1].replace(',', '.')
|
||||
try:
|
||||
old_price = tab.ele('.line-through').text.split(' ')[1].replace(',', '.')
|
||||
except:
|
||||
old_price = price
|
||||
|
||||
main_images = get_image_urls()
|
||||
|
||||
goods_info = types.GoodsInfo(
|
||||
title=title,
|
||||
desc=desc,
|
||||
brand=brand,
|
||||
url=url,
|
||||
spu=spu,
|
||||
price=price,
|
||||
old_price=old_price,
|
||||
)
|
||||
|
||||
m_data = []
|
||||
attr_items = []
|
||||
color_urls = []
|
||||
try:
|
||||
color_eles = tab.ele('.pt-6 xl:pt-8 -mr-6 md:mr-0').eles('@tag()=li')
|
||||
m_data.append('Kleur')
|
||||
for color_ele in color_eles:
|
||||
color_url = color_ele.ele('@tag()=a').attr('href')
|
||||
color_urls.append(color_url)
|
||||
except:
|
||||
pass
|
||||
m_data.append('Maat')
|
||||
|
||||
if len(color_urls) > 0:
|
||||
for color_url in color_urls:
|
||||
color_images = main_images
|
||||
if color_url != url:
|
||||
tab.get(color_url)
|
||||
color_images = get_image_urls()
|
||||
|
||||
price = tab.ele('.:text-pdp-price-primary-xs font-bold').text.split(' ')[1].replace(',', '.')
|
||||
try:
|
||||
old_price = tab.ele('.line-through').text.split(' ')[1].replace(',', '.')
|
||||
except:
|
||||
old_price = price
|
||||
|
||||
color_name = tab.ele('.text-cp-md font-bold').ele('xpath=text()[3]')
|
||||
|
||||
size_eles = get_size_eles()
|
||||
for size_ele in size_eles:
|
||||
size_name = size_ele.ele('.text-cp-md truncate').text
|
||||
|
||||
attr_items.append({
|
||||
'url': color_url,
|
||||
'items': [color_name, size_name],
|
||||
'price': price,
|
||||
'old_price': old_price,
|
||||
'images': color_images
|
||||
})
|
||||
|
||||
if len(attr_items) == 0:
|
||||
goods_info.attr = 'S'
|
||||
goods_info.attr_items = []
|
||||
goods_info.images = main_images
|
||||
goods_info.p_lists = []
|
||||
else:
|
||||
goods_info.attr = 'M'
|
||||
goods_info.attr_items = m_data
|
||||
for attr_item in attr_items:
|
||||
goods_info.p_lists.append(types.GoodsInfo.GoodsInfoP(
|
||||
url=attr_item['url'],
|
||||
attr_items=attr_item['items'],
|
||||
price=attr_item['price'],
|
||||
old_price=attr_item['old_price'],
|
||||
images=attr_item['images'],
|
||||
))
|
||||
for image_url in attr_item['images']:
|
||||
if image_url not in main_images:
|
||||
main_images.append(image_url)
|
||||
goods_info.images = main_images
|
||||
goods_info.p_urls = color_urls
|
||||
except Exception as e:
|
||||
try:
|
||||
tab.close()
|
||||
except:
|
||||
pass
|
||||
raise Exception(e)
|
||||
try:
|
||||
tab.close()
|
||||
except:
|
||||
pass
|
||||
return goods_info
|
||||
371
lib/module/ssfshop.py
Normal file
371
lib/module/ssfshop.py
Normal file
@@ -0,0 +1,371 @@
|
||||
from core import spiders, types
|
||||
from utils import formats, messages, files
|
||||
import requests
|
||||
|
||||
class SpiderModule(spiders.Spiders):
|
||||
project_name = "ssfshop"
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
self.project_name,
|
||||
bitch = 300,
|
||||
worker_num = 24,
|
||||
switch_clash = False,
|
||||
reflush_browser = False
|
||||
)
|
||||
|
||||
def get_category_urls(self) -> list[str]:
|
||||
category_urls = []
|
||||
|
||||
self.tab.get('https://www.ssfshop.com/')
|
||||
one_menu_eles = self.tab.eles('xpath=/html/body/div[5]/header/div[2]/div[2]/div/div[1]/div[1]/ul/li')
|
||||
for one_menu_ele in one_menu_eles:
|
||||
one_link_ele = one_menu_ele.ele('@tag()=a')
|
||||
one_url = one_link_ele.attr('href')
|
||||
one_name = one_link_ele.text.replace('/', '-')
|
||||
if one_name == '라이프':
|
||||
continue
|
||||
category_urls.append(f"{one_url}#{one_name}")
|
||||
messages.sendInfo(one_name)
|
||||
|
||||
two_menu_eles = one_menu_ele.eles('xpath=div/div/div[1]/ul/li')
|
||||
for two_menu_ele in two_menu_eles:
|
||||
two_link_ele = two_menu_ele.ele('@tag()=a')
|
||||
two_url = two_link_ele.attr('href')
|
||||
two_name = two_link_ele.text.replace('/', '-')
|
||||
if two_name == '메인':
|
||||
continue
|
||||
category_urls.append(f"{two_url}#{one_name}/{two_name}")
|
||||
two_menu_eles = one_menu_ele.eles('xpath=div/div/div[2]/ul/li')
|
||||
for two_menu_ele in two_menu_eles:
|
||||
two_link_ele = two_menu_ele.ele('@tag()=a')
|
||||
two_url = two_link_ele.attr('href')
|
||||
two_name = two_link_ele.text.replace('/', '-')
|
||||
if two_name == '메인':
|
||||
continue
|
||||
category_urls.append(f"{two_url}#{one_name}/Top Brand/{two_name}")
|
||||
|
||||
# three_menu_eles = two_menu_ele.eles('xpath=ul/li')
|
||||
# for three_menu_ele in three_menu_eles:
|
||||
# three_link_ele = three_menu_ele.ele('@tag()=a')
|
||||
# three_url = three_link_ele.attr('href')
|
||||
# three_name = three_link_ele.text.replace('/', '-')
|
||||
# category_urls.append(f"{three_url}#{one_name}/{two_name}/{three_name}")
|
||||
|
||||
return category_urls
|
||||
|
||||
def get_goods_urls(self, category_url: str) -> list[str]:
|
||||
page = 1
|
||||
self.tab.get(f"{category_url}¤tPage={page}&sortColumn=SALE_QTY_SEQ&serviceType=DSP&ctgrySectCd=GNRL_CTGRY&fitPsbYn=N")
|
||||
goods_urls = []
|
||||
|
||||
url_index = {}
|
||||
while True:
|
||||
self.tab.scroll.to_bottom()
|
||||
page_urls = []
|
||||
goods_eles = self.tab.eles('.god-item')
|
||||
for goods_ele in goods_eles:
|
||||
goods_link_ele = goods_ele.ele('xpath=a')
|
||||
if goods_link_ele.attr('href') in url_index:
|
||||
continue
|
||||
page_urls.append(goods_link_ele.attr('href'))
|
||||
url_index[goods_link_ele.attr('href')] = None
|
||||
|
||||
if len(page_urls) == 0:
|
||||
break
|
||||
if len(goods_urls) > 5000:
|
||||
break
|
||||
goods_urls += page_urls
|
||||
page += 1
|
||||
self.tab.get(f"{category_url}¤tPage={page}&sortColumn=SALE_QTY_SEQ&serviceType=DSP&ctgrySectCd=GNRL_CTGRY&fitPsbYn=N")
|
||||
self.tab.wait(1)
|
||||
|
||||
return goods_urls
|
||||
|
||||
def get_goods_info(self, url: str) -> types.GoodsInfo:
|
||||
def get_image_urls():
|
||||
image_urls = []
|
||||
|
||||
for _ in range(10):
|
||||
image_eles = tab.eles('xpath=//*[@id="godImgThumb"]/div')
|
||||
if len(image_eles) > 0:
|
||||
break
|
||||
tab.wait(3)
|
||||
for image_ele in image_eles:
|
||||
image_link_ele = image_ele
|
||||
image_urls.append('https://img.ssfshop.com'+image_link_ele.attr('data'))
|
||||
|
||||
return image_urls
|
||||
|
||||
def get_options(godNo, optValCd1, optValCd2 = ''):
|
||||
headers = {
|
||||
'Accept': 'application/json, text/javascript, */*; q=0.01',
|
||||
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
|
||||
'Connection': 'keep-alive',
|
||||
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||
'Origin': 'https://www.ssfshop.com',
|
||||
'Referer': url,
|
||||
'Sec-Fetch-Dest': 'empty',
|
||||
'Sec-Fetch-Mode': 'cors',
|
||||
'Sec-Fetch-Site': 'same-origin',
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36 Edg/146.0.0.0',
|
||||
'X-CSRF-TOKEN': 'e8e4bcd2-b976-4ca3-89b0-c85de0d1f3b0',
|
||||
'X-Requested-With': 'XMLHttpRequest',
|
||||
'sec-ch-ua': '"Chromium";v="146", "Not-A.Brand";v="24", "Microsoft Edge";v="146"',
|
||||
'sec-ch-ua-mobile': '?0',
|
||||
'sec-ch-ua-platform': '"Windows"',
|
||||
# 'Cookie': 'PCID=17748347492661999807244; UTID=17748347492661999807244; MAI="eyJsb2dpbiI6Ik4ifQ=="; WMONID=mUUUMLseCyQ; AWSALBAPP-1=_remove_; AWSALBAPP-2=_remove_; AWSALBAPP-3=_remove_; visid_incap_2173964=lpNXES71Q5iAc3f2rzl/jTzUyWkAAAAAQUIPAAAAAABeBQZ8XijRe/SDlNUYlcCm; nlbi_2173964_3216183=TbQ1Ku6HAX5AN79F2g4AdQAAAADFBJVdMHKyRlRjq5BE8+sZ; storedUrl=Y; visid_incap_2794548=/x/uA+w/Rna/+lXitrmX20DUyWkAAAAAQUIPAAAAAACOgO5Lt68U4l70FJ35r3uf; incap_ses_725_2173964=A1WxV+agRSxFFqDq6bcPCtPnyWkAAAAAl1pNcoghbBUv0Idr250rQA==; visid_incap_2898463=WYviBGzFSwWHcJFJUGirBdXnyWkAAAAAQUIPAAAAAAAtfVuBlsqIe97ZjwN6QI2j; nlbi_2898463=wXQSYet0xyoFwAnd4MbCSgAAAAArzXmJlyqxxSh3+i0S9GbO; incap_ses_725_2898463=s8pzSCxlllS0GaDq6bcPCtXnyWkAAAAAu3cfqwOGa86YepyhOT6TvQ==; nth_pcid=3d5ffbba-60dd-a49a-6747-a542beef7538-1774839765504; incap_ses_725_2794548=D/rjK2Wq+zSjGqDq6bcPCtXnyWkAAAAAwfdIptRC0JfZMv8gf0dFHw==; incap_ses_724_2173964=dLR3AfGiVBRg7b2bbSoMCuEsymkAAAAAo4viBM5iG3asWiau6QX32w==; incap_ses_724_2898463=/V2oJwzj6BLV8L2bbSoMCuMsymkAAAAA9Ybn1njwVQ3r7KT6QLCZcg==; incap_ses_724_2794548=3i9aHRkHkTdh872bbSoMCugsymkAAAAAt9AH6HTki4ssrvCcPmSpIA==; AWSALBTG=AIb2slX0AEp+Mv3KJalsspDk7579UU9Jv2/3kjqEGNWjsIrDM+27+/1Ke7bKfPJDQPkvjZ2Sxz50ZoGgs7wax+6xPQZc22NzAPVhfCwSibc44xWGCNEUT9ixCDWhVrmeHJTF4AGiXACsmVs+73qXWgynz4bNZxFvwGcomdcZ09QX; AWSALB=1Lc2nZgyDqlHzKH2Ht9zUCbVzO3nmyjbvR6L8TbjmEzgIJXLWPHd2TKRrA4NweRQ4J3aqEC0O7/FVTTgdHmYYm6M1K3NeLkZbyrFTXyTGk7GFDh5nYLYl/aBRLKe; AWSALBCORS=1Lc2nZgyDqlHzKH2Ht9zUCbVzO3nmyjbvR6L8TbjmEzgIJXLWPHd2TKRrA4NweRQ4J3aqEC0O7/FVTTgdHmYYm6M1K3NeLkZbyrFTXyTGk7GFDh5nYLYl/aBRLKe; AWSALBAPP-0=AAAAAAAAAACeq+TZG7CFWkFz6UEyoFzfgzCso6p2one/fqTkDd1D8aJwmBMDcXt1z/4SFXLjp7cnG/VXtUeFI5VsG2vzUNb7CeolT4ZG4OzG2MYZTDISyFXF0Ftu3Y5EnlA+ClLy5QvoVKs=; nlbi_2173964_2029297=AebNbzFaqQMN0dyi2g4AdQAAAADw44LnFE5aKd0nWF3BiMTo; STID=1774941024138741600844420260331161024; INFLOW_SN=99993; N_INFLOW_SN=Y; PC_JSESSIONID=054FCD4B9E7ABB3B015CF732C022A41B; incap_ses_138_2173964=rIZHCDf5DCYIKM99lkbqAV9zy2kAAAAAhshd7O+yiHEnrcRAybEDaw==; incap_ses_138_2898463=zRn2E3KmY3qUMM99lkbqAWBzy2kAAAAAT0zfogyh0Cs4exDxqH0C5w==; nlbi_2794548=gojpVZcccHOhC/svvoS1vwAAAAB8htUpn549dG0/xu4xckFq; incap_ses_138_2794548=A1yKCZEQdFLyMc99lkbqAWBzy2kAAAAAcNViNS39K56YSoYGpK3p0A==; _TODAYALLLIST="[{\\"todayGodSectCd\\":\\"GOD\\",\\"godNo\\":\\"GM0026011527285\\",\\"regDt\\":\\"1774840170633\\"},{\\"todayGodSectCd\\":\\"GOD\\",\\"godNo\\":\\"GQ3A26021060165\\",\\"regDt\\":\\"1774920131600\\"},{\\"todayGodSectCd\\":\\"GOD\\",\\"godNo\\":\\"GM0025122296270\\",\\"regDt\\":\\"1774920840210\\"},{\\"todayGodSectCd\\":\\"GOD\\",\\"godNo\\":\\"GQJ924040149659\\",\\"regDt\\":\\"1774921134062\\"},{\\"todayGodSectCd\\":\\"GOD\\",\\"godNo\\":\\"GR4H25042395931\\",\\"regDt\\":\\"1774921515277\\"},{\\"todayGodSectCd\\":\\"GOD\\",\\"godNo\\":\\"GQZG26012945089\\",\\"regDt\\":\\"1774921868451\\"},{\\"todayGodSectCd\\":\\"GOD\\",\\"godNo\\":\\"GQZG26012945090\\",\\"regDt\\":\\"1774921870125\\"},{\\"todayGodSectCd\\":\\"GOD\\",\\"godNo\\":\\"GQZG26012945092\\",\\"regDt\\":\\"1774921872189\\"},{\\"todayGodSectCd\\":\\"GOD\\",\\"godNo\\":\\"GRRI26030602949\\",\\"regDt\\":\\"1774941024251\\"},{\\"todayGodSectCd\\":\\"GOD\\",\\"godNo\\":\\"GRRI26030602950\\",\\"regDt\\":1774941046056}]"; godClickInfo=GQY026032636412||GM0026011527285||GQ3A26021060165||GM0025122296270||GR4H25042395931||GR4H25042395931||GQJ924040149659||GR4H25042395931||GR4H25042395931||GQZG26012945092||GQZG26012945089||GQZG26012945090||GQZG26012945092||GQZG26012945089||GQZG26012945090||GQZG26012945092||GRRI26030602949||GRRI26030602950',
|
||||
}
|
||||
|
||||
data = {
|
||||
'optValCd1': optValCd1,
|
||||
'optValCd2': optValCd2,
|
||||
'optValCd3': '',
|
||||
'godNo': godNo,
|
||||
}
|
||||
|
||||
response = requests.post('https://www.ssfshop.com/public/goods/selectGodDetailOpt', headers=headers, data=data, proxies={'http': 'http://127.0.0.1:7890','https': 'http://127.0.0.1:7890'})
|
||||
json_data = response.json()
|
||||
|
||||
options = {}
|
||||
if 'opt' not in json_data:
|
||||
return options
|
||||
|
||||
for option in json_data['opt']:
|
||||
for i in range(1, 6):
|
||||
key = f"optValNm{i}"
|
||||
if option[key]:
|
||||
options[option[key]] = {}
|
||||
break
|
||||
return options
|
||||
|
||||
tab = self.browser.new_tab(url)
|
||||
tab.set.window.max()
|
||||
spu = formats.url_to_spu(url)
|
||||
|
||||
try:
|
||||
brand = url.split('/')[3]
|
||||
godNo = url.split('/')[4]
|
||||
|
||||
title = tab.ele('#goodDtlTitle').text
|
||||
|
||||
desc = ""
|
||||
try:
|
||||
desc = tab.ele('#godsTabView').html
|
||||
except:
|
||||
pass
|
||||
|
||||
price = float(tab.ele('xpath=//*[@id="content"]/section/div[2]/div[2]/div[3]/span').ele('.price').text.replace(',', ''))
|
||||
try:
|
||||
old_price = float(tab.ele('xpath=//*[@id="content"]/section/div[2]/div[2]/div[3]/span/span[1]/del').text.replace(',', ''))
|
||||
except:
|
||||
old_price = price
|
||||
|
||||
main_images = get_image_urls()
|
||||
|
||||
goods_info = types.GoodsInfo(
|
||||
title=title,
|
||||
desc=desc,
|
||||
brand=brand,
|
||||
url=url,
|
||||
spu=spu,
|
||||
price=price,
|
||||
old_price=old_price,
|
||||
)
|
||||
|
||||
m_data = []
|
||||
attr_items = []
|
||||
color_urls = []
|
||||
try:
|
||||
tab.ele('.gods-option').ele('text=색상').click()
|
||||
color_eles = tab.eles('xpath=//*[@id="content"]/section/div[2]/div[2]/div[6]/div[1]/div/span/label')
|
||||
for color_ele in color_eles:
|
||||
color_url = color_ele.attr('onclick')
|
||||
if color_url:
|
||||
color_url = color_url.split("'")[1]
|
||||
else:
|
||||
color_url = url
|
||||
if 'https://' not in color_url:
|
||||
color_url = 'https://www.ssfshop.com'+color_url
|
||||
color_urls.append(color_url)
|
||||
except:
|
||||
pass
|
||||
|
||||
if len(color_urls) > 1:
|
||||
m_data = ["색상"]
|
||||
|
||||
try:
|
||||
option_eles = tab.ele('#prdInfoOptionArea').eles('#:optSelectPartmalDiv')
|
||||
except:
|
||||
option_eles = []
|
||||
for option_ele in option_eles:
|
||||
m_data.append(option_ele.ele('@tag()=input').attr('opt-nm'))
|
||||
m_data = m_data[:3]
|
||||
|
||||
option_data = {}
|
||||
if len(option_eles) > 0:
|
||||
try:
|
||||
option_eles[0].click()
|
||||
except:
|
||||
goods_info.attr = 'S'
|
||||
goods_info.attr_items = []
|
||||
goods_info.images = main_images
|
||||
goods_info.p_lists = []
|
||||
try:
|
||||
tab.close()
|
||||
except:
|
||||
pass
|
||||
return goods_info
|
||||
tab.wait(0.5)
|
||||
option1_eles = option_eles[0].eles('@tag()=li')
|
||||
for option1_ele in option1_eles:
|
||||
option_data[option1_ele.text] = get_options(godNo, option1_ele.text)
|
||||
for option2_name, items in option_data[option1_ele.text].items():
|
||||
option_data[option1_ele.text][option2_name] = get_options(godNo, option1_ele.text, option2_name)
|
||||
|
||||
if len(color_urls) > 1:
|
||||
for color_url in color_urls:
|
||||
color_images = main_images
|
||||
if color_url != url:
|
||||
tab.get(color_url)
|
||||
title = tab.ele('#goodDtlTitle').text
|
||||
color_images = get_image_urls()
|
||||
|
||||
godNo = color_url.split('/')[4]
|
||||
try:
|
||||
option_eles = tab.ele('#prdInfoOptionArea', timeout=5).eles('.select lg unapplied')
|
||||
except:
|
||||
option_eles = []
|
||||
option_data = {}
|
||||
if len(option_eles) > 0:
|
||||
option1_eles = option_eles[0].eles('xpath=div/ul/li')
|
||||
for option1_ele in option1_eles:
|
||||
option_data[option1_ele.text] = get_options(godNo, option1_ele.text)
|
||||
for option2_name, items in option_data[option1_ele.text].items():
|
||||
option_data[option1_ele.text][option2_name] = get_options(godNo, option1_ele.text, option2_name)
|
||||
|
||||
try:
|
||||
color_name = title.split('-')[1]
|
||||
except:
|
||||
color_name = tab.ele('.buy-txts').text
|
||||
|
||||
price = float(tab.ele('xpath=//*[@id="content"]/section/div[2]/div[2]/div[3]/span').ele('.price').text.replace(',', ''))
|
||||
try:
|
||||
old_price = float(tab.ele('xpath=//*[@id="content"]/section/div[2]/div[2]/div[3]/span/span[1]/del').text.replace(',', ''))
|
||||
except:
|
||||
old_price = price
|
||||
|
||||
if len(option_data) > 0:
|
||||
for option1_name, items1 in option_data.items():
|
||||
if len(items1) > 0:
|
||||
for option2_name, items2 in items1.items():
|
||||
attr_items.append({
|
||||
'url': color_url,
|
||||
'items': [color_name, option1_name, option2_name],
|
||||
'price': price,
|
||||
'old_price': old_price,
|
||||
'images': color_images
|
||||
})
|
||||
else:
|
||||
attr_items.append({
|
||||
'url': color_url,
|
||||
'items': [color_name, option1_name],
|
||||
'price': price,
|
||||
'old_price': old_price,
|
||||
'images': color_images
|
||||
})
|
||||
else:
|
||||
attr_items.append({
|
||||
'url': color_url,
|
||||
'items': [color_name],
|
||||
'price': price,
|
||||
'old_price': old_price,
|
||||
'images': color_images
|
||||
})
|
||||
else:
|
||||
for option1_name, items1 in option_data.items():
|
||||
if len(items1) > 0:
|
||||
for option2_name, items2 in items1.items():
|
||||
if len(items2) > 0:
|
||||
for option3_name, items3 in items2.items():
|
||||
attr_items.append({
|
||||
'url': url,
|
||||
'items': [option1_name, option2_name, option3_name],
|
||||
'price': price,
|
||||
'old_price': old_price,
|
||||
'images': []
|
||||
})
|
||||
else:
|
||||
attr_items.append({
|
||||
'url': url,
|
||||
'items': [option1_name, option2_name],
|
||||
'price': price,
|
||||
'old_price': old_price,
|
||||
'images': []
|
||||
})
|
||||
else:
|
||||
attr_items.append({
|
||||
'url': url,
|
||||
'items': [option1_name],
|
||||
'price': price,
|
||||
'old_price': old_price,
|
||||
'images': []
|
||||
})
|
||||
|
||||
if len(attr_items) == 0:
|
||||
try:
|
||||
tab.ele('.gods-option').ele('text=사이즈').click()
|
||||
size_eles = tab.eles('xpath=/html/body/div[5]/main/section/div[2]/div[2]/div[6]/div[1]/div/ul/li')
|
||||
goods_info.attr = 'M'
|
||||
goods_info.attr_items = ['사이즈']
|
||||
goods_info.images = main_images
|
||||
for size_ele in size_eles:
|
||||
goods_info.p_lists.append(types.GoodsInfo.GoodsInfoP(
|
||||
attr_items=[size_ele.text],
|
||||
price=price,
|
||||
old_price=old_price,
|
||||
images=[],
|
||||
))
|
||||
except:
|
||||
goods_info.attr = 'S'
|
||||
goods_info.attr_items = []
|
||||
goods_info.images = main_images
|
||||
goods_info.p_lists = []
|
||||
else:
|
||||
goods_info.attr = 'M'
|
||||
goods_info.attr_items = m_data
|
||||
for attr_item in attr_items:
|
||||
if len(attr_item['items']) != len(m_data):
|
||||
attr_item['items'] += m_data[len(attr_item['items']):]
|
||||
goods_info.p_lists.append(types.GoodsInfo.GoodsInfoP(
|
||||
url=attr_item['url'],
|
||||
attr_items=attr_item['items'],
|
||||
price=attr_item['price'],
|
||||
old_price=attr_item['old_price'],
|
||||
images=attr_item['images'],
|
||||
))
|
||||
for image_url in attr_item['images']:
|
||||
if image_url not in main_images:
|
||||
main_images.append(image_url)
|
||||
goods_info.images = main_images
|
||||
goods_info.p_urls = color_urls
|
||||
except Exception as e:
|
||||
try:
|
||||
tab.close()
|
||||
except:
|
||||
pass
|
||||
raise Exception(e)
|
||||
try:
|
||||
tab.close()
|
||||
except:
|
||||
pass
|
||||
return goods_info
|
||||
|
||||
def get_home(self):
|
||||
self.tab.get('https://www.ssfshop.com/main')
|
||||
li_eles = self.tab.ele('xpath=/html/body/div[5]/main/div[2]/section[2]/div/div[1]').eles('@tag()=li')
|
||||
categorys = []
|
||||
for li_ele in li_eles:
|
||||
a_ele = li_ele.ele('@tag()=a')
|
||||
categorys.append(f"{a_ele.attr('href')}#{a_ele.text}")
|
||||
files.save_list(f"{self.__data_path__}/categorys(home).txt", categorys)
|
||||
131
lib/module/taketoys.py
Normal file
131
lib/module/taketoys.py
Normal file
@@ -0,0 +1,131 @@
|
||||
from core import spiders, types
|
||||
from utils import formats, messages
|
||||
|
||||
class SpiderModule(spiders.Spiders):
|
||||
project_name = "taketoys"
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
self.project_name,
|
||||
bitch = 30,
|
||||
worker_num = 5,
|
||||
switch_clash = False,
|
||||
reflush_browser = False
|
||||
)
|
||||
self.tab.get('https://taketoys.sg/')
|
||||
# input('wait:')
|
||||
|
||||
def get_category_urls(self) -> list[str]:
|
||||
category_urls = []
|
||||
|
||||
one_menu_eles = self.tab.eles('xpath=/html/body/header/div[2]/div/nav/ul/li')
|
||||
for one_menu_ele in one_menu_eles[1:-1]:
|
||||
one_link_ele = one_menu_ele.ele('xpath=a')
|
||||
one_url = one_link_ele.attr('href')
|
||||
one_name = one_link_ele.text.replace('/', '-')
|
||||
category_urls.append(f"{one_url}#{one_name}")
|
||||
messages.sendInfo(one_name)
|
||||
|
||||
two_menu_eles = one_menu_ele.eles('xpath=ul/li', timeout=1)
|
||||
for two_index, two_menu_ele in enumerate(two_menu_eles):
|
||||
two_link_ele = two_menu_ele.ele('xpath=a')
|
||||
two_url = two_link_ele.attr('href')
|
||||
two_name = two_link_ele.text.replace('/', '-').replace(',', ',').replace('#', ' ')
|
||||
category_urls.append(f"{two_url}#{one_name}/{two_name}")
|
||||
|
||||
# try:
|
||||
# three_menu_eles = self.tab.ele(f'xpath=//*[@id="__next"]/div[1]/header/div/div[2]/nav/div[{two_index+1}]/div/div[1]').eles('@tag()=li')
|
||||
# except:
|
||||
# continue
|
||||
# for three_menu_ele in three_menu_eles:
|
||||
# three_link_ele = three_menu_ele.ele('@tag()=a')
|
||||
# three_url = three_link_ele.attr('href')
|
||||
# three_name = three_link_ele.text.replace('/', '-')
|
||||
# category_urls.append(f"{three_url}#{one_name}/{two_name}/{three_name}")
|
||||
|
||||
return category_urls
|
||||
|
||||
def get_goods_urls(self, category_url: str) -> list[str]:
|
||||
self.tab.get(f"{category_url}?page=1")
|
||||
goods_urls = []
|
||||
|
||||
#####获取页数####
|
||||
|
||||
#################
|
||||
|
||||
goods_urls = []
|
||||
while True:
|
||||
self.tab.scroll.to_bottom()
|
||||
try:
|
||||
self.tab.ele('text=Show more', timeout=5).click()
|
||||
self.tab.wait(1)
|
||||
except:
|
||||
break
|
||||
|
||||
goods_eles = self.tab.eles('.col-xs-6 col-sm-4 col-lg-3 item-wrapper')
|
||||
for goods_ele in goods_eles:
|
||||
goods_url = f"{goods_ele.ele('@tag()=a').attr('href')}"
|
||||
goods_urls.append(goods_url)
|
||||
messages.sendInfo(f"{len(goods_urls)} 个")
|
||||
|
||||
return goods_urls
|
||||
|
||||
def get_goods_info(self, url) -> types.GoodsInfo:
|
||||
def get_image_urls():
|
||||
image_urls = []
|
||||
image_eles = tab.eles('xpath=/html/body/main/div[2]/div[2]/div[2]/div[2]/div/div/div[3]/div[2]/div/div')
|
||||
|
||||
for image_ele in image_eles:
|
||||
image_url = image_ele.ele('xpath=img').attr('src')
|
||||
image_urls.append(image_url)
|
||||
return image_urls
|
||||
|
||||
tab = self.browser.new_tab(url)
|
||||
tab.set.window.max()
|
||||
spu = formats.url_to_spu(url)
|
||||
|
||||
try:
|
||||
h1_ele = tab.ele('@tag()=h1')
|
||||
brand = ''
|
||||
try:
|
||||
brand = h1_ele.ele('@tag()=strong').text
|
||||
except:
|
||||
pass
|
||||
title = h1_ele.ele('@tag()=span').text
|
||||
|
||||
desc = ""
|
||||
try:
|
||||
desc = formats.clean_html(tab.ele('#product-info-tab').html)
|
||||
except:
|
||||
pass
|
||||
|
||||
price = tab.ele('.price').attr('title').replace('SGD', '').replace(',', '')
|
||||
old_price = price
|
||||
|
||||
main_images = get_image_urls()
|
||||
|
||||
goods_info = types.GoodsInfo(
|
||||
title=title,
|
||||
desc=desc,
|
||||
brand=brand,
|
||||
url=url,
|
||||
spu=spu,
|
||||
price=price,
|
||||
old_price=old_price,
|
||||
)
|
||||
|
||||
goods_info.attr = 'S'
|
||||
goods_info.attr_items = []
|
||||
goods_info.images = main_images
|
||||
goods_info.p_lists = []
|
||||
except Exception as e:
|
||||
try:
|
||||
tab.close()
|
||||
except:
|
||||
pass
|
||||
raise Exception(e)
|
||||
try:
|
||||
tab.close()
|
||||
except:
|
||||
pass
|
||||
return goods_info
|
||||
140
lib/module/tfashion.py
Normal file
140
lib/module/tfashion.py
Normal file
@@ -0,0 +1,140 @@
|
||||
from core import spiders, types
|
||||
from utils import formats, messages
|
||||
|
||||
class SpiderModule(spiders.Spiders):
|
||||
project_name = "t-fashion"
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
self.project_name,
|
||||
bitch = 300,
|
||||
worker_num = 24,
|
||||
switch_clash = False,
|
||||
reflush_browser = False
|
||||
)
|
||||
|
||||
def get_category_urls(self) -> list[str]:
|
||||
category_urls = []
|
||||
|
||||
self.tab.get('https://www.t-fashion.jp/')
|
||||
one_menu_eles = self.tab.ele('.m-aside-menu-body').eles('.js-collest-li')
|
||||
for one_menu_ele in one_menu_eles:
|
||||
one_link_ele = one_menu_ele.ele('@tag()=a')
|
||||
# one_url = one_link_ele.attr('href')
|
||||
one_name = one_link_ele.text.replace('/', '-')
|
||||
# category_urls.append(f"{one_url}#{one_name}")
|
||||
messages.sendInfo(one_name)
|
||||
|
||||
two_menu_eles = one_menu_ele.eles('xpath=div/ul/li')
|
||||
for two_menu_ele in two_menu_eles[1:]:
|
||||
two_link_ele = two_menu_ele.ele('@tag()=a')
|
||||
two_url = two_link_ele.attr('href')
|
||||
two_name = two_link_ele.text.replace('/', '-')
|
||||
category_urls.append(f"{two_url}#{one_name}/{two_name}")
|
||||
|
||||
# three_menu_eles = two_menu_ele.eles('xpath=ul/li')
|
||||
# for three_menu_ele in three_menu_eles:
|
||||
# three_link_ele = three_menu_ele.ele('@tag()=a')
|
||||
# three_url = three_link_ele.attr('href')
|
||||
# three_name = three_link_ele.text.replace('/', '-')
|
||||
# category_urls.append(f"{three_url}#{one_name}/{two_name}/{three_name}")
|
||||
|
||||
return category_urls
|
||||
|
||||
def get_goods_urls(self, category_url: str) -> list[str]:
|
||||
page = 1
|
||||
self.tab.get(f"{category_url}?page={page}")
|
||||
goods_urls = []
|
||||
|
||||
while True:
|
||||
try:
|
||||
goods_eles = self.tab.eles('xpath=/html/body/div[1]/div[3]/div/section[1]/div/div[1]/div[1]/div[3]/ol/li')
|
||||
for goods_ele in goods_eles:
|
||||
goods_link_ele = goods_ele.ele('xpath=a')
|
||||
goods_urls.append(goods_link_ele.attr('href'))
|
||||
if len(goods_eles) == 0:
|
||||
break
|
||||
except:
|
||||
break
|
||||
page += 1
|
||||
self.tab.get(f"{category_url}?page={page}")
|
||||
|
||||
return goods_urls
|
||||
|
||||
def get_goods_info(self, url) -> types.GoodsInfo:
|
||||
def get_image_urls():
|
||||
image_urls = []
|
||||
|
||||
image_eles = tab.eles('xpath=//*[@id="item-gallery-parent"]/li')
|
||||
for image_ele in image_eles:
|
||||
image_link_ele = image_ele.ele('xpath=div/img')
|
||||
image_urls.append(image_link_ele.attr('src'))
|
||||
|
||||
return image_urls
|
||||
|
||||
tab = self.browser.new_tab(url)
|
||||
tab.set.window.max()
|
||||
spu = formats.url_to_spu(url)
|
||||
|
||||
try:
|
||||
brand = ''
|
||||
try:
|
||||
brand = tab.ele('xpath=//*[@id="current-tgoods-section"]/div/div[2]/div/div[1]/a[2]', timeout=10).text
|
||||
except:
|
||||
pass
|
||||
|
||||
title = tab.ele('@tag()=h1').text
|
||||
|
||||
desc = ""
|
||||
try:
|
||||
desc = formats.clean_html(tab.ele('xpath=//*[@id="slide-down-contents-parent"]'))
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
price = float(tab.ele('.is-fz28-36f is-fw-b ').text.replace(',', '').replace('¥', '').replace('(税込)', ''))
|
||||
except:
|
||||
price = float(tab.ele('.is-fz28-36f is-fw-b is-color-notice').text.replace(',', '').replace('¥', '').replace('(税込)', ''))
|
||||
old_price = price
|
||||
|
||||
main_images = get_image_urls()
|
||||
|
||||
goods_info = types.GoodsInfo(
|
||||
title=title,
|
||||
desc=desc,
|
||||
brand=brand,
|
||||
url=url,
|
||||
spu=spu,
|
||||
price=price,
|
||||
old_price=old_price,
|
||||
)
|
||||
|
||||
m_data = []
|
||||
attr_items = []
|
||||
goods_info.attr = 'M'
|
||||
goods_info.attr_items = ['Color', 'Size']
|
||||
goods_info.images = main_images
|
||||
color_eles = tab.eles('xpath=//*[@id="sku-list-box"]/div')
|
||||
for color_ele in color_eles:
|
||||
color_image = color_ele.ele('xpath=div/a').attr('href')
|
||||
color_name = color_ele.ele('xpath=div/a/span').text
|
||||
size_eles = color_ele.eles('xpath=ol/li')
|
||||
for size_ele in size_eles:
|
||||
size_name = size_ele.ele('xpath=div[1]/text()')
|
||||
goods_info.p_lists.append(types.GoodsInfo.GoodsInfoP(
|
||||
attr_items=[color_name, size_name],
|
||||
price=price,
|
||||
old_price=old_price,
|
||||
images=[color_image]
|
||||
))
|
||||
except Exception as e:
|
||||
try:
|
||||
tab.close()
|
||||
except:
|
||||
pass
|
||||
raise Exception(e)
|
||||
try:
|
||||
tab.close()
|
||||
except:
|
||||
pass
|
||||
return goods_info
|
||||
371
lib/shopyy.py
Normal file
371
lib/shopyy.py
Normal file
@@ -0,0 +1,371 @@
|
||||
import requests
|
||||
import lib
|
||||
from core import excels, browsers
|
||||
from utils import files, formats
|
||||
|
||||
class Shopyy:
|
||||
def __init__(self, save_folder):
|
||||
self.save_folder = save_folder
|
||||
|
||||
self.__album_template_path__ = 'sources/专辑模板.xlsx'
|
||||
self.__navigation_template_path__ = 'sources/导航模板.xlsx'
|
||||
|
||||
# 导航
|
||||
def generate_navigation(self, category_path):
|
||||
index = {}
|
||||
category_urls = files.load_lines(category_path)
|
||||
|
||||
WorkBook = excels.WorkBook(
|
||||
template=self.__navigation_template_path__,
|
||||
save_path=f"{self.save_folder}/导航表格.xlsx"
|
||||
)
|
||||
for category_url in category_urls:
|
||||
category = category_url.split('#')[-1]
|
||||
if category in index:
|
||||
continue
|
||||
category_lists = category.split('/')
|
||||
category_lists += ['', '']
|
||||
row_data = [
|
||||
'顶部导航菜单',
|
||||
category_lists[0],
|
||||
category_lists[1],
|
||||
category_lists[2],
|
||||
'collection',
|
||||
category
|
||||
]
|
||||
WorkBook.add_row_of_list(row_data)
|
||||
index[category] = None
|
||||
WorkBook.save()
|
||||
|
||||
return self
|
||||
|
||||
# 专辑
|
||||
def generate_album(self, goods_url_path):
|
||||
def open_workbook(bitch_index) -> excels.WorkBook:
|
||||
WorkBook = excels.WorkBook(
|
||||
template=self.__album_template_path__,
|
||||
save_path=f"{self.save_folder}/专辑表格({bitch_index}).xlsx"
|
||||
)
|
||||
return WorkBook
|
||||
|
||||
album_data = {}
|
||||
count = 0
|
||||
bitch_index = 1
|
||||
WorkBook = open_workbook(bitch_index)
|
||||
|
||||
goods_urls = files.load_lines(goods_url_path)
|
||||
for goods_url in goods_urls:
|
||||
if goods_url == '':
|
||||
continue
|
||||
goods_url_split = goods_url.split('#')
|
||||
goods_categorys = goods_url_split[-1].split('/')
|
||||
goods_url = '#'.join(goods_url_split[:-1])
|
||||
goods_url = goods_url.split('?')[0]
|
||||
|
||||
for category_index, goods_category in enumerate(goods_categorys):
|
||||
goods_category = '/'.join(goods_categorys[:category_index + 1])
|
||||
|
||||
if goods_category in album_data:
|
||||
mode = ''
|
||||
sort = ''
|
||||
else:
|
||||
mode = 'add'
|
||||
sort = 'collections_position'
|
||||
album_data[goods_category] = []
|
||||
|
||||
row_data = [
|
||||
'',
|
||||
goods_category,
|
||||
mode,
|
||||
sort,
|
||||
'',
|
||||
formats.url_to_spu(goods_url)
|
||||
]
|
||||
album_data[goods_category].append(row_data)
|
||||
count += 1
|
||||
|
||||
save_bitch = count/3+1
|
||||
for goods_category, row_datas in album_data.items():
|
||||
for row_data in row_datas:
|
||||
WorkBook.add_row_of_list(row_data)
|
||||
|
||||
if WorkBook.start_row > save_bitch and bitch_index <= 2:
|
||||
WorkBook.save()
|
||||
WorkBook.close()
|
||||
|
||||
bitch_index += 1
|
||||
WorkBook = open_workbook(bitch_index)
|
||||
WorkBook.save()
|
||||
WorkBook.close()
|
||||
|
||||
return self
|
||||
|
||||
class ShopyyVerify:
|
||||
def __init__(self, url):
|
||||
self.url = url
|
||||
browser = browsers.getBrowsers()
|
||||
self.tab = browser.get_tab(0)
|
||||
self.login()
|
||||
|
||||
def login(self):
|
||||
self.tab.get(f"{self.url}/admin/login")
|
||||
print('等待登录')
|
||||
while True:
|
||||
token = self.tab.local_storage('CARDADMIN_TOKEN')
|
||||
if token:
|
||||
print('登录成功')
|
||||
self.token = token.replace('"', '')
|
||||
break
|
||||
self.tab.wait(1)
|
||||
|
||||
def get_zero_collections(self, delete: bool = False):
|
||||
def get_collections(page):
|
||||
headers = {
|
||||
'accept': 'application/json, text/plain, */*',
|
||||
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
|
||||
'priority': 'u=1, i',
|
||||
# 'referer': 'https://cisalfasport.zenshop.cn/admin/collections?page=1&pagesize=50',
|
||||
'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Microsoft Edge";v="144"',
|
||||
'sec-ch-ua-mobile': '?0',
|
||||
'sec-ch-ua-platform': '"Windows"',
|
||||
'sec-fetch-dest': 'empty',
|
||||
'sec-fetch-mode': 'cors',
|
||||
'sec-fetch-site': 'same-origin',
|
||||
'token': self.token,
|
||||
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36 Edg/144.0.0.0',
|
||||
# 'cookie': '__stripe_mid=89b6ec3f-bbac-483d-b8ab-9938859a0b340b72d8; _aiihbe_vid=18FC7E3E-1CA7-FDC2-C52D-37A4BB0E1DF0; _aiihbe_cvid=75CFD325-E408-2C25-C126-07A349ED46C5; utm_source=direct; utm_medium=default; order_utm_history=%5B%7B%22utm_source%22%3A%22direct%22%2C%22utm_medium%22%3A%22default%22%2C%22utm_term%22%3A%22%22%2C%22utm_campaign%22%3A%22%22%2C%22utm_content%22%3A%22%22%2C%22source_device%22%3A%22computer%22%2C%22create_time%22%3A1770185710%2C%22expire_time%22%3A1772777710%7D%5D; landing_page=aHR0cHM6Ly9jaXNhbGZhc3BvcnQuemVuc2hvcC5jbi9wcm9kdWN0cy90b3VyLWRlLWZyYW5jZS1qcj9wcmV2aWV3PTE%3D; first_http_referer=https%3A%2F%2Fcisalfasport.zenshop.cn%2Fadmin%2Fproducts; first_visit_time=1770185710; PHPSESSID=6329e9a44018771ce40064bc50fbe189; _aiihbe_vs=36B35E5C-874E-4D6C-8945-F5CF6F323F99; theme_id=411278; _AIIHBE_ua=Mozilla%252F5.0%2520(Windows%2520NT%252010.0%253B%2520Win64%253B%2520x64)%2520AppleWebKit%252F537.36%2520(KHTML%252C%2520like%2520Gecko)%2520Chrome%252F144.0.0.0%2520Safari%252F537.36%2520Edg%252F144.0.0.0; _AIIHBE_pu=https%253A%252F%252Fcisalfasport.zenshop.cn%252Fadmin%252Ftheme; _AIIHBE_tz=Etc%2FGMT-8; _AIIHBE_ss=1920X1080; _AIIHBE_lang=zh-CN; _AIIHBE_vs=1874X930; _AIIHBE_dt=2026-02-06%2016%3A30%3A44; acw_tc=a3b54ee217704477374193466e23fb58e387e54f5b84504527a4beab6b; cdn_sec_tc=a3b54ee217704477374193466e23fb58e387e54f5b84504527a4beab6b; __stripe_sid=49bcd8c1-4ae4-46ba-8e95-a29205606cb2980c18; visit_token=4be69765c90de228978e9738878367fbkj083fsy; _aiihbe_ka=A298A3E1-379E-4DA0-2B28-A5961B741FA9; is_theme_edit=1',
|
||||
}
|
||||
|
||||
params = {
|
||||
'page': str(page),
|
||||
'pagesize': '600',
|
||||
}
|
||||
|
||||
response = requests.get(f'{self.url}/api/collections', params=params, headers=headers)
|
||||
response_data = response.json()
|
||||
if response_data['code'] != 0:
|
||||
raise Exception(response_data['msg'])
|
||||
return response_data['data']
|
||||
|
||||
def delete_collections(ids: list):
|
||||
headers = {
|
||||
'accept': 'application/json, text/plain, */*',
|
||||
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
|
||||
'cache-control': 'no-cache',
|
||||
'content-type': 'application/json',
|
||||
'origin': 'https://peekcloppenburgat.zenshop.cn',
|
||||
'pragma': 'no-cache',
|
||||
'priority': 'u=1, i',
|
||||
# 'referer': 'https://peekcloppenburgat.zenshop.cn/admin/collections?page=1&pagesize=600',
|
||||
'sec-ch-ua': '"Not:A-Brand";v="99", "Microsoft Edge";v="145", "Chromium";v="145"',
|
||||
'sec-ch-ua-mobile': '?0',
|
||||
'sec-ch-ua-platform': '"Windows"',
|
||||
'sec-fetch-dest': 'empty',
|
||||
'sec-fetch-mode': 'cors',
|
||||
'sec-fetch-site': 'same-origin',
|
||||
'token': self.token,
|
||||
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36 Edg/145.0.0.0',
|
||||
# 'cookie': '__stripe_mid=49d8f368-8d82-4b14-9c42-63e0d33542ef6372ca; _bzcece_vid=E823CDA9-7EDE-3617-71BB-80F879AD878E; _bzcece_cvid=36F627EC-095F-9323-5047-43325149C808; utm_source=direct; utm_medium=default; order_utm_history=%5B%7B%22utm_source%22%3A%22direct%22%2C%22utm_medium%22%3A%22default%22%2C%22utm_term%22%3A%22%22%2C%22utm_campaign%22%3A%22%22%2C%22utm_content%22%3A%22%22%2C%22source_device%22%3A%22computer%22%2C%22create_time%22%3A1773370701%2C%22expire_time%22%3A1775962701%7D%5D; landing_page=aHR0cHM6Ly9wZWVrY2xvcHBlbmJ1cmdhdC56ZW5zaG9wLmNuL3Byb2R1Y3RzL3Zlcm8tbW9kYS13aWRlLWxlZy1qZWFucy1hdXMtYmF1bXdvbGwtbWl4LW1vZGVsbC10ZXNzYS1pbi1oZWxsZ3JhdT9wcmV2aWV3PTE%3D; first_http_referer=https%3A%2F%2Fpeekcloppenburgat.zenshop.cn%2Fadmin%2Fproducts; first_visit_time=1773370701; PHPSESSID=fba65fe62a66071f174801bb432b942c; theme_id=418468; __stripe_sid=323c1341-4108-4c33-b331-ea6b782f9a2349679f; visit_token=f1d5170d234867f2ca490821f454239bmwnlrqr7; _bzcece_vs=5F572333-803E-D038-11EC-6CFCBA6F32D3; _bzcece_ka=B2503B21-4B44-A5A0-F261-71EC86D52A6E; is_theme_edit=1; acw_tc=9b66b49a17734819180038754ede11478ee763b95bb1c9acff317f521f; cdn_sec_tc=9b66b49a17734819180038754ede11478ee763b95bb1c9acff317f521f',
|
||||
}
|
||||
|
||||
json_data = {
|
||||
'ids': ids,
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
f'{self.url}/api/collections/batchdelete',
|
||||
headers=headers,
|
||||
json=json_data,
|
||||
)
|
||||
print(response.json())
|
||||
|
||||
print('开始检查专辑数量')
|
||||
collection_items = []
|
||||
data = get_collections(1)
|
||||
page_total = data['paginate']['pageTotal']
|
||||
collection_items += data['collections']
|
||||
print(f"1/{page_total}")
|
||||
|
||||
if page_total > 1:
|
||||
for page in range(2, page_total+1):
|
||||
data = get_collections(page)
|
||||
collection_items += data['collections']
|
||||
print(f"{page}/{page_total}")
|
||||
|
||||
lost_collection = []
|
||||
zero_ids = []
|
||||
for collection_item in collection_items:
|
||||
if collection_item['collection_products_count'] == 0:
|
||||
lost_collection.append(collection_item['title'])
|
||||
print(f"{collection_item['title']} 数量为0")
|
||||
zero_ids.append(collection_item['id'])
|
||||
if delete:
|
||||
delete_collections(zero_ids)
|
||||
|
||||
if len(lost_collection) > 0:
|
||||
with open('商品数量为0专辑.txt', 'w', encoding='utf-8') as f:
|
||||
f.write('\n'.join(lost_collection))
|
||||
return self
|
||||
|
||||
def get_error_images(self, delete: bool = False):
|
||||
def get_errors(page):
|
||||
headers = {
|
||||
'accept': 'application/json, text/plain, */*',
|
||||
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
|
||||
'cache-control': 'no-cache',
|
||||
'dnt': '1',
|
||||
'pragma': 'no-cache',
|
||||
'priority': 'u=1, i',
|
||||
# 'referer': 'https://vanuffelenmode.zenshop.cn/admin/resources',
|
||||
'sec-ch-ua': '"Not:A-Brand";v="99", "Microsoft Edge";v="145", "Chromium";v="145"',
|
||||
'sec-ch-ua-mobile': '?0',
|
||||
'sec-ch-ua-platform': '"Windows"',
|
||||
'sec-fetch-dest': 'empty',
|
||||
'sec-fetch-mode': 'cors',
|
||||
'sec-fetch-site': 'same-origin',
|
||||
'token': self.token,
|
||||
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36 Edg/145.0.0.0',
|
||||
# 'cookie': 'acw_tc=a3b54dab17734824723112557e921e5eb8672de1b4bf2e0bfb7de57fe1; cdn_sec_tc=a3b54dab17734824723112557e921e5eb8672de1b4bf2e0bfb7de57fe1; __stripe_mid=cc09d025-360b-466e-bef4-ba92d045fdc94448e2; __stripe_sid=511d0972-d39d-4aa1-a031-5258db651ad1d4124e; visit_token=9b8172c220d5be292045835470d38951px0lh404',
|
||||
}
|
||||
|
||||
params = {
|
||||
'file_name': '',
|
||||
'page_type': 'fail',
|
||||
'page': str(page),
|
||||
'pagesize': '600',
|
||||
}
|
||||
|
||||
response = requests.get(f'{self.url}/api/resources', params=params, headers=headers)
|
||||
response_data = response.json()
|
||||
if response_data['code'] != 0:
|
||||
raise Exception(response_data['msg'])
|
||||
return response_data['data']
|
||||
|
||||
def post_retry(ids: list):
|
||||
headers = {
|
||||
'accept': 'application/json, text/plain, */*',
|
||||
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
|
||||
'content-type': 'application/json',
|
||||
# 'origin': 'https://ssfshop.zenshop.cn',
|
||||
'priority': 'u=1, i',
|
||||
# 'referer': 'https://ssfshop.zenshop.cn/admin/resources',
|
||||
'sec-ch-ua': '"Chromium";v="146", "Not-A.Brand";v="24", "Microsoft Edge";v="146"',
|
||||
'sec-ch-ua-mobile': '?0',
|
||||
'sec-ch-ua-platform': '"Windows"',
|
||||
'sec-fetch-dest': 'empty',
|
||||
'sec-fetch-mode': 'cors',
|
||||
'sec-fetch-site': 'same-origin',
|
||||
'token': self.token,
|
||||
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36 Edg/146.0.0.0',
|
||||
# 'cookie': '__stripe_mid=a8059a05-4d7e-476d-b376-9e54f222efbe3c23c7; _bzgigi_vid=85F94DA2-7BD9-525E-E4A5-8D686E51B2C6; _bzgigi_cvid=EEFE28A2-FDC4-DC54-E76A-2BC1B2929243; utm_source=direct; utm_medium=default; order_utm_history=%5B%7B%22utm_source%22%3A%22direct%22%2C%22utm_medium%22%3A%22default%22%2C%22utm_term%22%3A%22%22%2C%22utm_campaign%22%3A%22%22%2C%22utm_content%22%3A%22%22%2C%22source_device%22%3A%22computer%22%2C%22create_time%22%3A1775195861%2C%22expire_time%22%3A1777787861%7D%5D; landing_page=aHR0cHM6Ly9zc2ZzaG9wLnplbnNob3AuY24vcHJvZHVjdHMvJUU4JTg3JUFBJUU3JTk0JUIxJUU1JThDJUJBLWwtMTklRTUlOEYlQjclRTMlODIlQjUlRTMlODIlQTQlRTMlODIlQkElRTMlODElQkUlRTMlODElQTclRTUlQjElOTUlRTklOTYlOEItJUUzJTgyJUFCJUUzJTgyJUJGJUUzJTgzJUFEJUUzJTgyJUIwJUU2JThFJUIyJUU4JUJDJTg5LSVFMyU4MiVCQiVFMyU4MyU4MyVFMyU4MyU4OCVFMyU4MiVBMiVFMyU4MyU4MyVFMyU4MyU5NyVFNSVBRiVCRSVFNSVCRiU5Qy0lRTMlODIlQkIlRTMlODMlQUMlRTMlODMlQTIlRTMlODMlOEIlRTMlODMlQkMtJUU5JTgwJTlBJUU1JThCJUE0LSVFMyU4MyU4OCVFMyU4MyVBQSVFMyU4MiVBMiVFMyU4MiVCQiVFMyU4MyU4MCVFMyU4MyU5NiVFMyU4MyVBQiVFMyU4MiVBRiVFMyU4MyVBRCVFMyU4MiVCOSVFMyU4MyU4NiVFMyU4MyVCQyVFMyU4MyVBOSVFMyU4MyVCQyVFMyU4MyU4OS0lRTMlODIlQjglRTMlODMlQTMlRTMlODIlQjElRTMlODMlODMlRTMlODMlODhfOGNhZjQ4Y2U%2FcHJldmlldz0x; first_http_referer=https%3A%2F%2Fssfshop.zenshop.cn%2Fadmin%2Fproducts; first_visit_time=1775195861; visit_token=41be25876fa245bb99018d68f7338d89y49l7utp; _bzgigi_vs=E5BE5924-EEF9-E277-6AFC-5F70BB548D0F; PHPSESSID=b08ff5f29b9469e1e92740efef87c09e; _BZGIGI_ua=Mozilla%252F5.0%2520(Windows%2520NT%252010.0%253B%2520Win64%253B%2520x64)%2520AppleWebKit%252F537.36%2520(KHTML%252C%2520like%2520Gecko)%2520Chrome%252F146.0.0.0%2520Safari%252F537.36%2520Edg%252F146.0.0.0; _BZGIGI_pu=https%253A%252F%252Fssfshop.zenshop.cn%252Fadmin%252Fproducts; _BZGIGI_tz=Etc%2FGMT-8; _BZGIGI_ss=2560X1440; _BZGIGI_lang=zh-CN; _BZGIGI_vs=2514X1316; _BZGIGI_dt=2026-04-07%2014%3A48%3A20; theme_id=429104; is_theme_edit=1; acw_tc=9b66b4a617756120379694001e5c7efed3faa08e9cf1c621bbfeb27c77; cdn_sec_tc=9b66b4a617756120379694001e5c7efed3faa08e9cf1c621bbfeb27c77; __stripe_sid=a0f6f277-4a95-4d43-bd6f-c38f108e17f52fc752',
|
||||
}
|
||||
response = requests.post(f'{self.url}/api/resources/retry', headers=headers, json={'ids':ids})
|
||||
print(response.json())
|
||||
|
||||
def delete_images(ids: list):
|
||||
headers = {
|
||||
'accept': 'application/json, text/plain, */*',
|
||||
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
|
||||
'content-type': 'application/json',
|
||||
# 'origin': 'https://ssfshop.zenshop.cn',
|
||||
'priority': 'u=1, i',
|
||||
# 'referer': 'https://ssfshop.zenshop.cn/admin/resources',
|
||||
'sec-ch-ua': '"Chromium";v="146", "Not-A.Brand";v="24", "Microsoft Edge";v="146"',
|
||||
'sec-ch-ua-mobile': '?0',
|
||||
'sec-ch-ua-platform': '"Windows"',
|
||||
'sec-fetch-dest': 'empty',
|
||||
'sec-fetch-mode': 'cors',
|
||||
'sec-fetch-site': 'same-origin',
|
||||
'token': self.token,
|
||||
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36 Edg/146.0.0.0',
|
||||
# 'cookie': '__stripe_mid=a8059a05-4d7e-476d-b376-9e54f222efbe3c23c7; _bzgigi_vid=85F94DA2-7BD9-525E-E4A5-8D686E51B2C6; _bzgigi_cvid=EEFE28A2-FDC4-DC54-E76A-2BC1B2929243; utm_source=direct; utm_medium=default; order_utm_history=%5B%7B%22utm_source%22%3A%22direct%22%2C%22utm_medium%22%3A%22default%22%2C%22utm_term%22%3A%22%22%2C%22utm_campaign%22%3A%22%22%2C%22utm_content%22%3A%22%22%2C%22source_device%22%3A%22computer%22%2C%22create_time%22%3A1775195861%2C%22expire_time%22%3A1777787861%7D%5D; landing_page=aHR0cHM6Ly9zc2ZzaG9wLnplbnNob3AuY24vcHJvZHVjdHMvJUU4JTg3JUFBJUU3JTk0JUIxJUU1JThDJUJBLWwtMTklRTUlOEYlQjclRTMlODIlQjUlRTMlODIlQTQlRTMlODIlQkElRTMlODElQkUlRTMlODElQTclRTUlQjElOTUlRTklOTYlOEItJUUzJTgyJUFCJUUzJTgyJUJGJUUzJTgzJUFEJUUzJTgyJUIwJUU2JThFJUIyJUU4JUJDJTg5LSVFMyU4MiVCQiVFMyU4MyU4MyVFMyU4MyU4OCVFMyU4MiVBMiVFMyU4MyU4MyVFMyU4MyU5NyVFNSVBRiVCRSVFNSVCRiU5Qy0lRTMlODIlQkIlRTMlODMlQUMlRTMlODMlQTIlRTMlODMlOEIlRTMlODMlQkMtJUU5JTgwJTlBJUU1JThCJUE0LSVFMyU4MyU4OCVFMyU4MyVBQSVFMyU4MiVBMiVFMyU4MiVCQiVFMyU4MyU4MCVFMyU4MyU5NiVFMyU4MyVBQiVFMyU4MiVBRiVFMyU4MyVBRCVFMyU4MiVCOSVFMyU4MyU4NiVFMyU4MyVCQyVFMyU4MyVBOSVFMyU4MyVCQyVFMyU4MyU4OS0lRTMlODIlQjglRTMlODMlQTMlRTMlODIlQjElRTMlODMlODMlRTMlODMlODhfOGNhZjQ4Y2U%2FcHJldmlldz0x; first_http_referer=https%3A%2F%2Fssfshop.zenshop.cn%2Fadmin%2Fproducts; first_visit_time=1775195861; visit_token=41be25876fa245bb99018d68f7338d89y49l7utp; _bzgigi_vs=E5BE5924-EEF9-E277-6AFC-5F70BB548D0F; PHPSESSID=b08ff5f29b9469e1e92740efef87c09e; _BZGIGI_ua=Mozilla%252F5.0%2520(Windows%2520NT%252010.0%253B%2520Win64%253B%2520x64)%2520AppleWebKit%252F537.36%2520(KHTML%252C%2520like%2520Gecko)%2520Chrome%252F146.0.0.0%2520Safari%252F537.36%2520Edg%252F146.0.0.0; _BZGIGI_pu=https%253A%252F%252Fssfshop.zenshop.cn%252Fadmin%252Fproducts; _BZGIGI_tz=Etc%2FGMT-8; _BZGIGI_ss=2560X1440; _BZGIGI_lang=zh-CN; _BZGIGI_vs=2514X1316; _BZGIGI_dt=2026-04-07%2014%3A48%3A20; theme_id=429104; is_theme_edit=1; acw_tc=9b66b4a617756120379694001e5c7efed3faa08e9cf1c621bbfeb27c77; cdn_sec_tc=9b66b4a617756120379694001e5c7efed3faa08e9cf1c621bbfeb27c77; __stripe_sid=60ef73cf-e5ed-483a-a342-9e581a0387d64df267',
|
||||
}
|
||||
json_data = {
|
||||
'ids': ids,
|
||||
'delete_product': 0
|
||||
}
|
||||
response = requests.delete('https://ssfshop.zenshop.cn/api/resources/batchdelete', headers=headers, json=json_data)
|
||||
print(response.json())
|
||||
|
||||
print('开始检查失败图片')
|
||||
image_items = []
|
||||
data = get_errors(1)
|
||||
page_total = data['paginate']['pageTotal']
|
||||
image_items += data['list']
|
||||
print(f"1/{page_total}")
|
||||
|
||||
if page_total > 1:
|
||||
for page in range(2, page_total+1):
|
||||
ids = []
|
||||
data = get_errors(1)
|
||||
for item in data['list']:
|
||||
ids.append(item['id'])
|
||||
if delete:
|
||||
delete_images(ids)
|
||||
else:
|
||||
post_retry(ids)
|
||||
page_total = data['paginate']['pageTotal']
|
||||
print(f"{page}/{page_total}")
|
||||
|
||||
# lost_image_urls = []
|
||||
# for image_item in image_items:
|
||||
# lost_image_urls.append(image_item['remote_url'])
|
||||
|
||||
# if len(lost_image_urls) > 0:
|
||||
# files.save_list('采集失败图片链接.txt', lost_image_urls)
|
||||
# print(f"共有: {len(lost_image_urls)} 条失败链接")
|
||||
|
||||
def get_all_images(self):
|
||||
def get_images(page):
|
||||
headers = {
|
||||
'accept': 'application/json, text/plain, */*',
|
||||
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
|
||||
'cache-control': 'no-cache',
|
||||
'dnt': '1',
|
||||
'pragma': 'no-cache',
|
||||
'priority': 'u=1, i',
|
||||
# 'referer': 'https://vanuffelenmode.zenshop.cn/admin/resources',
|
||||
'sec-ch-ua': '"Not:A-Brand";v="99", "Microsoft Edge";v="145", "Chromium";v="145"',
|
||||
'sec-ch-ua-mobile': '?0',
|
||||
'sec-ch-ua-platform': '"Windows"',
|
||||
'sec-fetch-dest': 'empty',
|
||||
'sec-fetch-mode': 'cors',
|
||||
'sec-fetch-site': 'same-origin',
|
||||
'token': self.token,
|
||||
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36 Edg/145.0.0.0',
|
||||
# 'cookie': 'acw_tc=a3b54dab17734824723112557e921e5eb8672de1b4bf2e0bfb7de57fe1; cdn_sec_tc=a3b54dab17734824723112557e921e5eb8672de1b4bf2e0bfb7de57fe1; __stripe_mid=cc09d025-360b-466e-bef4-ba92d045fdc94448e2; __stripe_sid=511d0972-d39d-4aa1-a031-5258db651ad1d4124e; visit_token=9b8172c220d5be292045835470d38951px0lh404',
|
||||
}
|
||||
|
||||
params = {
|
||||
'file_name': '',
|
||||
'page_type': 'all',
|
||||
'page': str(page),
|
||||
'pagesize': '600',
|
||||
}
|
||||
|
||||
response = requests.get(f'{self.url}/api/resources', params=params, headers=headers)
|
||||
response_data = response.json()
|
||||
if response_data['code'] != 0:
|
||||
raise Exception(response_data['msg'])
|
||||
return response_data['data']
|
||||
|
||||
print('开始获取图片url')
|
||||
image_items = []
|
||||
data = get_images(1)
|
||||
page_total = data['paginate']['pageTotal']
|
||||
image_items += data['list']
|
||||
print(f"1/{page_total}")
|
||||
|
||||
if page_total > 1:
|
||||
for page in range(2, page_total+1):
|
||||
data = get_images(page)
|
||||
image_items += data['list']
|
||||
print(f"{page}/{page_total}")
|
||||
|
||||
image_urls = []
|
||||
for image_item in image_items:
|
||||
image_urls.append(image_item['remote_url'])
|
||||
|
||||
if len(image_urls) > 0:
|
||||
files.save_list('图片链接.txt', image_urls)
|
||||
print(f"共有: {len(image_urls)} 张图片")
|
||||
Reference in New Issue
Block a user