KR/backUp/jd_openCard.py

1205 lines
48 KiB
Python
Raw Normal View History

2022-02-11 16:56:14 +08:00
#!/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', '<br/>'),
"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 更新远程shopid08,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()