xpjb-01.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. # BUFF选品01脚本
  2. import re
  3. from traceback import print_tb
  4. import requests as req
  5. import time,random,numpy as np
  6. from datetime import datetime
  7. from exceptiongroup import catch
  8. import argparse
  9. import mysql.connector
  10. from numpy.ma.core import argsort
  11. from selenium.webdriver.common.devtools.v85.system_info import ProcessInfo
  12. import json
  13. class xpjb():
  14. def __init__(self):
  15. # 数据库配置
  16. self.host = "121.40.50.77"
  17. self.user = "root"
  18. self.password = "Root@123456"
  19. self.database = "ry-vue"
  20. # 程序执行次数
  21. self.total_run_count = 0
  22. # 入参
  23. self.args = None
  24. # 选品账号的email
  25. self.xpzh_email = None
  26. # 选品账号的email_dh
  27. self.xpzh_email_dh = None
  28. # 选品账号的cookie
  29. self.xpzh_cookie = None
  30. # 选品有效品类信息
  31. self.xp_category_list=[]
  32. # 选品品质信息
  33. self.xp_rarity_list=[]
  34. # 选品类别信息
  35. self.xp_quality_list=[]
  36. # 选品外观信息
  37. self.xp_exterior_list=[]
  38. # 选品收藏品信息
  39. self.xp_itemset_list=[]
  40. # 已检索的BUFF商品数
  41. self.searchedGoodsNum =0;
  42. #BUFF搜寻商品入参
  43. self.search_good_param_init = {
  44. 'game': 'csgo'
  45. }
  46. #BUFF搜寻商品入参数list,因为有些内容存在多个选择,检索条件采取组合模式,分批次请求,请求中加入暂停,以防锁号
  47. self.search_good_param_list=[]
  48. # buff选品接口配置
  49. self.goodsurl = 'https://buff.163.com/api/market/goods'
  50. self.my_headers = {
  51. "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36",
  52. "Host": "buff.163.com",
  53. "Referer": "https://buff.163.com/market/?game=csgo",
  54. "X-Requested-With": "XMLHttpRequest"
  55. }
  56. # 判断嵌套属性是否存在
  57. @staticmethod
  58. def has_nested_attribute(obj, attr_path):
  59. attrs = attr_path.split('.')
  60. try:
  61. for attr in attrs:
  62. obj = obj[attr] if isinstance(obj, dict) else getattr(obj, attr)
  63. return True
  64. except (KeyError, AttributeError):
  65. return False
  66. # 处理命令行参数
  67. def dealArgc(self):
  68. try:
  69. print('处理命令行参数--开始')
  70. # 创建解析器
  71. parser = argparse.ArgumentParser(description='BUFF选品脚本')
  72. # 添加一个位置参数,表示运行多久重新再运行 默认10秒
  73. parser.add_argument('--runtime', type=str,default=10, help='单次运行时间 默认10秒')
  74. # 添加一个位置参数,表示自动运行多少次程序,默认为10次
  75. parser.add_argument('--runcount', type=int,default=10, help='程序运行总次数,默认为10次')
  76. # 添加一个位置参数,表示每次调用BUFF接口程序运行间隔多少秒,默认为10秒
  77. parser.add_argument('--timeinterval', type=int,default=5, help='每次调用BUFF接口程序运行间隔多少秒,默认为10秒')
  78. # 添加一个位置参数,表示选品账号的手机号码
  79. parser.add_argument('--xp_phone', type=str ,default=17756576757, help='选品账号的手机号码,17756576757')
  80. # 添加一个位置参数,表示选品脚本停止条件标志,1 按照成功数量,2 按照页数和每页数量 默认为1
  81. parser.add_argument('--xptz_status', type=int ,default=1, help='选品脚本停止条件标志,1 按照成功数量,2 按照页数和每页数量 默认为1')
  82. # 添加一个位置参数,表示选品脚本停止条件标志的成功数量, 默认 200
  83. parser.add_argument('--xptz_success_num', type=int ,default=200, help='选品脚本停止条件标志的成功数量, 默认 200')
  84. # 添加一个位置参数,表示选品脚本停止条件标志的页数 默认 100
  85. parser.add_argument('--xptz_page_num', type=int ,default=100, help='选品脚本停止条件标志的页数 默认 100')
  86. # 添加一个位置参数,表示选品脚本停止条件标志的每页数量 默认 80
  87. parser.add_argument('--xptz_page_size', type=int ,default=80, help='选品脚本停止条件标志的每页数量 默认 80')
  88. # 添加一个位置参数,表示选品最低价(元)
  89. parser.add_argument('--xp_min_price', help='选品最低价')
  90. # 添加一个位置参数,表示选品最高价(元)
  91. parser.add_argument('--xp_max_price', help='选品最高价')
  92. # 添加一个位置参数,表示选品排序模式 price.asc 价格升序 price.desc 价格降序 sell_num.desc 在售数量
  93. parser.add_argument('--xp_sort',type=str, help='选品排序模式')
  94. # 解析命令行参数
  95. self.args = parser.parse_args()
  96. # 使用参数
  97. print(f'单次运行时间,默认10秒: {self.args.runtime}')
  98. print(f'自动运行多少次程序 默认10次: {self.args.runcount}')
  99. print(f'每次调用BUFF接口程序运行间隔多少秒 默认5秒: {self.args.timeinterval}')
  100. print(f'选品账号的手机号码: {self.args.xp_phone}')
  101. print(f'选品脚本停止条件标志: {self.args.xptz_status}')
  102. print(f'选品脚本停止条件标志的成功数量 默认 200: {self.args.xptz_success_num}')
  103. print(f'选品脚本停止条件标志的页数 默认 100: {self.args.xptz_page_num}')
  104. print(f'选品脚本停止条件标志的每页数量 默认 80: {self.args.xptz_page_size}')
  105. print(f'选品最低价: {self.args.xp_min_price}')
  106. print(f'选品最高价: {self.args.xp_max_price}')
  107. print(f'选品排序模式: {self.args.xp_sort}')
  108. print('处理命令行参数--成功')
  109. except Exception as e:
  110. print('处理命令行参数--失败',e)
  111. exit()
  112. # 获取选品品类信息
  113. def getXpCategory(self):
  114. print('获取选品品类信息')
  115. try:
  116. # 创建mysql连接
  117. conn = mysql.connector.connect(
  118. host=self.host,
  119. user=self.user,
  120. password=self.password,
  121. database=self.database
  122. )
  123. # 创建游标对象
  124. cursor = conn.cursor()
  125. # 执行SQL查询
  126. cursor.execute(f"select category_code from sys_category where del_flag = '0' and status = '0' ")
  127. # 获取所有记录列表
  128. results = cursor.fetchall()
  129. if len(results) == 0:
  130. print('选品品类信息不存在,请检查数据库配置')
  131. self.xp_category_list=[]
  132. for row in results:
  133. self.xp_category_list.append(row[0])
  134. # 关闭游标和连接
  135. cursor.close()
  136. conn.close()
  137. except Exception as e:
  138. print('获取选品品类信息--失败',e)
  139. exit()
  140. # 获取选品品质信息
  141. def getXpRarity(self):
  142. print('获取选品品质信息')
  143. try:
  144. # 创建mysql连接
  145. conn = mysql.connector.connect(
  146. host=self.host,
  147. user=self.user,
  148. password=self.password,
  149. database=self.database
  150. )
  151. # 创建游标对象
  152. cursor = conn.cursor()
  153. # 执行SQL查询
  154. cursor.execute(f"select quality_code from sys_quality where del_flag = '0' and quality_status = '0' ")
  155. # 获取所有记录列表
  156. results = cursor.fetchall()
  157. if len(results) == 0:
  158. print('选品品质信息不存在,请检查数据库配置')
  159. self.xp_rarity_list=[]
  160. for row in results:
  161. self.xp_rarity_list.append(row[0])
  162. # 关闭游标和连接
  163. cursor.close()
  164. conn.close()
  165. except Exception as e:
  166. print('获取选品品质信息--失败',e)
  167. exit()
  168. # 获取选品类别信息
  169. def getXpQuality(self):
  170. print('获取选品类别信息')
  171. try:
  172. # 创建mysql连接
  173. conn = mysql.connector.connect(
  174. host=self.host,
  175. user=self.user,
  176. password=self.password,
  177. database=self.database
  178. )
  179. # 创建游标对象
  180. cursor = conn.cursor()
  181. # 执行SQL查询
  182. cursor.execute(f"select type_code from sys_type where del_flag = '0' and typestatus = '0' ")
  183. # 获取所有记录列表
  184. results = cursor.fetchall()
  185. if len(results) == 0:
  186. print('选品类别信息不存在,请检查数据库配置')
  187. self.xp_quality_list=[]
  188. for row in results:
  189. self.xp_quality_list.append(row[0])
  190. # 关闭游标和连接
  191. cursor.close()
  192. conn.close()
  193. except Exception as e:
  194. print('获取选品类别信息--失败',e)
  195. exit()
  196. # 获取选品外观信息
  197. def getXpExterior(self):
  198. print('获取选品外观信息')
  199. try:
  200. # 创建mysql连接
  201. conn = mysql.connector.connect(
  202. host=self.host,
  203. user=self.user,
  204. password=self.password,
  205. database=self.database
  206. )
  207. # 创建游标对象
  208. cursor = conn.cursor()
  209. # 执行SQL查询
  210. cursor.execute(f"select appear_code from sys_appear where del_flag = '0' and appear_sta = '0' ")
  211. # 获取所有记录列表
  212. results = cursor.fetchall()
  213. if len(results) == 0:
  214. print('选品外观信息不存在,请检查数据库配置')
  215. self.xp_exterior_list=[]
  216. for row in results:
  217. self.xp_exterior_list.append(row[0])
  218. # 关闭游标和连接
  219. cursor.close()
  220. conn.close()
  221. except Exception as e:
  222. print('获取选品外观信息--失败',e)
  223. exit()
  224. # 获取选品收藏品信息
  225. def getXpItemset(self):
  226. print('获取选品收藏品信息')
  227. try:
  228. # 创建mysql连接
  229. conn = mysql.connector.connect(
  230. host=self.host,
  231. user=self.user,
  232. password=self.password,
  233. database=self.database
  234. )
  235. # 创建游标对象
  236. cursor = conn.cursor()
  237. # 执行SQL查询
  238. cursor.execute(f"select colect_code from sys_collect where del_flag = '0' and colect_sta = '0' ")
  239. # 获取所有记录列表
  240. results = cursor.fetchall()
  241. if len(results) == 0:
  242. print('选品收藏品信息不存在,请检查数据库配置')
  243. self.xp_itemset_list=[]
  244. for row in results:
  245. self.xp_itemset_list.append(row[0])
  246. # 关闭游标和连接
  247. cursor.close()
  248. conn.close()
  249. except Exception as e:
  250. print('获取选品收藏品信息--失败',e)
  251. exit()
  252. # 获取选品账号信息
  253. def getXpzh(self):
  254. print('获取选品账号信息')
  255. try:
  256. # 创建mysql连接
  257. conn = mysql.connector.connect(
  258. host=self.host,
  259. user=self.user,
  260. password=self.password,
  261. database=self.database
  262. )
  263. # 创建游标对象
  264. cursor = conn.cursor()
  265. # 执行SQL查询
  266. cursor.execute(f"SELECT id,phone,email,email_dh,cookie FROM sc_xpzh where phone = '{self.args.xp_phone}' and is_del='0' ")
  267. # 获取所有记录列表
  268. results = cursor.fetchall()
  269. if len(results) == 0:
  270. print('选品账号信息不存在,请检查手机号码是否正确')
  271. exit()
  272. for row in results:
  273. self.xpzh_email = row[2]
  274. self.xpzh_email_dh = row[3]
  275. self.xpzh_cookie = row[4]
  276. # 关闭游标和连接
  277. cursor.close()
  278. conn.close()
  279. print(f"选品账号手机号码: {self.args.xp_phone}")
  280. print(f"选品账号email:{self.xpzh_email}")
  281. print(f"选品账号cookie:{self.xpzh_cookie}")
  282. print(f"选品账号email:{self.xpzh_email}")
  283. except Exception as e:
  284. print('获取选品账号信息--失败',e)
  285. exit()
  286. # 获取检索BUFF物品的API接口入参
  287. def getSearchGoodParam(self):
  288. print('获取检索BUFF物品API接口入参')
  289. # 过滤掉空的列表
  290. non_empty_lists = {
  291. 'category': self.xp_category_list,
  292. 'rarity': self.xp_rarity_list,
  293. 'quality': self.xp_quality_list,
  294. 'exterior': self.xp_exterior_list,
  295. 'itemset': self.xp_itemset_list
  296. }
  297. # 只保留非空的列表
  298. filtered_lists = {k: v for k, v in non_empty_lists.items() if v}
  299. # 如果所有列表都为空,返回空列表
  300. if not filtered_lists:
  301. return []
  302. # 生成所有可能的组合
  303. # 使用itertools.product来生成所有可能的组合
  304. from itertools import product
  305. # 获取所有非空列表的值
  306. values = list(filtered_lists.values())
  307. # 获取所有非空列表的键
  308. keys = list(filtered_lists.keys())
  309. for combination in product(*values):
  310. combination_dict = {keys[i]: combination[i] for i in range(len(keys))}
  311. self.search_good_param_list.append(combination_dict)
  312. for i in range(len(self.search_good_param_list)):
  313. self.search_good_param_list[i]['category_group'] = self.search_good_param_list[i]['category']
  314. # 生成检索BUFF物品的API接口最终入参
  315. def generate_combinations(self):
  316. #当self.search_good_param_list为空,加入一个空对象
  317. if len(self.search_good_param_list) == 0:
  318. self.search_good_param_list.append({})
  319. #遍历search_good_param_list数组,每个数组中增加search_good_param_init的值
  320. for i in range(len(self.search_good_param_list)):
  321. self.search_good_param_list[i].update(self.search_good_param_init)
  322. #xptz_status为2时候,将search_good_param_list数组中的每个数组的xptz_page_num和xptz_page_size
  323. if self.args.xptz_status == 2:
  324. for i in range(len(self.search_good_param_list)):
  325. self.search_good_param_list[i]['page_num'] = self.args.xptz_page_num
  326. self.search_good_param_list[i]['page_size'] = self.args.xptz_page_size
  327. elif self.args.xptz_status == 1:
  328. for i in range(len(self.search_good_param_list)):
  329. self.search_good_param_list[i]['page_num'] = self.args.xptz_page_num
  330. self.search_good_param_list[i]['page_size'] = self.args.xptz_page_size
  331. #选品最低价不为空,则将search_good_param_list数组中的每个数组的xptz_min_price的值设置为命令行参数--xptz_min_price的值
  332. if self.args.xp_min_price != None:
  333. for i in range(len(self.search_good_param_list)):
  334. self.search_good_param_list[i]['min_price'] = self.args.xp_min_price
  335. #选品最高价不为空,则将search_good_param_list数组中的每个数组的xptz_max_price的值设置为命令行参数--xptz_max_price的值
  336. if self.args.xp_max_price != None:
  337. for i in range(len(self.search_good_param_list)):
  338. self.search_good_param_list[i]['max_price'] = self.args.xp_max_price
  339. #选品排序值不为空,则将search_good_param_list数组中的每个数组的xptz_sort_type的值设置为命令行参数--xptz_sort_type的值
  340. if self.args.xp_sort != None:
  341. for i in range(len(self.search_good_param_list)):
  342. self.search_good_param_list[i]['sort_by'] = self.args.xp_sort
  343. # 选品
  344. def SearchGoods(self):
  345. print('选品开始')
  346. #simpleSearchGoods函数执行runcount次数,自动停止,两次之间暂停runtime秒
  347. for i in range(self.args.runcount):
  348. self.simpleSearchGoods(i)
  349. time.sleep(self.args.runtime)
  350. print('选品结束')
  351. # 单次选品
  352. def simpleSearchGoods(self,i):
  353. # 如果搜寻的BUFF商品已完成,则停止脚本
  354. if self.searchedGoodsNum >= self.args.xptz_success_num:
  355. print('搜寻的BUFF商品已完成,停止脚本')
  356. exit()
  357. # print(f'选品程序第{i}次执行开始')
  358. # print(self.search_good_param_list)
  359. # 遍历search_good_param_list
  360. for param in self.search_good_param_list:
  361. # print('选品入参:',param)
  362. # 获取BUFF商品信息
  363. gooditems = self.callMarketGoods(param)
  364. # print(gooditems)
  365. # 判断是否满足条件
  366. # 此处调整到单独的脚本xpjb-02.py处理
  367. # print(f'选品程序第{i}次执行结束')
  368. # 请求BUFF物品的API接口
  369. def callMarketGoods(self,param):
  370. # print('获取商品信息')
  371. #Cookie赋值
  372. self.my_headers.update({
  373. 'Cookie': self.xpzh_cookie
  374. })
  375. datalist = []
  376. try:
  377. res = req.get(url=self.goodsurl, headers=self.my_headers, params=param)
  378. # if res.json()['code'] != 'OK' :
  379. print('选品接口请求返回报文:', res.text.strip())
  380. # return
  381. data = res.json()['data']
  382. datalist.extend(data['items'])
  383. total_page_num= data['total_page']
  384. # datalist 入数据库
  385. self.insertGoods(datalist)
  386. time.sleep(self.args.timeinterval)
  387. if total_page_num >= param['page_num']:
  388. total_page_num = param['page_num']
  389. # print('商品页数'+str(total_page_num))
  390. if int(total_page_num) > 1:
  391. for i in range(1, total_page_num):
  392. time.sleep(self.args.timeinterval)
  393. param.update({
  394. 'page_num': i
  395. })
  396. try:
  397. datalist=[]
  398. res = req.get(url=self.goodsurl, headers=self.my_headers, params=param)
  399. # if res.json()['code'] != 'OK' :
  400. print('选品接口请求返回报文:', res.text.strip())
  401. # continue
  402. data = res.json()['data']
  403. datalist.extend(data['items'])
  404. # datalist 入数据库
  405. self.insertGoods(datalist)
  406. except Exception as e:
  407. print('选品接口请求--失败',e)
  408. except Exception as e:
  409. print('选品接口请求--失败',e)
  410. # print('数据获取成功') # 打印数据列表
  411. return
  412. def insertGoods(self,datalist):
  413. # print('buff商品数据入库')
  414. try:
  415. # 创建mysql连接
  416. conn = mysql.connector.connect(
  417. host=self.host,
  418. user=self.user,
  419. password=self.password,
  420. database=self.database
  421. )
  422. cursor = conn.cursor()
  423. #遍历datalist
  424. for item in datalist:
  425. self.searchedGoodsNum += 1 # 搜索商品数量加1 为了跟入参xptz_success_num要求比对
  426. print(f"buff商品 id:{item['id']} 已入库")
  427. query = "INSERT INTO sys_buff_goods (goods_info, deal_flag,create_time) VALUES (%s, %s,now())"
  428. data = (json.dumps(item), '0')
  429. cursor.execute(query, data)
  430. conn.commit()
  431. except Exception as e:
  432. print('datalist入库--失败',e)
  433. finally:
  434. if conn.is_connected():
  435. cursor.close()
  436. conn.close()
  437. if __name__ == '__main__':
  438. print('开启选品脚本')
  439. xp = xpjb()
  440. # 处理命令行参数
  441. xp.dealArgc()
  442. # 获取数据库中BUFF品类配置
  443. xp.getXpCategory()
  444. # 获取数据库中BUFF品质配置
  445. xp.getXpRarity()
  446. # 获取数据库中BUFF类别配置
  447. xp.getXpQuality()
  448. # 获取数据库中BUFF外观配置
  449. xp.getXpExterior()
  450. # 获取数据库中BUFF收藏品信息
  451. xp.getXpItemset()
  452. # 根据数据库中配置信息,组合商品选取API的入参列表
  453. xp.getSearchGoodParam()
  454. # 生成最终选品API的入参列表
  455. xp.generate_combinations()
  456. # 获取选品账号信息,根据脚本的入参xp_phone检索
  457. xp.getXpzh()
  458. # 选品
  459. xp.SearchGoods()