steam_purchase.py
import base64 import json import logging import os import sys import time # import qrcode import requests from lxml import etree requests.packages.urllib3.disable_warnings() from steam_master.steam.client import SteamClient from steam_master.steam.enums import EResult logging.basicConfig( level=logging.INFO, # 定义输出到文件的log级别,大于此级别的都被输出 format='%(asctime)s %(filename)s %(levelname)s : %(message)s', # 定义输出log的格式 datefmt='%Y-%m-%d %H:%M:%S', # 时间 filename="{}\\steam_cd_key.log".format(os.path.dirname(os.path.abspath(__file__))), # log文件名 filemode='a') # 写入模式“w”或“a” console = logging.StreamHandler() console.setLevel(logging.INFO) # 设置格式 formatter = logging.Formatter('%(asctime)s %(filename)s %(levelname)s : %(message)s') # 告诉handler使用这个格式 console.setFormatter(formatter) # 为root logger添加handler logging.getLogger('').addHandler(console) def steam_bind(username, password=None, auth_code=None, two_factor_code=None, user_sentry=None, file_path=None, payment="alipay", app_origin_id=None, file_path_QR=None): logging.info('username={}, auth_code={}, two_factor_code={}, user_sentry={}, file_path={}, payment={}, app_origin_id={}'.format(username, auth_code, two_factor_code, user_sentry, file_path, payment, app_origin_id)) item = {} if password == '0': password = None if auth_code == '0': auth_code = None if two_factor_code == '0': two_factor_code = None if user_sentry == '0': user_sentry = None if file_path == '0': file_path = None item["username"] = username item["app_origin_id"] = app_origin_id if file_path is not None: file_path = file_path else: file_path = "{}\\purchase.json".format(os.path.dirname(os.path.abspath(__file__)), username) if file_path_QR is not None: file_path_QR = file_path_QR else: file_path_QR = "{}\\QR_code.jpg".format(os.path.dirname(os.path.abspath(__file__))) file_path_sentry = "{}\\".format(os.path.dirname(os.path.abspath(__file__))) if user_sentry is not None: with open("{}{}_sentry.bin".format(file_path_sentry, username), 'wb') as f: f.write(base64.b64decode(user_sentry)) client = SteamClient() client.set_credential_location(file_path_sentry) result = client.login(username=username, password=password, auth_code=auth_code, two_factor_code=two_factor_code) if result == EResult.InvalidPassword: item["code"] = 4 item["message"] = "账号或密码错误:" elif result in (EResult.AccountLogonDenied, EResult.InvalidLoginAuthCode): if result == EResult.AccountLogonDenied: item["code"] = 5 item["message"] = "请输入邮箱验证码:" else: item["code"] = 6 item["message"] = "验证码不正确:请重新输入邮箱验证码:" elif result in (EResult.AccountLoginDeniedNeedTwoFactor, EResult.TwoFactorCodeMismatch): if result == EResult.AccountLoginDeniedNeedTwoFactor: item["code"] = 7 item["message"] = "请输入手机验证码:" else: item["code"] = 8 item["message"] = "验证码不正确:请重新输入手机验证码:" elif result == EResult.OK: item["code"] = 12 item["message"] = "steam登入成功:开始购买游戏:" logging.info("用户{}:登入成功".format(username)) try: with open("{}{}_sentry.bin".format(file_path_sentry, username), 'rb') as f: user_sentry = f.read() except: user_sentry = b'user is not bound steam' item['user_sentry'] = base64.b64encode(user_sentry).decode('utf-8') app_origin_id = app_origin_id headers = { "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36", } # 一键公开 session = client.get_web_session() # 获取session game_html = session.get("https://store.steampowered.com/app/{}".format(app_origin_id), verify=False).content.decode('utf-8') # proxies=REQUESTS_PROXIES etree_html = etree.HTML(game_html) add_data = {} try: add_data['snr'] = etree_html.xpath('//div[@class="game_area_purchase_game"]/form[@method="POST"]/input[@name="snr"]/@value')[0] add_data['originating_snr'] = etree_html.xpath('//div[@class="game_area_purchase_game"]/form[@method="POST"]/input[@name="originating_snr"]/@value')[0] add_data['action'] = etree_html.xpath('//div[@class="game_area_purchase_game"]/form[@method="POST"]/input[@name="action"]/@value')[0] add_data['sessionid'] = etree_html.xpath('//div[@class="game_area_purchase_game"]/form[@method="POST"]/input[@name="sessionid"]/@value')[0] add_data['subid'] = etree_html.xpath('//div[@class="game_area_purchase_game"]/form[@method="POST"]/input[@name="subid"]/@value')[0] except: item["code"] = 13 item["message"] = "游戏是免费游戏或者你已经拥有这个游戏:" add_data['snr'] = '' logging.info("游戏是免费游戏或者你已经拥有这个游戏") # print("{}".format(data)) if add_data['snr']: # try: logging.info(json.dumps(add_data, ensure_ascii=False)) logging.info('*' * 100) cart_html = session.post("https://store.steampowered.com/cart/", data=add_data, verify=False).content.decode('utf-8') etree_html = etree.HTML(cart_html) btn_purchase_self_url = etree_html.xpath('//*[@id="btn_purchase_self"]/@href')[0] self_html = session.get(btn_purchase_self_url, verify=False).content.decode('utf-8') self_etree_html = etree.HTML(self_html) mode_data = {} try: mode_data['gidShoppingCart'] = self_etree_html.xpath('//*[@id="shopping_cart_gid"]/@value')[0] except: mode_data['gidShoppingCart'] = -1 try: mode_data['gidReplayOfTransID'] = self_etree_html.xpath('//*[@id="gid_replay"]/@value')[0] except: mode_data['gidReplayOfTransID'] = -1 mode_data['PaymentMethod'] = payment mode_data['abortPendingTransactions'] = 0 mode_data['bHasCardInfo'] = False mode_data['CardNumber'] = '' mode_data['CardExpirationYear'] = '' mode_data['CardExpirationMonth'] = 0 mode_data['sessionid'] = add_data['sessionid'] mode_data['shopping_cart_gid'] = self_etree_html.xpath('//*[@id="shopping_cart_gid"]/@value')[0] mode_of_payment = session.post("https://store.steampowered.com/checkout/inittransaction/", data=mode_data, verify=False).content.decode('utf-8') if json.loads(mode_of_payment)['success'] == 1: mode_data['transid'] = json.loads(mode_of_payment)['transid'] logging.info(json.dumps(mode_data, ensure_ascii=False)) logging.info("*" * 100) get_final_price = session.get("https://store.steampowered.com/checkout/getfinalprice/?count=1&transid={}&purchasetype=selfµtxnid=-1&cart={}&gidReplayOfTransID=-1".format(mode_data['transid'], mode_data['shopping_cart_gid']), verify=False).content.decode('utf-8') # proxies=REQUESTS_PROXIES logging.info(json.dumps(get_final_price)) get_final_price = json.loads(get_final_price) if get_final_price['success'] == 1: item['original_price'] = int(get_final_price['base']) / 100 item['discount'] = int(get_final_price['discount']) if item['discount'] != 0: item['discount'] = item['discount'] / 100 item['real_price'] = int(get_final_price['total']) / 100 item['integral'] = get_final_price['lineitems'][0]['loyaltypoints'] payment_html = session.get("https://store.steampowered.com/checkout/externallink/?transid={}_external_provider".format(mode_data['transid']), verify=False).content.decode('utf-8') # 支付跳转 # print(payment_html) # print('*' * 100) payment_etree_html = etree.HTML(payment_html) payment_data = {} payment_url = payment_etree_html.xpath('//*[@id="externalForm"]/@action')[0] payment_data['MerchantID'] = payment_etree_html.xpath('//*[@id="externalForm"]/input[@name="MerchantID"]/@value')[0] payment_data['MerchantTransactionID'] = payment_etree_html.xpath('//*[@id="externalForm"]/input[@name="MerchantTransactionID"]/@value')[0] payment_data['Amount'] = payment_etree_html.xpath('//*[@id="externalForm"]/input[@name="Amount"]/@value')[0] payment_data['Currency'] = payment_etree_html.xpath('//*[@id="externalForm"]/input[@name="Currency"]/@value')[0] payment_data['ReturnURL'] = payment_etree_html.xpath('//*[@id="externalForm"]/input[@name="ReturnURL"]/@value')[0] payment_data['MethodID'] = payment_etree_html.xpath('//*[@id="externalForm"]/input[@name="MethodID"]/@value')[0] payment_data['Country'] = payment_etree_html.xpath('//*[@id="externalForm"]/input[@name="Country"]/@value')[0] payment_data['CustomerEmail'] = payment_etree_html.xpath('//*[@id="externalForm"]/input[@name="CustomerEmail"]/@value')[0] payment_data['CustomerName'] = payment_etree_html.xpath('//*[@id="externalForm"]/input[@name="CustomerName"]/@value')[0] payment_data['SkipHPP'] = payment_etree_html.xpath('//*[@id="externalForm"]/input[@name="SkipHPP"]/@value')[0] if payment == 'alipay': payment_data['Articles'] = payment_etree_html.xpath('//*[@id="externalForm"]/input[@name="Articles"]/@value')[0] payment_data['Description'] = payment_etree_html.xpath('//*[@id="externalForm"]/input[@name="Description"]/@value')[0] payment_data['SkinID'] = payment_etree_html.xpath('//*[@id="externalForm"]/input[@name="SkinID"]/@value')[0] payment_data['Hash'] = payment_etree_html.xpath('//*[@id="externalForm"]/input[@name="Hash"]/@value')[0] logging.info(json.dumps(payment_data, ensure_ascii=False)) logging.info("*" * 100) payments_html = session.post(payment_url, data=payment_data, verify=False, headers=headers) if payment == 'alipay': alipay_html = payments_html.content.decode('gbk') logging.info(payments_html.url) logging.info("*" * 100) logging.info(payments_html.headers) logging.info("*" * 100) alipay_etree_html = etree.HTML(alipay_html) alipay_code = alipay_etree_html.xpath('//*[@id="J_qrCode"]/@value')[0] item['payment_link'] = alipay_code logging.info(alipay_code) logging.info("*" * 100) # img = qrcode.make(alipay_code) # img.save(file_path_QR) # logging.info("二维码生成成功,请支付付款") else: wechat_html = payments_html.content.decode('utf-8') logging.info(payments_html.url) logging.info("*" * 100) wechat_etree_html = etree.HTML(wechat_html) wechat_code = wechat_etree_html.xpath('//*[@id="QRCodeImageControl"]/img/@src')[0] item['payment_link'] = wechat_code logging.info(wechat_code) logging.info("*" * 100) # with open(file_path_QR, 'wb') as file: # img = base64.b64decode(wechat_code.replace("data:image/gif;base64,", "")) # file.write(img) # logging.info("二维码生成成功,请支付付款") item["code"] = 17 item["message"] = "支付链接已经生成(微信是二维码base64编码,支付宝是支付链接):app_origin_id:{}".format(app_origin_id) try: with open(file_path, 'w') as f: json.dump(item, f) logging.info("文件写入成功") except Exception as e: logging.info("文件写入错误:{}".format(e)) for i in range(1200): transaction_status = session.get("https://store.steampowered.com/checkout/transactionstatus/?count=1&transid={}".format(mode_data['transid'])).content.decode('utf-8') logging.info("i:{}, transaction_status:{}".format(i, json.dumps(transaction_status))) logging.info("*" * 100) time.sleep(2) if json.loads(transaction_status)['success'] == 1: logging.info("{} 购买游戏成功:app_origin_id:{}".format(username, app_origin_id)) item["code"] = 200 item["message"] = "{} 购买游戏成功:app_origin_id:{}".format(username, app_origin_id) break if i == 600: logging.info("{} 购买游戏失败:app_origin_id:{} 请重新购买".format(username, app_origin_id)) item["code"] = 14 item["message"] = "{} 购买游戏失败:app_origin_id:{} 请重新购买".format(username, app_origin_id) break break else: logging.info("前面购买这个这个游戏失败或支付为成功请重新购买 app_origin_id:{}".format(app_origin_id)) item["code"] = 16 item["message"] = "前面购买这个这个游戏失败或支付为成功请重新购买 app_origin_id:{}".format(app_origin_id) else: logging.info("过去几个小时内尝试了多次购买。请在重试前稍等片刻") item["code"] = 15 item["message"] = "过去几个小时内尝试了多次购买。请在重试前稍等片刻" # except: # item['code'] = 14 # item["message"] = "username:{} 购买游戏失败:app_origin_id:{} 请重新购买".format(username, app_origin_id) # logging.info("游戏购买失败") try: logging.info("{}{}_sentry.bin".format(file_path_sentry, username)) os.remove("{}{}_sentry.bin".format(file_path_sentry, username)) logging.info("删除文件成功:{}{}_sentry.bin".format(file_path_sentry, username)) except Exception as e: logging.info("删除用户认证文件异常:{}".format(e)) client.logout() logging.info('username:{}, message:, auth_code:{}, two_factor_code:{}, code:, result:{}'.format(username, auth_code, two_factor_code, result)) elif result == EResult.RateLimitExceeded: item["code"] = 10 item["message"] = "请求频率过高,请稍后在请求:" else: item["code"] = 99 item["message"] = "未知错误" item["result"] = result item["username"] = username try: with open(file_path, 'w') as f: json.dump(item, f) logging.info("文件写入成功") except Exception as e: logging.info("文件写入错误:{}".format(e)) logging.info("item:{}".format(item)) if __name__ == "__main__": # steam_bind('17682303516', 'Yu1064145110', payment="alipay", app_origin_id="1168660") # steam_bind('yoyo12165', 'Yu1064145110', payment="wechat", app_origin_id="1168660") # steam_bind('17682303516', 'yu1064145110', file_path="{}\\{}_info.json".format(os.path.dirname(os.path.abspath(__file__)), "uname")) steam_bind(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5], sys.argv[6], sys.argv[7], sys.argv[8], sys.argv[9])