#!/bin/env python3 # -*- coding: utf-8 -* ''' 项目名称: JD_OpenCard Author: Curtin 功能:JD入会开卡领取京豆 CreateDate: 2021/5/4 下午1:47 UpdateTime: 2022/1/1 建议cron: 2 8,15 * * * python3 jd_OpenCard.py new Env('开卡有礼'); ''' version = 'v1.3.1' readmes = """ # JD入会领豆小程序 @Version: {}""".format(version) ################################ 【Main】################################ import time, os, sys, datetime import requests import random, string import re, json, base64 from urllib.parse import unquote, quote_plus from threading import Thread from configparser import RawConfigParser # 定义一些要用到参数 requests.packages.urllib3.disable_warnings() scriptHeader = """ ════════════════════════════════════════ ║ ║ ║ JD 入 会 领 豆 ║ ║ ║ ════════════════════════════════════════ @Version: {}""".format(version) remarks = '\n' timestamp = int(round(time.time() * 1000)) today = datetime.datetime.now().strftime('%Y-%m-%d') # 获取当前工作目录 pwd = os.path.dirname(os.path.abspath(__file__)) + os.sep ###### openCardBean = 0 sleepNum = 0.0 record = True onlyRecord = False memory = True printlog = True isRemoteSid = True Concurrent = True TG_BOT_TOKEN = '' TG_USER_ID = '' PUSH_PLUS_TOKEN = '' TG_PROXY_IP = '' TG_PROXY_PORT = '' TG_API_HOST = '' QYWX_AM = '' BARK = '' DoubleThread = True JD_COOKIE_CHECK = "true" # 获取账号参数 try: configinfo = RawConfigParser() try: configinfo.read(pwd + "OpenCardConfig.ini", encoding="UTF-8") except Exception as e: with open(pwd + "OpenCardConfig.ini", "r", encoding="UTF-8") as config: getConfig = config.read().encode('utf-8').decode('utf-8-sig') with open(pwd + "OpenCardConfig.ini", "w", encoding="UTF-8") as config: config.write(getConfig) try: configinfo.read(pwd + "OpenCardConfig.ini", encoding="UTF-8") except: configinfo.read(pwd + "OpenCardConfig.ini", encoding="gbk") cookies = configinfo.get('main', 'JD_COOKIE') openCardBean = configinfo.getint('main', 'openCardBean') sleepNum = configinfo.getfloat('main', 'sleepNum') record = configinfo.getboolean('main', 'record') onlyRecord = configinfo.getboolean('main', 'onlyRecord') memory = configinfo.getboolean('main', 'memory') printlog = configinfo.getboolean('main', 'printlog') isRemoteSid = configinfo.getboolean('main', 'isRemoteSid') TG_BOT_TOKEN = configinfo.get('main', 'TG_BOT_TOKEN') TG_USER_ID = configinfo.get('main', 'TG_USER_ID') PUSH_PLUS_TOKEN = configinfo.get('main', 'PUSH_PLUS_TOKEN') TG_PROXY_IP = configinfo.get('main', 'TG_PROXY_IP') TG_PROXY_PORT = configinfo.get('main', 'TG_PROXY_PORT') TG_API_HOST = configinfo.get('main', 'TG_API_HOST') QYWX_AM = configinfo.get('main', 'QYWX_AM') Concurrent = configinfo.getboolean('main', 'Concurrent') DoubleThread = configinfo.getboolean('main', 'DoubleThread') BARK = configinfo.get('main', 'BARK') JD_COOKIE_CHECK = configinfo.get('main', 'JD_COOKIE_CHECK') except Exception as e: OpenCardConfigLabel = 1 print("参数配置有误,请检查OpenCardConfig.ini\nError:", e) print("尝试从Env环境获取!") def getBool(label): try: if label == 'True' or label == 'yes' or label == 'true' or label == 'Yes': return True elif label == 'False' or label == 'no' or label == 'false' or label == 'No': return False else: return True except Exception as e: print(e) # 获取系统ENV环境参数优先使用 适合Ac、云服务等环境 # JD_COOKIE=cookie (多账号&分隔) if "JD_COOKIE" in os.environ: if len(os.environ["JD_COOKIE"]) > 10: cookies = os.environ["JD_COOKIE"] print("已获取并使用Env环境 Cookie") # 只入送豆数量大于此值 if "openCardBean" in os.environ: if len(os.environ["openCardBean"]) > 0: openCardBean = int(os.environ["openCardBean"]) print("已获取并使用Env环境 openCardBean:", openCardBean) elif not openCardBean: openCardBean = 0 # 是否开启双线程 if "DoubleThread" in os.environ: if len(os.environ["DoubleThread"]) > 1: DoubleThread = getBool(os.environ["DoubleThread"]) print("已获取并使用Env环境 DoubleThread", DoubleThread) # 多账号并发 if "Concurrent" in os.environ: if len(os.environ["Concurrent"]) > 1: Concurrent = getBool(os.environ["Concurrent"]) print("已获取并使用Env环境 Concurrent", Concurrent) elif not Concurrent: Concurrent = True # 限制速度,单位秒,如果请求过快报错适当调整0.5秒以上 if "sleepNum" in os.environ: if len(os.environ["sleepNum"]) > 0: sleepNum = float(os.environ["sleepNum"]) print("已获取并使用Env环境 sleepNum:", sleepNum) elif not sleepNum: sleepNum = 0 if "printlog" in os.environ: if len(os.environ["printlog"]) > 1: printlog = getBool(os.environ["printlog"]) print("已获取并使用Env环境 printlog:", printlog) elif not printlog: printlog = True # 是否记录符合条件的shopid,输出文件【OpenCardlog/yes_shopid.txt】 False|True if "record" in os.environ: if len(os.environ["record"]) > 1: record = getBool(os.environ["record"]) print("已获取并使用Env环境 record:", record) elif not record: record = True # 仅记录,不入会。入会有豆的shopid输出文件 if "onlyRecord" in os.environ: if len(os.environ["onlyRecord"]) > 1: onlyRecord = getBool(os.environ["onlyRecord"]) print("已获取并使用Env环境 onlyRecord:", onlyRecord) elif not onlyRecord: onlyRecord = False # 开启记忆, 需要record=True且 memory= True 才生效 if "memory" in os.environ: if len(os.environ["memory"]) > 1: memory = getBool(os.environ["memory"]) print("已获取并使用Env环境 memory:", memory) elif not memory: memory = True # 是否启用远程shopid if "isRemoteSid" in os.environ: if len(os.environ["isRemoteSid"]) > 1: isRemoteSid = getBool(os.environ["isRemoteSid"]) print("已获取并使用Env环境 isRemoteSid:", isRemoteSid) elif not isRemoteSid: isRemoteSid = True # 获取TG_BOT_TOKEN if "TG_BOT_TOKEN" in os.environ: if len(os.environ["TG_BOT_TOKEN"]) > 1: TG_BOT_TOKEN = os.environ["TG_BOT_TOKEN"] print("已获取并使用Env环境 TG_BOT_TOKEN") # 获取TG_USER_ID if "TG_USER_ID" in os.environ: if len(os.environ["TG_USER_ID"]) > 1: TG_USER_ID = os.environ["TG_USER_ID"] print("已获取并使用Env环境 TG_USER_ID") # 获取代理ip if "TG_PROXY_IP" in os.environ: if len(os.environ["TG_PROXY_IP"]) > 1: TG_PROXY_IP = os.environ["TG_PROXY_IP"] print("已获取并使用Env环境 TG_PROXY_IP") # 获取TG 代理端口 if "TG_PROXY_PORT" in os.environ: if len(os.environ["TG_PROXY_PORT"]) > 1: TG_PROXY_PORT = os.environ["TG_PROXY_PORT"] print("已获取并使用Env环境 TG_PROXY_PORT") elif not TG_PROXY_PORT: TG_PROXY_PORT = '' # 获取TG TG_API_HOST if "TG_API_HOST" in os.environ: if len(os.environ["TG_API_HOST"]) > 1: TG_API_HOST = os.environ["TG_API_HOST"] print("已获取并使用Env环境 TG_API_HOST") # 获取pushplus+ PUSH_PLUS_TOKEN if "PUSH_PLUS_TOKEN" in os.environ: if len(os.environ["PUSH_PLUS_TOKEN"]) > 1: PUSH_PLUS_TOKEN = os.environ["PUSH_PLUS_TOKEN"] print("已获取并使用Env环境 PUSH_PLUS_TOKEN") # 获取企业微信应用推送 QYWX_AM if "QYWX_AM" in os.environ: if len(os.environ["QYWX_AM"]) > 1: QYWX_AM = os.environ["QYWX_AM"] print("已获取并使用Env环境 QYWX_AM") # 获取企业微信应用推送 QYWX_AM if "BARK" in os.environ: if len(os.environ["BARK"]) > 1: BARK = os.environ["BARK"] print("已获取并使用Env环境 BARK") if "JD_COOKIE_CHECK" in os.environ: if len(os.environ["JD_COOKIE_CHECK"]) > 1: JD_COOKIE_CHECK = os.environ["JD_COOKIE_CHECK"] else: JD_COOKIE_CHECK = "true" # 判断参数是否存在 try: cookies except NameError as e: var_exists = False print("[OpenCardConfig.ini] 和 [Env环境] 都无法获取到您的cookies,请配置!\nError:", e) time.sleep(60) exit(1) else: var_exists = True # 创建临时目录 if not os.path.exists(pwd + "log"): os.mkdir(pwd + "log") # 记录功能json memoryJson = {} message_info = '' notify_mode = [] ################################### Function ################################ class TaskThread(Thread): """ 处理task相关的线程类 """ def __init__(self, func, args=()): super(TaskThread, self).__init__() self.func = func # 要执行的task类型 self.args = args # 要传入的参数 def run(self): self.result = self.func(*self.args) # 将任务执行结果赋值给self.result变量 def get_result(self): # 改方法返回task函数的执行结果,方法名不是非要get_result try: return self.result except Exception as ex: print(ex) return "ERROR" def nowtime(): return datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') def printinfo(context, label: bool): if label == False: print(context) def exitCodeFun(code): try: if sys.platform == 'win32' or sys.platform == 'cygwin': print("连按回车键即可退出窗口!") exitCode = input() exit(code) except: time.sleep(3) exit(code) def message(str_msg): global message_info print(str_msg) message_info = "{}\n{}".format(message_info, str_msg) sys.stdout.flush() # 获取通知, if PUSH_PLUS_TOKEN: notify_mode.append('pushplus') if TG_BOT_TOKEN and TG_USER_ID: notify_mode.append('telegram_bot') if QYWX_AM: notify_mode.append('wecom_app') if BARK: notify_mode.append('bark') # tg通知 def telegram_bot(title, content): try: print("\n") bot_token = TG_BOT_TOKEN user_id = TG_USER_ID if not bot_token or not user_id: print("tg服务的bot_token或者user_id未设置!!\n取消推送") return print("tg服务启动") if TG_API_HOST: if 'http' in TG_API_HOST: url = f"{TG_API_HOST}/bot{TG_BOT_TOKEN}/sendMessage" else: url = f"https://{TG_API_HOST}/bot{TG_BOT_TOKEN}/sendMessage" else: url = f"https://api.telegram.org/bot{TG_BOT_TOKEN}/sendMessage" headers = {'Content-Type': 'application/x-www-form-urlencoded'} payload = {'chat_id': str(TG_USER_ID), 'text': f'{title}\n\n{content}', 'disable_web_page_preview': 'true'} proxies = None if TG_PROXY_IP and TG_PROXY_PORT: proxyStr = "http://{}:{}".format(TG_PROXY_IP, TG_PROXY_PORT) proxies = {"http": proxyStr, "https": proxyStr} try: response = requests.post(url=url, headers=headers, params=payload, proxies=proxies).json() except: print('推送失败!') if response['ok']: print('推送成功!') else: print('推送失败!') except Exception as e: print(e) # push推送 def pushplus_bot(title, content): try: print("\n") if not PUSH_PLUS_TOKEN: print("PUSHPLUS服务的token未设置!!\n取消推送") return print("PUSHPLUS服务启动") url = 'http://www.pushplus.plus/send' data = { "token": PUSH_PLUS_TOKEN, "title": title, "content": content } body = json.dumps(data).encode(encoding='utf-8') headers = {'Content-Type': 'application/json'} response = requests.post(url=url, data=body, headers=headers).json() if response['code'] == 200: print('推送成功!') else: print('推送失败!') except Exception as e: print(e) # BARK def bark_push(title, content): print("\n") if not BARK: print("bark服务的bark_token未设置!!\n取消推送") return print("bark服务启动") try: response = requests.get('''https://api.day.app/{0}/{1}/{2}'''.format(BARK, title, quote_plus(content))).json() if response['code'] == 200: print('推送成功!') else: print('推送失败!') except Exception as e: print(e) print('Bark推送失败!') def send(title, content): """ 使用 bark, telegram bot, dingding bot, serverJ 发送手机推送 :param title: :param content: :return: """ content = content + "\n\n" + footer for i in notify_mode: if i == 'telegram_bot': if TG_BOT_TOKEN and TG_USER_ID: telegram_bot(title=title, content=content) else: print('未启用 telegram机器人') continue elif i == 'pushplus': if PUSH_PLUS_TOKEN: pushplus_bot(title=title, content=content) else: print('未启用 PUSHPLUS机器人') continue elif i == 'wecom_app': if QYWX_AM: wecom_app(title=title, content=content) else: print('未启用企业微信应用消息推送') continue elif i == 'bark': if BARK: bark_push(title=title, content=content) else: print('未启用Bark APP应用消息推送') continue else: print('此类推送方式不存在') # 企业微信 APP 推送 def wecom_app(title, content): try: if not QYWX_AM: print("QYWX_AM 并未设置!!\n取消推送") return QYWX_AM_AY = re.split(',', QYWX_AM) if 4 < len(QYWX_AM_AY) > 5: print("QYWX_AM 设置错误!!\n取消推送") return corpid = QYWX_AM_AY[0] corpsecret = QYWX_AM_AY[1] touser = QYWX_AM_AY[2] agentid = QYWX_AM_AY[3] try: media_id = QYWX_AM_AY[4] except: media_id = '' wx = WeCom(corpid, corpsecret, agentid) # 如果没有配置 media_id 默认就以 text 方式发送 if not media_id: message = title + '\n\n' + content response = wx.send_text(message, touser) else: response = wx.send_mpnews(title, content, media_id, touser) if response == 'ok': print('推送成功!') else: print('推送失败!错误信息如下:\n', response) except Exception as e: print(e) class WeCom: def __init__(self, corpid, corpsecret, agentid): self.CORPID = corpid self.CORPSECRET = corpsecret self.AGENTID = agentid def get_access_token(self): url = 'https://qyapi.weixin.qq.com/cgi-bin/gettoken' values = {'corpid': self.CORPID, 'corpsecret': self.CORPSECRET, } req = requests.post(url, params=values) data = json.loads(req.text) return data["access_token"] def send_text(self, message, touser="@all"): send_url = 'https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=' + self.get_access_token() send_values = { "touser": touser, "msgtype": "text", "agentid": self.AGENTID, "text": { "content": message }, "safe": "0" } send_msges = (bytes(json.dumps(send_values), 'utf-8')) respone = requests.post(send_url, send_msges) respone = respone.json() return respone["errmsg"] def send_mpnews(self, title, message, media_id, touser="@all"): send_url = 'https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=' + self.get_access_token() send_values = { "touser": touser, "msgtype": "mpnews", "agentid": self.AGENTID, "mpnews": { "articles": [ { "title": title, "thumb_media_id": media_id, "author": "Author", "content_source_url": "", "content": message.replace('\n', '
'), "digest": message } ] } } send_msges = (bytes(json.dumps(send_values), 'utf-8')) respone = requests.post(send_url, send_msges) respone = respone.json() return respone["errmsg"] # 检测cookie格式是否正确 def iscookie(): """ :return: cookiesList,userNameList,pinNameList """ cookiesList = [] userNameList = [] pinNameList = [] if 'pt_key=' in cookies and 'pt_pin=' in cookies: r = re.compile(r"pt_key=.*?pt_pin=.*?;", re.M | re.S | re.I) result = r.findall(cookies) if len(result) >= 1: message("您已配置{}个账号".format(len(result))) u = 1 for i in result: r = re.compile(r"pt_pin=(.*?);") pinName = r.findall(i) pinName = unquote(pinName[0]) # 获取账号名 if JD_COOKIE_CHECK == "true": ck, nickname = getUserInfo(i, pinName, u) if nickname != False: cookiesList.append(ck) userNameList.append(nickname) pinNameList.append(pinName) else: u += 1 continue else: cookiesList.append(i) userNameList.append(pinName) pinNameList.append(pinName) u += 1 if len(cookiesList) > 0 and len(userNameList) > 0: return cookiesList, userNameList, pinNameList else: message("没有可用Cookie,已退出") exitCodeFun(3) else: message("cookie 格式错误!...本次操作已退出") exitCodeFun(4) else: message("cookie 格式错误!...本次操作已退出") exitCodeFun(4) # 检查是否有更新版本 def gettext(url): try: resp = requests.get(url, timeout=60).text if '该内容无法显示' in resp: return gettext(url) return resp except Exception as e: print(e) def isUpdate(): global footer, readme1, readme2, readme3, uPversion url = base64.decodebytes( b"aHR0cHM6Ly9naXRlZS5jb20vY3VydGlubHYvUHVibGljL3Jhdy9tYXN0ZXIvT3BlbkNhcmQvdXBkYXRlLmpzb24=") try: result = gettext(url) result = json.loads(result) isEnable = result['isEnable'] uPversion = result['version'] info = result['info'] readme1 = result['readme1'] readme2 = result['readme2'] readme3 = "\n目前每天07:30和14:30 更新远程shopid,08,15点后跑一次即可。" pError = result['m'] footer = '' getWait = result['s'] if isEnable > 50 and isEnable < 150: if version != uPversion: print(f"\n当前最新版本:【{uPversion}】\n\n{info}\n") message(f"{readme1}{readme2}{readme3}") time.sleep(getWait) else: message(f"{readme1}{readme2}{readme3}") time.sleep(getWait) else: print(pError) time.sleep(300) exit(666) except: message("请检查您的环境/版本是否正常!") time.sleep(10) exit(666) # # def getUserInfo(ck, pinName, userNum): # url = 'https://me-api.jd.com/user_new/info/GetJDUserInfoUnion?orgFlag=JD_PinGou_New&callSource=mainorder&channel=4&isHomewhite=0&sceneval=2&sceneval=2&callback=GetJDUserInfoUnion' # headers = { # 'Cookie': ck, # 'Accept': '*/*', # 'Connection': 'close', # 'Referer': 'https://home.m.jd.com/myJd/home.action', # 'Accept-Encoding': 'gzip, deflate, br', # 'Host': 'me-api.jd.com', # 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.2 Mobile/15E148 Safari/604.1', # 'Accept-Language': 'zh-cn' # } # try: # resp = requests.get(url=url, verify=False, headers=headers, timeout=60).text # r = re.compile(r'GetJDUserInfoUnion.*?\((.*?)\)') # result = r.findall(resp) # userInfo = json.loads(result[0]) # nickname = userInfo['data']['userInfo']['baseInfo']['nickname'] # return ck, nickname # except Exception: # context = f"账号{userNum}【{pinName}】Cookie 已失效!请重新获取。" # message(context) # send("【JD入会领豆】Cookie 已失效!", context) # return ck, False def getUserInfo(ck, pinName, userNum): url = 'https://me-api.jd.com/user_new/info/GetJDUserInfoUnion?orgFlag=JD_PinGou_New&callSource=mainorder&channel=4&isHomewhite=0&sceneval=2&_=&sceneval=2&g_login_type=1' headers = { 'Cookie' : ck, 'Accept' : '*/*', 'Connection' : 'keep-alive', 'Referer' : 'https://home.m.jd.com/', 'Accept-Encoding' : 'gzip, deflate, br', 'Host' : 'me-api.jd.com', 'User-Agent' : 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1', 'Accept-Language' : 'zh-CN,zh-Hans;q=0.9' } try: if sys.platform == 'ios': requests.packages.urllib3.disable_warnings() resp = requests.get(url=url, verify=False, headers=headers, timeout=60).json() else: resp = requests.get(url=url, headers=headers, timeout=60).json() # print(json.dumps(resp, indent=4 , ensure_ascii=False)) if resp['retcode'] == "0": nickname = resp['data']['userInfo']['baseInfo']['nickname'] return ck, nickname else: context = f"账号{userNum}【{pinName}】Cookie 已失效!请重新获取。" print(context) return ck, False except Exception: context = f"账号{userNum}【{pinName}】Cookie 已失效!请重新获取。" print(context) return ck, False # 设置Headers def setHeaders(cookie, intype): if intype == 'mall': headers = { "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Host": "mall.jd.com", "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.2 Safari/605.1.15", "Accept-Language": "zh-cn", "Accept-Encoding": "gzip, deflate, br", "Connection": "close" } return headers elif intype == 'JDApp': headers = { 'Cookie': cookie, 'Accept': "*/*", 'Connection': "close", 'Referer': "https://shopmember.m.jd.com/shopcard/?", 'Accept-Encoding': "gzip, deflate, br", 'Host': "api.m.jd.com", 'User-Agent': "jdapp;iPhone;9.4.8;14.3;809409cbd5bb8a0fa8fff41378c1afe91b8075ad;network/wifi;ADID/201EDE7F-5111-49E8-9F0D-CCF9677CD6FE;supportApplePay/0;hasUPPay/0;hasOCPay/0;model/iPhone13,4;addressid/;supportBestPay/0;appBuild/167629;jdSupportDarkMode/0;Mozilla/5.0 (iPhone; CPU iPhone OS 14_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 'Accept-Language': "zh-cn" } return headers elif intype == 'mh5': headers = { 'Cookie': cookie, 'Accept': "*/*", 'Connection': "close", 'Referer': "https://shopmember.m.jd.com/shopcard/?", 'Accept-Encoding': "gzip, deflate, br", 'Host': "api.m.jd.com", 'User-Agent': "Mozilla/5.0 (iPhone; CPU iPhone OS 14_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1", 'Accept-Language': "zh-cn" } return headers # 记录符合件的shopid到本地文件保存 当前目录:OpenCardlog/shopid-yyyy-mm-dd.txt 或 log-yyyy-mm-dd.txt def outfile(filename, context, iscover): """ :param filename: 文件名 默认txt格式 :param context: 写入内容 :param iscover: 是否覆盖 False or True :return: """ if record == True: try: if iscover == False: with open(pwd + "log/{0}".format(filename), "a+", encoding="utf-8") as f1: f1.write("{}\n".format(context)) f1.close() elif iscover == True: with open(pwd + "{0}".format(filename), "w+", encoding="utf-8") as f1: f1.write("{}".format(context)) f1.close() except Exception as e: print(e) # 记忆功能 默认双线程 def memoryFun(startNum, threadNum, usernameLabel, username, getallbean, userCount): global memoryJson if memory == True: if usernameLabel == True: memoryJson['allShopidNum'] = endShopidNum memoryJson['currUser{}'.format(threadNum)] = username memoryJson['t{}_startNum'.format(threadNum)] = startNum memoryJson['allUserCount'] = userCount if usernameLabel == False: try: memoryJson['{}'.format(username)] memoryJson['{}'.format(username)] += getallbean except: memoryJson['{}'.format(username)] = getallbean try: memoryJson['{}_ok'.format(username)] memoryJson['{}_ok'.format(username)] += 1 except: memoryJson['{}_ok'.format(username)] = 1 try: if os.path.exists(pwd + "log"): with open(pwd + "log/memory.json", "w+", encoding="utf-8") as f: json.dump(memoryJson, f, indent=4) else: pass except Exception as e: print(e) # 修复记忆功能一些问题,如记录累计京豆统计显示为0等 def isMemoryEnable(): global memoryJson memoryJson = getMemory() # 获取记忆配置 def getMemory(): """ :return: memoryJson """ if os.path.exists(pwd + "log/memory.json"): with open(pwd + "log/memory.json", "r", encoding="utf-8") as f: memoryJson = json.load(f) if len(memoryJson) > 0: return memoryJson else: pass def rmCount(): if os.path.exists(pwd + "log/入会汇总.txt"): os.remove(pwd + "log/入会汇总.txt") if os.path.exists(pwd + "log/memory.json"): os.remove(pwd + "log/memory.json") # 判断是否启用记忆功能 def isMemory(memorylabel, startNum1, startNum2, midNum, endNum, pinNameList): """ :param memorylabel: 记忆标签 :param startNum1: 线程1默认开始位置 :param startNum2: 线程2默认开始位置 :param midNum: 线程1默认结束位置 :param endNum: 线程2默认结束位置 :return: startNum1, startNum2, memorylabel """ if memory == True and memorylabel == 0: try: memoryJson = getMemory() if memoryJson['allShopidNum'] == endNum: currUserLabel = 0 if memoryJson['allUserCount'] == allUserCount: for u in pinNameList: if memoryJson['currUser1'] == u: currUserLabel += 1 elif memoryJson['currUser2'] == u: currUserLabel += 1 if memoryJson['currUser1'] == memoryJson['currUser2']: currUserLabel = 2 if currUserLabel < 2: print("通知:检测到您配置的CK有变更,本次记忆功能不生效。") rmCount() return startNum1, startNum2, memorylabel if memoryJson['t1_startNum'] + 1 == midNum and memoryJson['t2_startNum'] + 1 == endNum: print( f"\n上次已完成所有shopid。\n\n请输入 0 或 1\n0 : 退出。\n1 : 重新跑一次,以防有漏") if "JD_COOKIE" in os.environ: print("当前Env环境,即将退出") exit(0) try: getyourNum = int(input("正在等待您的选择:")) if getyourNum == 1: print("Ok,那就重新跑一次~") rmCount() memorylabel = 1 return startNum1, startNum2, memorylabel elif getyourNum == 0: print("Ok,已退出~") time.sleep(10) exit(0) except: # print("Error: 您的输入有误!已退出。") exitCodeFun(3) else: isMemoryEnable() if memoryJson['t1_startNum']: startNum1 = memoryJson['t1_startNum'] message(f"已启用记忆功能 memory= True,线程1从第【{startNum1}】店铺开始") if memoryJson['t2_startNum']: startNum2 = memoryJson['t2_startNum'] message(f"已启用记忆功能 memory= True,线程2从第【{startNum2}】店铺开始") memorylabel = 1 return startNum1, startNum2, memorylabel else: message("通知:检测到您配置的CK有变更,本次记忆功能不生效。") rmCount() return startNum1, startNum2, memorylabel else: message("通知:检测到shopid有更新,本次记忆功能不生效。") rmCount() memorylabel = 1 return startNum1, startNum2, memorylabel except Exception as e: memorylabel = 1 return startNum1, startNum2, memorylabel else: rmCount() memorylabel = 1 return startNum1, startNum2, memorylabel # 获取VenderId def getVenderId(shopId, headers): """ :param shopId: :param headers :return: venderId """ url = 'https://mall.jd.com/index-{0}.html'.format(shopId) resp = requests.get(url=url, verify=False, headers=headers, timeout=60) resulttext = resp.text r = re.compile(r'shopId=\d+&id=(\d+)"') venderId = r.findall(resulttext) return venderId[0] # 查询礼包 def getShopOpenCardInfo(venderId, headers, shopid, userName, user_num): """ :param venderId: :param headers: :return: activityId,getBean 或 返回 0:没豆 1:有豆已是会员 2:记录模式(不入会) """ num1 = string.digits v_num1 = ''.join(random.sample(["1", "2", "3", "4", "5", "6", "7", "8", "9"], 1)) + ''.join( random.sample(num1, 4)) # 随机生成一窜4位数字 url = 'https://api.m.jd.com/client.action?appid=jd_shop_member&functionId=getShopOpenCardInfo&body=%7B%22venderId%22%3A%22{2}%22%2C%22channel%22%3A406%7D&client=H5&clientVersion=9.2.0&uuid=&jsonp=jsonp_{0}_{1}'.format( timestamp, v_num1, venderId) resp = requests.get(url=url, verify=False, headers=headers, timeout=60) time.sleep(sleepNum) resulttxt = resp.text r = re.compile(r'jsonp_.*?\((.*?)\)\;', re.M | re.S | re.I) result = r.findall(resulttxt) cardInfo = json.loads(result[0]) venderCardName = cardInfo['result']['shopMemberCardInfo']['venderCardName'] # 店铺名称 if user_num == 1: printinfo(f"\t└查询入会礼包【{venderCardName}】", printlog) openCardStatus = cardInfo['result']['userInfo']['openCardStatus'] # 是否会员 interestsRuleList = cardInfo['result']['interestsRuleList'] if interestsRuleList == None: if user_num == 1: printinfo("\t\t└查询该店入会没有送豆,不入会", printlog) return 0, 0 try: if len(interestsRuleList) > 0: for i in interestsRuleList: if "京豆" in i['prizeName']: getBean = int(i['discountString']) activityId = i['interestsInfo']['activityId'] context = "{0}".format(shopid) outfile(f"shopid-{today}.txt", context, False) # 记录所有送豆的shopid in_url = 'https://shop.m.jd.com/?shopId={}'.format(shopid) url = 'https://shopmember.m.jd.com/member/memberCloseAccount?venderId={}'.format(venderId) context = "[{0}]:入会{2}豆店铺【{1}】\n\t加入会员:{4}\n\t解绑会员:{3}".format(nowtime(), venderCardName, getBean, url, in_url) # 记录 if user_num == 1: outfile("入会汇总.txt", context, False) if getBean >= openCardBean: # 判断豆是否符合您的需求 print(f"\t└账号{user_num}【{userName}】{venderCardName}:入会赠送【{getBean}豆】,可入会") context = "{0}".format(shopid) outfile(f"入会{openCardBean}豆以上的shopid-{today}.txt", context, False) if onlyRecord == True: if user_num == 1: print("已开启仅记录,不入会。") return 2, 2 if openCardStatus == 1: url = 'https://shopmember.m.jd.com/member/memberCloseAccount?venderId={}'.format(venderId) print("\t\t└[账号:{0}]:您已经是本店会员,请注销会员卡24小时后再来~\n注销链接:{1}".format(userName, url)) context = "[{3}]:入会{1}豆,{0}销卡:{2}".format(venderCardName, getBean, url, nowtime()) outfile("可退会账号【{0}】.txt".format(userName), context, False) return 1, 1 return activityId, getBean else: if user_num == 1: print(f'\t\t└{venderCardName}:入会送【{getBean}】豆少于【{openCardBean}豆】,不入...') if onlyRecord == True: if user_num == 1: print("已开启仅记录,不入会。") return 2, 2 return 0, openCardStatus else: pass if user_num == 1: printinfo("\t\t└查询该店入会没有送豆,不入会", printlog) return 0, 0 else: return 0, 0 except Exception as e: print(e) # 开卡 def bindWithVender(venderId, shopId, activityId, channel, headers): """ :param venderId: :param shopId: :param activityId: :param channel: :param headers: :return: result : 开卡结果 """ num = string.ascii_letters + string.digits v_name = ''.join(random.sample(num, 10)) num1 = string.digits v_num1 = ''.join(random.sample(["1", "2", "3", "4", "5", "6", "7", "8", "9"], 1)) + ''.join(random.sample(num1, 4)) qq_num = ''.join(random.sample(["1", "2", "3", "4", "5", "6", "7", "8", "9"], 1)) + ''.join( random.sample(num1, 8)) + "@qq.com" url = 'https://api.m.jd.com/client.action?appid=jd_shop_member&functionId=bindWithVender&body=%7B%22venderId%22%3A%22{4}%22%2C%22shopId%22%3A%22{7}%22%2C%22bindByVerifyCodeFlag%22%3A1%2C%22registerExtend%22%3A%7B%22v_sex%22%3A%22%E6%9C%AA%E7%9F%A5%22%2C%22v_name%22%3A%22{0}%22%2C%22v_birthday%22%3A%221990-03-18%22%2C%22v_email%22%3A%22{6}%22%7D%2C%22writeChildFlag%22%3A0%2C%22activityId%22%3A{5}%2C%22channel%22%3A{3}%7D&client=H5&clientVersion=9.2.0&uuid=&jsonp=jsonp_{1}_{2}'.format( v_name, timestamp, v_num1, channel, venderId, activityId, qq_num, shopId) try: respon = requests.get(url=url, verify=False, headers=headers, timeout=60) result = respon.text return result except Exception as e: print(e) # 获取开卡结果 def getResult(resulttxt, userName, user_num): r = re.compile(r'jsonp_.*?\((.*?)\)\;', re.M | re.S | re.I) result = r.findall(resulttxt) for i in result: result_data = json.loads(i) busiCode = result_data['busiCode'] if busiCode == '0': message = result_data['message'] try: result = result_data['result']['giftInfo']['giftList'] print(f"\t\t└账号{user_num}【{userName}】:{message}") for i in result: print("\t\t\t└{0}:{1} ".format(i['prizeTypeName'], i['discount'])) except: print(f'\t\t└账号{user_num}【{userName}】:{message}') return busiCode else: print("\t\t└账号{0}【{1}】:{2}".format(user_num, userName, result_data['message'])) return busiCode def getRemoteShopid(): global shopidList, venderidList shopidList = [] venderidList = [] url = base64.decodebytes( b"aHR0cHM6Ly9naXRlZS5jb20vY3VydGlubHYvUHVibGljL3Jhdy9tYXN0ZXIvT3BlbkNhcmQvc2hvcGlkLnR4dA==") try: rShopid = gettext(url) rShopid = rShopid.split("\n") for i in rShopid: if len(i) > 0: shopidList.append(i.split(':')[0]) venderidList.append(i.split(':')[1]) return shopidList, venderidList except: print("无法从远程获取shopid") exitCodeFun(999) # 读取shopid.txt def getShopID(): shopid_path = pwd + "shopid.txt" try: with open(shopid_path, "r", encoding="utf-8") as f: shopid = f.read() if len(shopid) > 0: shopid = shopid.split("\n") return shopid else: print("Error:请检查shopid.txt文件是否正常!\n") exitCodeFun(2) except Exception as e: print("Error:请检查shopid.txt文件是否正常!\n", e) exitCodeFun(2) # 进度条 def progress_bar(start, end, threadNum): print("\r", end="") if threadNum == 2: start2 = start - midNum end2 = end - midNum print("\n###[{1}]:线程{2}【当前进度: {0}%】\n".format(round(start2 / end2 * 100, 2), nowtime(), threadNum)) elif threadNum == 1: print("\n###[{1}]:线程{2}【当前进度: {0}%】\n".format(round(start / end * 100, 2), nowtime(), threadNum)) sys.stdout.flush() ## 多账号并发 def sss(ii, ck, userName, pinName, endNum, user_num, shopids, threadNum): if ii % 10 == 0 and ii != 0 and user_num == 1: progress_bar(ii, endNum, threadNum) try: if len(shopids[ii]) > 0: headers_b = setHeaders(ck, "mall") # 获取请求头 if isRemoteSid: venderId = venderidList[shopidList.index(shopids[ii])] else: venderId = getVenderId(shopids[ii], headers_b) # 获取venderId time.sleep(sleepNum) # 根据您需求是否限制请求速度 # 新增记忆功能 memoryFun(ii, threadNum, True, pinName, 0, allUserCount) headers_a = setHeaders(ck, "mh5") activityId, getBean = getShopOpenCardInfo(venderId, headers_a, shopids[ii], userName, user_num) # 获取入会礼包结果 # activityId,getBean 或 返回 0:没豆 1:有豆已是会员 2:记录模式(不入会) time.sleep(sleepNum) # 根据账号需求是否限制请求速度 if activityId == 0 or activityId == 2: pass elif activityId > 10: headers = setHeaders(ck, "JDApp") result = bindWithVender(venderId, shopids[ii], activityId, 208, headers) busiCode = getResult(result, userName, user_num) if busiCode == '0': memoryFun(ii, threadNum, False, pinName, getBean, allUserCount) memoryJson = getMemory() print(f"账号{user_num}:【{userName}】累计获得:{memoryJson['{}'.format(pinName)]} 京豆") time.sleep(sleepNum) else: pass except Exception as e: if user_num == 1: # print(f"【Error】:多账号并发报错,请求过快建议适当调整 sleepNum 参数限制速度 \n{e}") pass # 为多线程准备 def OpenVipCard(startNum: int, endNum: int, shopids, cookies, userNames, pinNameList, threadNum): sssLabel = 0 for i in range(startNum, endNum): user_num = 1 if Concurrent: if sssLabel == 0 and threadNum == 1: if DoubleThread: message("当前模式: 双线程,多账号并发运行") else: message("当前模式: 单线程,多账号并发运行") sssLabel = 1 threads = [] for ck, userName, pinName in zip(cookies, userNames, pinNameList): tt = TaskThread(sss, args=(i, ck, userName, pinName, endNum, user_num, shopids, threadNum)) threads.append(tt) tt.start() user_num += 1 time.sleep(sleepNum) for t in threads: t.join() time.sleep(sleepNum) else: if sssLabel == 0 and threadNum == 1: if DoubleThread: message("当前模式: 双线程,单账号运行") else: message("当前模式: 单线程,单账号运行") sssLabel = 1 activityIdLabel = 0 for ck, userName, pinName in zip(cookies, userNames, pinNameList): if i % 10 == 0 and i != 0: progress_bar(i, endNum, threadNum) try: if len(shopids[i]) > 0: headers_b = setHeaders(ck, "mall") # 获取请求头 venderId = getVenderId(shopids[i], headers_b) # 获取venderId time.sleep(sleepNum) # 根据账号需求是否限制请求速度 # 新增记忆功能 memoryFun(i, threadNum, True, pinName, 0, allUserCount) if activityIdLabel == 0: s = random.randint(0, allUserCount - 1) headers_a = setHeaders(cookies[s], "mh5") activityId, getBean = getShopOpenCardInfo(venderId, headers_a, shopids[i], userName, user_num) # 获取入会礼包结果 # activityId,getBean 或 返回 0:没豆 1:有豆已是会员 2:记录模式(不入会) time.sleep(sleepNum) # 根据账号需求是否限制请求速度 if activityId == 0 or activityId == 2: break elif activityId == 1: user_num += 1 continue elif activityId > 10: activityIdLabel = 1 headers = setHeaders(ck, "JDApp") result = bindWithVender(venderId, shopids[i], activityId, 208, headers) busiCode = getResult(result, userName, user_num) if busiCode == '0': memoryFun(i, threadNum, False, pinName, getBean, allUserCount) memoryJson = getMemory() print(f"账号{user_num}:【{userName}】累计获得:{memoryJson['{}'.format(pinName)]} 京豆") time.sleep(sleepNum) else: break except Exception as e: user_num += 1 print(e) continue user_num += 1 # start def start(): global allUserCount print(scriptHeader) outfile("Readme.md", readmes, True) isUpdate() global endShopidNum, midNum, allUserCount if isRemoteSid: message("已启用远程获取shopid") allShopid, venderidList = getRemoteShopid() else: message("从本地shopid.txt获取shopid") allShopid = getShopID() allShopid = list(set(allShopid)) endShopidNum = len(allShopid) midNum = int(endShopidNum / 2) message("获取到店铺数量: {}".format(endShopidNum)) message(f"您已设置入会条件:{openCardBean} 京豆") print("获取账号...") cookies, userNames, pinNameList = iscookie() allUserCount = len(cookies) message("共{}个有效账号".format(allUserCount)) memorylabel = 0 startNum1 = 0 startNum2 = midNum starttime = time.perf_counter() # 记录时间开始 if endShopidNum > 1 and DoubleThread: # 如果启用记忆功能,则获取上一次记忆位置 startNum1, startNum2, memorylabel = isMemory(memorylabel, startNum1, startNum2, midNum, endShopidNum, pinNameList) # 多线程部分 threads = [] t1 = Thread(target=OpenVipCard, args=(startNum1, midNum, allShopid, cookies, userNames, pinNameList, 1)) threads.append(t1) t2 = Thread(target=OpenVipCard, args=(startNum2, endShopidNum, allShopid, cookies, userNames, pinNameList, 2)) threads.append(t2) try: for t in threads: t.setDaemon(True) t.start() for t in threads: t.join() isSuccess = True progress_bar(1, 1, 1) progress_bar(1, 1, 2) except: isSuccess = False elif endShopidNum == 1 or not DoubleThread: startNum1, startNum2, memorylabel = isMemory(memorylabel, startNum1, startNum2, midNum, endShopidNum, pinNameList) OpenVipCard(startNum1, endShopidNum, allShopid, cookies, userNames, pinNameList, 1) isSuccess = True else: message("获取到shopid数量为0") exitCodeFun(9) endtime = time.perf_counter() # 记录时间结束 if os.path.exists(pwd + "log/memory.json"): memoryJson = getMemory() n = 1 message("\n###【本次统计 {}】###\n".format(nowtime())) all_get_bean = 0 for name, pinname in zip(userNames, pinNameList): try: userCountBean = memoryJson['{}'.format(pinname)] successJoin = memoryJson['{}_ok'.format(pinname)] message(f"账号{n}:【{name}】\n\t└成功入会【{successJoin}】个,收获【{userCountBean}】京豆") all_get_bean += userCountBean except Exception as e: message(f"账号{n}:【{name}】\n\t└成功入会【0】个,收获【0】京豆") n += 1 message(f"\n本次总累计获得:{all_get_bean} 京豆") time.sleep(1) message("\n------- 入会总耗时 : %.03f 秒 seconds -------" % (endtime - starttime)) print("{0}\n{1}\n{2}".format("*" * 30, scriptHeader, remarks)) send("【JD入会领豆】", message_info) exitCodeFun(0) if __name__ == '__main__': start()