OfpayGrab.py 25 KB

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