OfpayGrab.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  1. # -*- coding: utf-8 -*-
  2. import os
  3. import argparse
  4. import csv
  5. import requests
  6. import json
  7. from datetime import datetime
  8. # from http.cookies import SimpleCookie
  9. from cachetools import TTLCache
  10. import pickle
  11. import multiprocessing
  12. from multiprocessing import Manager
  13. from multiprocessing.dummy import Pool as ThreadPool
  14. from functools import partial
  15. import time
  16. def read_csv(filename='results.csv'):
  17. data = []
  18. try:
  19. with open(filename, mode='r', encoding='utf-8') as csvfile:
  20. reader = csv.DictReader(csvfile);
  21. for row in reader:
  22. data.append(row);
  23. except IOError as e:
  24. print(f"read_csv error occurred: {e}");
  25. # print(data);
  26. return data;
  27. def read_json(filename='results.json'):
  28. data = None;
  29. try:
  30. with open(filename, 'r', encoding='utf-8') as file:
  31. data = json.load(file);
  32. except IOError as e:
  33. print(f"read_json error occurred: {e}");
  34. # print(data);
  35. return data;
  36. g_shared_cache = None;
  37. class SharedCache:
  38. cache_file_path = 'elife.cache.pickle';
  39. def __init__(self):
  40. self.init();
  41. def init(self):
  42. cache = None;
  43. try:
  44. cache_file_path = SharedCache.cache_file_path;
  45. if os.path.exists(cache_file_path):
  46. # 从文件中加载缓存对象
  47. with open(cache_file_path, 'rb') as file:
  48. cache = pickle.load(file);
  49. else:
  50. cache = TTLCache(maxsize=100, ttl=60*60*24);
  51. # 将缓存对象持久化到文件
  52. with open(cache_file_path, 'wb') as file:
  53. pickle.dump(cache, file);
  54. except Exception as e:
  55. cache = {};
  56. print(e);
  57. finally:
  58. pass
  59. self.cache = cache;
  60. def save(self):
  61. try:
  62. cache_file_path = SharedCache.cache_file_path;
  63. with open(cache_file_path, 'wb') as file:
  64. pickle.dump(self.cache, file);
  65. except Exception as e:
  66. print(e);
  67. finally:
  68. pass;
  69. def set(self, key, value):
  70. self.cache[key] = value;
  71. def get(self, key):
  72. ret = None;
  73. try:
  74. ret = self.cache.get(key);
  75. except Exception as e:
  76. print(e);
  77. finally:
  78. return ret;
  79. class OfpayGrabber:
  80. FastModeEnable = True;
  81. CheckStockEnable = True;
  82. CheckBuyRepeatEnable = True;
  83. def __init__(self, accout_data, activities_data, cli_options):
  84. if cli_options.get('mode') == 'fast':
  85. OfpayGrabber.FastModeEnable = True;
  86. else:
  87. OfpayGrabber.FastModeEnable = False;
  88. if cli_options.get('check_stock') == '1':
  89. OfpayGrabber.CheckStockEnable = True;
  90. else:
  91. OfpayGrabber.CheckStockEnable = False;
  92. if cli_options.get('check_repeat') == '1':
  93. OfpayGrabber.CheckBuyRepeatEnable = True;
  94. else:
  95. OfpayGrabber.CheckBuyRepeatEnable = False;
  96. self.app_version = 602;
  97. self.award_want_discount_dict = None;
  98. self.activities_data = activities_data;
  99. self.enable = True if accout_data['enable'] == 1 else False;
  100. self.accout_data = accout_data;
  101. self.host = 'market-web.ofpay.com';
  102. self.market_id = accout_data['market_id'];
  103. self.event_visitor_id = accout_data['event_visitor_id'];
  104. self.accout_id = accout_data['account'];
  105. uuid = accout_data['uuid'];
  106. user_agent = accout_data['user_agent'];
  107. authorization = accout_data['authorization'];
  108. self.cookies = eval(accout_data['cookies']);
  109. cookies_str = '; '.join([f'{key}={value}' for key, value in self.cookies.items()]);
  110. self.headers = {
  111. 'Host': self.host,
  112. 'UUID': uuid,
  113. 'Accept': '*/*',
  114. 'Sec-Fetch-Site': 'same-origin',
  115. 'Origin': 'https://market-web.ofpay.com',
  116. 'Accept-Language': 'zh-CN,zh-Hans;q=0.9',
  117. 'Accept-Encoding': 'gzip, deflate, br',
  118. 'Sec-Fetch-Mode': 'cors',
  119. 'Content-Type': 'application/json; charset=utf-8',
  120. 'Connection': 'keep-alive',
  121. 'User-Agent': user_agent,
  122. 'Accept-Language': 'zh-CN,zh-Hans;q=0.9',
  123. 'Authorization': authorization,
  124. 'Sec-Fetch-Dest': 'empty',
  125. 'Referer': 'https://market-web.ofpay.com/h5/union/standard/interactiveIGoChoose/index',
  126. 'Cookie': cookies_str,
  127. };
  128. def start(self):
  129. ret_code = self.check_refresh_token();
  130. print(f"账号[{self.accout_id}]token数据状态:{ret_code}");
  131. if ret_code < 0:
  132. print(f"账号[{self.accout_id}]token已失效");
  133. return;
  134. if ret_code == 1:
  135. self.sync_new_token();
  136. cate_items_list = self.get_market_items_from_cache();
  137. if not cate_items_list:
  138. cate_items_list = self.get_market_items_from_svr(self.market_id, self.event_visitor_id);
  139. if not cate_items_list:
  140. return;
  141. cate_items_dict = {};
  142. for activity_data in cate_items_list:
  143. out_activity_code = activity_data['outActivityCode'];
  144. cate_items_dict[out_activity_code] = activity_data;
  145. all_buy_dict = self.get_will_market_buy_list_all();
  146. all_ret_list = [];
  147. for cate_type in all_buy_dict:
  148. buy_list = all_buy_dict[cate_type];
  149. if not buy_list:
  150. continue;
  151. activity_data = cate_items_dict[cate_type] if cate_type in cate_items_dict else None;
  152. if not activity_data:
  153. continue;
  154. buy_ret_list = self.check_to_buy_all(buy_list, activity_data);
  155. all_ret_list.extend(buy_ret_list);
  156. if len(all_ret_list):
  157. g_shared_cache.save();
  158. return all_ret_list;
  159. def check_refresh_token(self, force_refresh=False):
  160. expire_time_str = self.accout_data['expire_time'];
  161. expire_dt = datetime.strptime(expire_time_str, "%Y-%m-%d %H:%M:%S")
  162. now_dt = datetime.now();
  163. is_valid = False;
  164. if now_dt < expire_dt:
  165. is_valid = True;
  166. if not force_refresh and is_valid:
  167. return 0;
  168. login_params = self.accout_data['login_params'];
  169. url = f'https://{self.host}/h5/union/interactiveIGoChoose/index?loginParams={login_params}';
  170. response = self.get_request(url);
  171. # content = response.content;
  172. # print(content.decode("utf-8"));
  173. # cookie_dict = dict(response.cookies);
  174. cookie_dict = {}
  175. for cookie in response.cookies:
  176. if cookie.name:
  177. key = cookie.name;
  178. cookie_dict[key] = cookie.value;
  179. authorization = None;
  180. for key in cookie_dict:
  181. self.cookies[key] = cookie_dict[key];
  182. if key == 'unionToken_interactiveIGoChoose':
  183. authorization = self.cookies[key];
  184. if authorization:
  185. self.headers['Authorization'] = authorization;
  186. cookies_str = '; '.join([f'{key}={value}' for key, value in self.cookies.items()]);
  187. self.headers['Cookie'] = cookies_str;
  188. return 1;
  189. return -1;
  190. def sync_new_token(self):
  191. print('sync_new_token');
  192. def get_will_market_buy_list_all(self):
  193. def_val = 'eSupermarket#京东E卡|eTravel#滴滴快车|eCoffee#星巴克|eFood#百果园|eTea#霸王茶姬|eMovie#|eBicycle#|eOffice#';
  194. buy_ret_dict = {};
  195. buy_conf_str = self.accout_data['will_buy_list'] if self.accout_data['will_buy_list'] else def_val;
  196. if len(buy_conf_str):
  197. buy_ret_dict = {};
  198. items = buy_conf_str.strip().split('|');
  199. for vstr in items:
  200. if len(vstr):
  201. cate_item = vstr.strip().split('#');
  202. cate_type_key = cate_item[0];
  203. cate_item_val = cate_item[1] if len(cate_item) > 1 else None;
  204. if cate_item_val and len(cate_item_val):
  205. vlist = cate_item_val.strip().split('+');
  206. buy_ret_dict[cate_type_key] = vlist;
  207. else:
  208. buy_ret_dict = {};
  209. return buy_ret_dict;
  210. def get_award_expected_discount(self, price, prize_name):
  211. if not self.award_want_discount_dict:
  212. self.award_want_discount_dict = {};
  213. def_val = '星巴克#20.80|霸王茶姬#10.80|百果园#10.80|京东E卡#10.80|滴滴快车#10.80';
  214. discount_str = self.accout_data['will_discount'] if self.accout_data['will_discount'] else def_val;
  215. if len(discount_str):
  216. segments = discount_str.strip().split('|');
  217. for vstr in segments:
  218. if len(vstr):
  219. vlist = vstr.strip().split('#');
  220. key = vlist[0];
  221. if vlist[1]:
  222. price_val = float(vlist[1].strip());
  223. self.award_want_discount_dict[key] = price_val;
  224. if self.award_want_discount_dict.get(prize_name) != None:
  225. return self.award_want_discount_dict[prize_name];
  226. return price - 8.8;
  227. def get_market_items_from_cache(self):
  228. if not self.activities_data:
  229. self.activities_data = read_json('elife_activities_data.json');
  230. return self.activities_data;
  231. def save_market_items_cache(self, market_id, event_visitor_id, data):
  232. with open('elife_activities_data.json', 'w', newline='', encoding='utf-8') as f:
  233. json_str = json.dumps(data, cls=DecimalEncoder, ensure_ascii=False);
  234. f.write(json_str);
  235. def get_market_items_from_svr(self, market_id, event_visitor_id):
  236. params = {
  237. 'marketId': market_id,
  238. 'eventVisitorId': event_visitor_id
  239. };
  240. url = ('https://%s/h5/union/api/interactiveIGoChoose/indexConfigRebuild' % (self.host));
  241. print("请求市场商品列表数据");
  242. response = self.get_request(url, params);
  243. if response.status_code == 200:
  244. try:
  245. json_str = response.content;
  246. json_str = json_str.decode('utf-8');
  247. params = json.loads(json_str);
  248. if params.get('code') == 'success':
  249. print("请求市场商品列表数据成功");
  250. # self.save_market_items_cache(params['data']);
  251. return params['data'];
  252. else:
  253. print(f"请求市场商品列表数据成功,响应:{json_str}");
  254. except Exception as e:
  255. print("请求市场商品列表发生错误");
  256. print(e);
  257. finally:
  258. pass
  259. else:
  260. print("请求市场商品列表发生错误");
  261. return None;
  262. def check_to_buy_all(self, buy_list, activity_data):
  263. activity_id = activity_data['activityId'];
  264. sub_activity_id = activity_data['subActivityId'] if 'subActivityId' in activity_data else None;
  265. sub_login_type = activity_data['subLoginType'];
  266. award_list = activity_data['awardList'];
  267. ret_list = [];
  268. for i in range(len(buy_list)):
  269. try:
  270. one_ret = self.check_to_buy_one(activity_id, sub_activity_id, sub_login_type, buy_list[i], award_list);
  271. if one_ret:
  272. ret_list.append(one_ret);
  273. except Exception as e:
  274. print(e);
  275. else:
  276. pass
  277. finally:
  278. pass
  279. return ret_list;
  280. def check_to_buy_one(self, activity_id, sub_activity_id, sub_login_type, item_name, award_list):
  281. one_ret = None;
  282. check_buy_repeat_key = f"lkOfPayBuyItemKey#{item_name}#{self.accout_id}";
  283. now_string = datetime.now().strftime('%Y-%m-%d %H:%M:%S');
  284. if OfpayGrabber.CheckBuyRepeatEnable:
  285. last_buy_succ_date = g_shared_cache.get(check_buy_repeat_key);
  286. if now_string == last_buy_succ_date:
  287. print(f"商品[{item_name}]今日已抢购成功过,跳过~~");
  288. return one_ret;
  289. if OfpayGrabber.FastModeEnable:
  290. for award_data in award_list:
  291. if item_name in award_data['prizeName']:
  292. print(f"开始尝试抢购-{award_data['prizeName']}{award_data['prizeDesc']},价格:{award_data['price']},库存:{award_data['remainStock']}");
  293. if OfpayGrabber.CheckStockEnable:
  294. if award_data['remainStock'] > 0:
  295. one_ret = self.item_buy_fast(activity_id, sub_activity_id, sub_login_type, award_data);
  296. if one_ret:
  297. # 抢购成功
  298. g_shared_cache.set(check_buy_repeat_key, now_string);
  299. else:
  300. print("库存不足,跳过~");
  301. else:
  302. one_ret = self.item_buy_fast(activity_id, sub_activity_id, sub_login_type, award_data);
  303. if one_ret:
  304. # 抢购成功
  305. g_shared_cache.set(check_buy_repeat_key, now_string);
  306. break;
  307. else:
  308. for award_data in award_list:
  309. if item_name in award_data['prizeName']:
  310. print(f"开始尝试抢购-{award_data['prizeName']}{award_data['prizeDesc']},价格:{award_data['price']},库存:{award_data['remainStock']}");
  311. if award_data['remainStock'] > 0:
  312. one_ret = self.item_buy_normal(activity_id, sub_activity_id, sub_login_type, award_data);
  313. if one_ret:
  314. # 抢购成功
  315. g_shared_cache.set(check_buy_repeat_key, now_string);
  316. else:
  317. print("库存不足,跳过~");
  318. break;
  319. return one_ret;
  320. def item_buy_fast(self, activity_id, sub_activity_id, sub_login_type, award_data):
  321. print("###item_buy_fast");
  322. activity_id = award_data['activityId']
  323. # 假设 ofpay_account_phone 和 event_visitor_id 在这段代码之外被定义
  324. # 或者作为参数传递给这个函数
  325. event_visitor_id = self.event_visitor_id;
  326. game_account = self.accout_id;
  327. third_info = json.loads(award_data['thirdInfo']);
  328. award_id = award_data['awardId'];
  329. pay_info = self.get_pay_info(activity_id, award_id, '', '', game_account, event_visitor_id);
  330. if pay_info:
  331. if 'detailId' in pay_info:
  332. pay_ret = self.pay(activity_id, event_visitor_id, pay_info['detailId']);
  333. if pay_ret:
  334. return award_data;
  335. return None;
  336. def get_pay_info(self, activity_id, award_id, goods_id, invitation_code, game_account, event_visitor_id):
  337. url = f'https://{self.host}/h5/union/api/draw/interactiveIGoChoose/{activity_id}?awardId={award_id}&goodsId={goods_id}&invitationCode={invitation_code}&gameAccount={game_account}&eventVisitorId={event_visitor_id}';
  338. print("请求商品预支付数据");
  339. response = self.get_request(url);
  340. if response.status_code == 200:
  341. try:
  342. json_str = response.content;
  343. json_str = json_str.decode('utf-8');
  344. params = json.loads(json_str);
  345. if params.get('code') == '0':
  346. print("请求商品预支付数据成功");
  347. print(json_str);
  348. return params;
  349. else:
  350. # 19=存在待支付订单
  351. print(f"请求商品预支付数据失败,响应:{json_str}")
  352. except Exception as e:
  353. print("请求商品预支付数据发生错误");
  354. print(e);
  355. finally:
  356. pass
  357. else:
  358. print("请求商品预支付数据发生错误");
  359. return None;
  360. def pay(self, activity_id, event_visitor_id, detail_id):
  361. account_phone = self.accout_id;
  362. post_data = {
  363. "detailId": detail_id,
  364. "rechargeAccount": account_phone,
  365. "account": account_phone,
  366. "appVersion": self.app_version,
  367. };
  368. url = f"https://{self.host}/h5/api/mobile/activity/pay/{activity_id}?eventVisitorId={event_visitor_id}";
  369. body = json.dumps(post_data);
  370. response = self.post_request(url, body);
  371. if response.status_code == 200:
  372. try:
  373. json_str = response.content;
  374. json_str = json_str.decode('utf-8');
  375. params = json.loads(json_str);
  376. if params.get('code') == 'success':
  377. print("请求下单成功");
  378. print(json_str);
  379. return params;
  380. else:
  381. print(f"请求下单失败,响应:{json_str}");
  382. except Exception as e:
  383. print("请求下单发生错误");
  384. print(e);
  385. finally:
  386. pass
  387. else:
  388. print("请求下单发生错误");
  389. return None;
  390. def check_pick_item(self, prize_name, award_list):
  391. for award_data in award_list:
  392. one_prize_name = award_data['prizeName'];
  393. if '忽略' not in one_prize_name and prize_name in one_prize_name:
  394. return award_data;
  395. return None;
  396. def item_buy_normal(self, activity_id, sub_activity_id, sub_login_type, award_data):
  397. print("###item_buy_normal");
  398. activity_id = award_data["activityId"];
  399. prize_name = award_data["prizeName"];
  400. market_id = self.market_id;
  401. event_visitor_id = self.event_visitor_id;
  402. act_data_list = self.get_activity_items(market_id, activity_id, event_visitor_id);
  403. the_act_data = self.get_activity_data(activity_id, event_visitor_id);
  404. des_info = self.get_des_decode_info(activity_id, event_visitor_id);
  405. cate_act_type = sub_login_type;
  406. if des_info:
  407. if des_info["code"] != '0':
  408. # 5=已享这周首单优惠 7=人数过多稍后重试
  409. cate_act_type = 'subChoose'
  410. for act_data in act_data_list:
  411. act_type = act_data["type"]
  412. if act_type == cate_act_type:
  413. award_list = act_data["awardList"]
  414. new_award_item = self.check_pick_item(prize_name, award_list);
  415. if new_award_item:
  416. award_data = new_award_item;
  417. break;
  418. game_account = self.accout_id;
  419. third_info = json.loads(award_data["thirdInfo"]);
  420. award_id = award_data["awardId"];
  421. award_price = float(award_data["price"]);
  422. award_face_value = float(third_info["faceValue"]);
  423. award_data["faceValue"] = award_face_value;
  424. discount_price = self.get_award_expected_discount(award_face_value, prize_name);
  425. print(f"商品{prize_name}(面值:{award_face_value})\n匹配的最终价格:{award_price}\n预设折扣价格:{discount_price}#{award_id}");
  426. if award_price <= discount_price:
  427. activity_id = award_data["activityId"];
  428. pay_info = self.get_pay_info(activity_id, award_id, '', '', game_account, event_visitor_id);
  429. if pay_info:
  430. if "detailId" in pay_info:
  431. pay_ret = self.pay(activity_id, event_visitor_id, pay_info["detailId"]);
  432. if pay_ret:
  433. return award_data;
  434. else:
  435. print(f"未到预设折扣价格{discount_price},跳过~");
  436. return None;
  437. def get_activity_items(self, market_id, activity_id, event_visitor_id):
  438. url = f"https://{self.host}/h5/union/interactiveIGoChoose/marketIndexRebuild?marketId={market_id}&activityId={activity_id}&eventVisitorId={event_visitor_id}";
  439. print("请求活动商品列表数据");
  440. response = self.get_request(url);
  441. if response.status_code == 200:
  442. try:
  443. json_str = response.content;
  444. json_str = json_str.decode('utf-8');
  445. params = json.loads(json_str);
  446. if params.get('code') == 'success':
  447. print("请求活动商品列表数据成功");
  448. return params['data'];
  449. else:
  450. print(f"请求活动商品列表数据失败,响应:{json_str}");
  451. except Exception as e:
  452. print("请求活动商品列表发生错误");
  453. print(e);
  454. finally:
  455. pass
  456. else:
  457. print("请求活动商品列表发生错误");
  458. return None;
  459. def get_activity_data(self, activity_id, event_visitor_id):
  460. url = f"https://{self.host}/h5/api/mobile/activity/data?activityNo={activity_id}&eventVisitorId={event_visitor_id}";
  461. print("请求活动状态数据");
  462. response = self.get_request(url);
  463. if response.status_code == 200:
  464. try:
  465. json_str = response.content;
  466. json_str = json_str.decode('utf-8');
  467. params = json.loads(json_str);
  468. if params.get('code') == 'success':
  469. print("请求活动状态数据成功");
  470. return params['data'];
  471. else:
  472. print(f"请求活动状态数据失败,响应:{json_str}");
  473. except Exception as e:
  474. print("请求活动状态发生错误");
  475. print(e);
  476. finally:
  477. pass
  478. else:
  479. print("请求活动状态发生错误");
  480. return None;
  481. def get_des_decode_info(self, activity_id, event_visitor_id):
  482. url = f"https://{self.host}/h5/union/api/interactiveIGoChoose/getDesDecodeInfo?activityNo={activity_id}&eventVisitorId={event_visitor_id}";
  483. print("请求活动描述数据");
  484. response = self.get_request(url);
  485. if response.status_code == 200:
  486. try:
  487. json_str = response.content;
  488. json_str = json_str.decode('utf-8');
  489. params = json.loads(json_str);
  490. print("请求活动描述数据成功");
  491. print(json_str);
  492. return params;
  493. except Exception as e:
  494. print("请求活动描述发生错误");
  495. print(e);
  496. finally:
  497. pass
  498. else:
  499. print("请求活动描述发生错误");
  500. return None;
  501. def get_request(self, url, params=None, timeout=6):
  502. response = requests.get(url, headers=self.headers, params=params, cookies=self.cookies, timeout=timeout);
  503. return response;
  504. def post_request(self, url, data, timeout=6):
  505. response = requests.post(url, data=data, headers=self.headers, cookies=self.cookies, timeout=timeout);
  506. return response;
  507. def init_data_pre_excute():
  508. # print('init_shared_data');
  509. pass;
  510. def thread_worker_func(index, shared_namespace, account_info, activities_data):
  511. global g_shared_cache;
  512. g_shared_cache = shared_namespace.g_shared_cache;
  513. cli_options = shared_namespace.cli_options;
  514. print('########[%d]账号[%s]开始抢券工作########' % (index, account_info['account']));
  515. try:
  516. grabber = OfpayGrabber(account_info, activities_data, cli_options);
  517. results = grabber.start();
  518. except Exception as e:
  519. print(e);
  520. finally:
  521. pass
  522. if results:
  523. print(results);
  524. print(f"账号[{account_info['account']}]任务完成");
  525. print('###############################################\n');
  526. return {'account_info': account_info, 'results': results};
  527. # 守护进程
  528. def thread_daemon(func, *args, **kwargs):
  529. # print('thread_daemon');
  530. timeout = kwargs.get('timeout', None);
  531. p = ThreadPool(1);
  532. res = p.apply_async(func, args=args);
  533. try:
  534. out = res.get(timeout=timeout) # Wait timeout seconds for func to complete.
  535. return out;
  536. except multiprocessing.TimeoutError:
  537. print("Aborting due to timeout={}".format(args[0]));
  538. return (args[0], 444);
  539. def collect_result(result):
  540. # print("{}".format(result));
  541. pass;
  542. def main(cli_options):
  543. global g_shared_cache;
  544. g_shared_cache = SharedCache();
  545. g_shared_cache.set('test', 10);
  546. cpu_threads = multiprocessing.cpu_count();
  547. print(f"当前脚本模式 {cli_options.get('mode')}");
  548. print(f"fast -此模式快速,不会重新拉取商品列表,直接进行购买操作");
  549. print(f"normal-此模式正常,每次重新拉取商品列表,再进行购买操作");
  550. print(f"多线程检查: CPU支持 {cpu_threads} 个线程/核心");
  551. activities_data = read_json('elife_activities_data.json');
  552. accout_data = read_csv('elife_accout_data.csv');
  553. if cpu_threads > 1:
  554. # 创建进程池
  555. manager = Manager();
  556. # 创建共享命名空间
  557. shared_namespace = manager.Namespace();
  558. shared_namespace.g_shared_cache = g_shared_cache;
  559. shared_namespace.cli_options = cli_options;
  560. pool = multiprocessing.Pool(maxtasksperchild=1);
  561. results = [];
  562. index = 0;
  563. for item in accout_data:
  564. enable = int(item.get('enable'));
  565. if enable != 1:
  566. print('########账号[%s]抢券功能关闭########' % item['account']);
  567. continue;
  568. # result = pool.apply_async(thread_worker_func,(index, shared_namespace, item, activities_data,));
  569. # try:
  570. # print(result.get(timeout=3));
  571. # except multiprocessing.TimeoutError:
  572. # # pool.terminate();
  573. # print('########账号[%s]抢券执行超时########' % item['account']);
  574. # results.append(result);
  575. abortable_func = partial(thread_daemon, thread_worker_func, timeout=60);
  576. pool.apply_async(abortable_func, args=[index, shared_namespace, item, activities_data,], callback=collect_result);
  577. index += 1;
  578. # 关闭进程池,不再接受新的任务
  579. pool.close();
  580. # 等待所有任务完成
  581. pool.join();
  582. # for result in results:
  583. # print(result.get());
  584. else:
  585. for item in accout_data:
  586. enable = int(item.get('enable'));
  587. if enable != 1:
  588. print('########账号[%s]抢券功能关闭########' % item['account']);
  589. continue;
  590. print('########账号[%s]开始抢券工作########' % item['account']);
  591. grabber = OfpayGrabber(item, activities_data, cli_options);
  592. grabber.start();
  593. print('########################################');
  594. if __name__ == "__main__":
  595. parser = argparse.ArgumentParser();
  596. parser.add_argument('-m', '--mode', type=str,default='fast', help='mode(normal,fast)');
  597. parser.add_argument('-cs', '--check_stock', type=str,default='1', help='check stock');
  598. parser.add_argument('-cr', '--check_repeat', type=str,default='1', help='check repeat');
  599. args = parser.parse_args();
  600. args = vars(args);
  601. args_key_map = {
  602. 'ELIFE_OFPAY_GRAB_MODE': 'mode',
  603. 'ELIFE_OFPAY_CHECK_STOCK': 'check_stock',
  604. 'ELIFE_OFPAY_CHECK_REPEAT': 'check_repeat',
  605. };
  606. for key in args_key_map:
  607. value = os.getenv(key);
  608. if value != None:
  609. mkey = args_key_map[key];
  610. args[mkey] = value;
  611. main(args);