def slotService(): reqs = request.json action = request.json['action'] if 'id' in request.json: id = request.json['id'] serial = request.json['serial'] type = request.json['type'] if 'remark' in request.json: remark = request.json['remark'] else: remark = "Backed"; if 'page' in reqs: page = reqs['page'] else: page = 1; if not action: return jsonify({'success': False, 'msg': u'paramter action is missed'}) if not serial: return jsonify({'success': False, 'msg': u'paramter serial is missed'}) slot = Slot(serial, type) if action == "save": if remark == "": remark = "BackUp" slot.backup(id, remark) return jsonify({'success': True, 'msg': u'Save slot success'}) if action == "restore": slot.restore(id) return jsonify({'success': True, 'msg': u'Restore slot success'}) if action == "clear": slot.clear(id) return jsonify({'success': True, 'msg': u'Clear slot success'}) if action == "list": result = [] slots = slot.getSlots() if not slots: slots = {}; idFrom = (page - 1)*20 + 1 idTo = (page-1) * 20 + 20 for index in range(idFrom, idTo + 1): if slots.has_key(str(index)) : obj = slots[str(index)] obj['empty'] = False; obj['id'] = index else: obj = {'id':index, 'empty': True} result.append(obj) return jsonify({'slots': result }) return "-"
class MobilqqLogin: def __init__(self): self.type = 'mobileqq' self.repo = Repo() def GetUnique(self): nowTime = datetime.datetime.now().strftime("%Y%m%d%H%M%S") # 生成当前时间 randomNum = random.randint(0, 1000) # 生成的随机整数n,其中0<=n<=100 if randomNum <= 10: randomNum = str(00) + str(randomNum) uniqueNum = str(nowTime) + str(randomNum) return uniqueNum def WebViewBlankPages(self, d): Str = d.info # 获取屏幕大小等信息 height = float(Str["displayHeight"]) width = float(Str["displayWidth"]) W_H = width / height screenScale = round(W_H, 2) base_dir = os.path.abspath( os.path.join(os.path.dirname(__file__), os.path.pardir, "tmp")) if not os.path.isdir(base_dir): os.mkdir(base_dir) sourcePng = os.path.join(base_dir, "%s_s.png" % (self.GetUnique())) if screenScale == 0.56: left = 60 # 验证码的位置信息 top = 500 right = 290 bottom = 600 if screenScale == 0.61: left = 60 # 验证码的位置信息 top = 490 right = 210 bottom = 510 # left = width * 7 / 135 # 验证码的位置信息 # top = height * 245 / 444 # right = width * 51 / 54 # bottom = height * 275 / 444 d.screenshot(sourcePng) # 截取整个输入验证码时的屏幕 img = Image.open(sourcePng) box = (left, top, right, bottom) # left top right bottom region = img.crop(box) # 截取验证码的图片 # show(region) #展示资料卡上的信息 image = region.convert('RGBA') # 生成缩略图,减少计算量,减小cpu压力 image.thumbnail((200, 200)) max_score = None dominant_color = None for count, (r, g, b, a) in image.getcolors(image.size[0] * image.size[1]): # 跳过纯黑色 if a == 0: continue saturation = colorsys.rgb_to_hsv(r / 255.0, g / 255.0, b / 255.0)[1] y = min( abs(r * 2104 + g * 4130 + b * 802 + 4096 + 131072) >> 13, 235) y = (y - 16.0) / (235 - 16) # 忽略高亮色 if y > 0.9: continue score = (saturation + 0.1) * count if score > max_score: max_score = score dominant_color = (r, g, b) # 红绿蓝 return dominant_color def WebViewPlayCode(self, d, z): z.toast("开始截图打码") Str = d.info # 获取屏幕大小等信息 height = float(Str["displayHeight"]) width = float(Str["displayWidth"]) W_H = width / height screenScale = round(W_H, 2) base_dir = os.path.abspath( os.path.join(os.path.dirname(__file__), os.path.pardir, "tmp")) if not os.path.isdir(base_dir): os.mkdir(base_dir) sourcePng = os.path.join(base_dir, "%s_s.png" % (self.GetUnique())) icode = imageCode() im_id = "" for i in range(0, 1): # 打码循环 if i > 0: icode.reportError(im_id) d.screenshot(sourcePng) # 截取整个输入验证码时的屏幕 if screenScale == 0.61: p = { "x1": 30 / width, "y1": 200 / height, "x2": 271 / width, "y2": 300 / height } if screenScale == 0.56: p = { "x1": 40 / width, "y1": 270 / height, "x2": 362 / width, "y2": 400 / height } cropedImg = z.img_crop(sourcePng, p) im = open(cropedImg, 'rb') codeResult = icode.getCode(im, icode.CODE_TYPE_4_NUMBER_CHAR, 60) code = codeResult["Result"] im_id = codeResult["Id"] os.remove(sourcePng) z.heartbeat() z.sleep(5) if screenScale == 0.61: d.click(360, 240) if screenScale == 0.56: d.click(500, 350) z.input(code) z.sleep(2) if screenScale == 0.61: d.click(270, 450) if screenScale == 0.56: d.click(360, 600) while d(className='android.widget.ProgressBar', index=0).exists: # 网速不给力时,点击完成后仍然在加载时的状态 z.sleep(2) z.sleep(8) if not d(textContains='验证码').exists: z.toast("机器人打码跳出--") break def BindAddressBook(self, z, d, args): z.toast("点击开始绑定") self.scode = smsCode(d.server.adb.device_serial()) d(text='马上绑定').click() while d(text='验证手机号码').exists: PhoneNumber = None j = 0 while PhoneNumber is None: j += 1 PhoneNumber = self.scode.GetPhoneNumber( self.scode.QQ_CONTACT_BIND) # 获取接码平台手机号码 z.heartbeat() if j == 2: z.toast('取不到手机号码') if (args["time_delay"]): z.sleep(int(args["time_delay"])) return if not d(textContains='+86').exists: d(description='点击选择国家和地区').click() if d(text='中国').exists: d(text='中国').click() else: str = d.info # 获取屏幕大小等信息 height = str["displayHeight"] width = str["displayWidth"] d.click(width * 5 / 12, height * 5 / 32) z.sleep(1.5) z.input('中国') z.sleep(2) d(text='+86').click() z.input(PhoneNumber) z.sleep(1.5) if d(text='下一步').exists: d(text='下一步').click() z.sleep(3) e = 0 while d(text='正在发送请求').exists: z.sleep(2) z.sleep(10) z.heartbeat() if d(text='确定').exists: d(text='确定').click() z.sleep(2) code = self.scode.GetVertifyCode(PhoneNumber, self.scode.QQ_CONTACT_BIND, '4') # 获取接码验证码 self.scode.defriendPhoneNumber(PhoneNumber, self.scode.QQ_CONTACT_BIND) if code == '': z.toast(PhoneNumber + '手机号,获取不到验证码') if d(text='返回').exists: d(text='返回').click() if not d(textContains='中国').exists: if d(text='返回').exists: d(text='返回').click() if d(className='android.view.View', descriptionContains='删除').exists: d(className='android.view.View', descriptionContains='删除').click() continue z.heartbeat() z.input(code) if d(text='完成').exists: d(text='完成').click() z.sleep(15) break def login(self, d, args, z): z.heartbeat() self.scode = smsCode(d.server.adb.device_serial()) base_dir = os.path.abspath( os.path.join(os.path.dirname(__file__), os.path.pardir, "tmp")) if not os.path.isdir(base_dir): os.mkdir(base_dir) sourcePng = os.path.join(base_dir, "%s_s.png" % (self.GetUnique())) codePng = os.path.join(base_dir, "%s_c.png" % (self.GetUnique())) cate_id = args["repo_cate_id"] time_limit1 = args['time_limit1'] numbers = self.repo.GetAccount(cate_id, time_limit1, 1) while len(numbers) == 0: z.heartbeat() d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"QQ帐号库%s号仓库无%s分钟未用,开始切换卡槽\"" % (cate_id, time_limit1)).communicate() z.sleep(2) return 0 QQNumber = numbers[0]['number'] # 即将登陆的QQ号 QQPassword = numbers[0]['password'] z.sleep(1) z.heartbeat() d.server.adb.cmd("shell", "pm clear com.tencent.mobileqq").communicate() # 清除缓存 d.server.adb.cmd( "shell", "am start -n com.tencent.mobileqq/com.tencent.mobileqq.activity.SplashActivity" ).communicate() # 拉起来 while d(textContains='正在更新数据').exists: z.sleep(2) z.sleep(20) z.heartbeat() d.dump(compressed=False) if d(text='登 录', resourceId='com.tencent.mobileqq:id/btn_login').exists: d(text='登 录').click() z.sleep(1) # d(className='android.widget.EditText', index=0).set_text(QQNumber) # 1918697054----xiake1234. QQNumber d(className='android.widget.EditText', index=0).click() # 1918697054----xiake1234. QQNumber z.input(QQNumber) z.sleep(1) # d(resourceId='com.tencent.mobileqq:id/password').set_text(QQPassword) # Bn2kJq5l QQPassword d(resourceId='com.tencent.mobileqq:id/password').click( ) # Bn2kJq5l QQPassword z.input(QQPassword) z.heartbeat() logger = util.logger print('QQ号:%s,QQ密码:%s' % (QQNumber, QQPassword)) d.dump(compressed=False) d(text='登 录', resourceId='com.tencent.mobileqq:id/login').click() z.sleep(1) while d(text='登录中').exists: z.sleep(2) z.sleep(20) z.heartbeat() loginStatusList = z.qq_getLoginStatus(d) if loginStatusList is None: if d(text='消息').exists and d(text='联系人').exists and d( text='动态').exists: loginStatusList = {'success': True} else: loginStatusList = {'success': False} loginStatus = loginStatusList['success'] if loginStatus: return QQNumber detection_robot = d(index='3', className="android.widget.EditText") not_detection_robot = d(resourceId='com.tencent.mobileqq:id/name', index='2', className="android.widget.EditText") if detection_robot.exists or not_detection_robot.exists: # 需要验证码的情况 z.toast("非网页打码") icode = imageCode() im_id = "" for i in range(0, 4): # 打码循环 if i > 0: icode.reportError(im_id) obj = d(resourceId='com.tencent.mobileqq:id/name', className='android.widget.ImageView' ) # 当弹出选择QQ框的时候,定位不到验证码图片 if not obj.exists: obj = d(index='2', className='android.widget.Image') obj = obj.info obj = obj['bounds'] # 验证码处的信息 left = obj["left"] # 验证码的位置信息 top = obj['top'] right = obj['right'] bottom = obj['bottom'] d.screenshot(sourcePng) # 截取整个输入验证码时的屏幕 img = Image.open(sourcePng) box = (left, top, right, bottom) # left top right bottom region = img.crop(box) # 截取验证码的图片 img = Image.new('RGBA', (right - left, bottom - top)) img.paste(region, (0, 0)) img.save(codePng) im = open(codePng, 'rb') codeResult = icode.getCode(im, icode.CODE_TYPE_4_NUMBER_CHAR, 60) code = codeResult["Result"] im_id = codeResult["Id"] os.remove(sourcePng) os.remove(codePng) z.heartbeat() z.sleep(5) if not_detection_robot.exists: d(resourceId='com.tencent.mobileqq:id/name', index='2', className="android.widget.EditText").set_text(code) else: detection_robot.set_text(code) z.sleep(3) if d(descriptionContains='验证', className='android.view.View').exists: d(descriptionContains='验证', className='android.view.View').click() else: d(text='完成', resourceId='com.tencent.mobileqq:id/ivTitleBtnRightText' ).click() z.sleep(6) z.heartbeat() while d(className='android.widget.ProgressBar', index=0).exists: # 网速不给力时,点击完成后仍然在加载时的状态 z.sleep(2) z.sleep(3) z.heartbeat() if detection_robot.exists or not_detection_robot.exists: continue else: break z.sleep(5) if d(textContains='验证码').exists: return "nothing" else: if self.WebViewBlankPages(d)[2] > 200: z.toast("不是空白页") self.WebViewPlayCode(d, z) z.heartbeat() # z.toast( "强制停止,拉起" ) # d.server.adb.cmd( "shell", "am force-stop com.tencent.mobileqq" ).communicate( ) # 强制停止 # z.sleep( 1 ) # d.server.adb.cmd( "shell", # "am start -n com.tencent.mobileqq/com.tencent.mobileqq.activity.SplashActivity" ).communicate( ) # 拉起来 z.sleep(5) z.heartbeat() loginStatusList = z.qq_getLoginStatus(d) if loginStatusList is None: if d(text='消息').exists and d(text='联系人').exists and d( text='动态').exists: loginStatusList = {'success': True} else: z.toast("登陆新场景,现无法判断登陆状态") loginStatusList = {'success': False} loginStatus = loginStatusList['success'] if loginStatus: z.toast("卡槽QQ状态正常,继续执行") else: if d(text='去安全中心').exists: self.repo.BackupInfo(cate_id, 'frozen', QQNumber, '', '') # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber else: self.repo.BackupInfo(cate_id, 'normal', QQNumber, '', '') z.toast("卡槽QQ状态异常,跳过此模块") return "nothing" if d(text='马上绑定').exists: self.BindAddressBook(z, d, args) if d(text='匹配手机通讯录').exists: # 登陆上后弹出t通讯录的情况 d(text='匹配手机通讯录').click() z.sleep(1.5) if d(text='取消').exists: d(text='取消').child() if d(textContains="请在小米神隐模式中将TIM设置为“无限制”。").exists: z.toast("我是小米神隐") d(text='我知道了').click() return QQNumber def qiehuan(self, d, z, args): time_limit = int(args['time_limit']) cate_id = args["repo_cate_id"] serial = d.server.adb.device_serial() self.slot = Slot(serial, self.type) slotObj = self.slot.getAvailableSlot(time_limit) # 没有空卡槽,取2小时没用过的卡槽 if not slotObj is None: slotnum = slotObj['id'] while slotnum == 0: # 2小时没有用过的卡槽也为空的情况 d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"QQ卡槽全满,无间隔时间段未用\"" ).communicate() z.heartbeat() z.sleep(30) slotObj = self.slot.getAvailableSlot( time_limit) # 没有空卡槽,取2小时没用过的卡槽 if not slotObj is None: slotnum = slotObj['id'] z.heartbeat() d.server.adb.cmd("shell", "pm clear com.tencent.mobileqq").communicate() # 清除缓存 d.server.adb.cmd( "shell", "settings put global airplane_mode_on 1").communicate() d.server.adb.cmd( "shell", "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true" ).communicate() z.sleep(6) z.heartbeat() d.server.adb.cmd( "shell", "settings put global airplane_mode_on 0").communicate() d.server.adb.cmd( "shell", "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false" ).communicate() z.heartbeat() while True: ping = d.server.adb.cmd("shell", "ping -c 3 baidu.com").communicate() print(ping) if 'icmp_seq' and 'bytes from' and 'time' in ping[0]: break z.sleep(2) obj = self.slot.getSlotInfo(slotnum) remark = obj['remark'] remarkArr = remark.split("_") if len(remarkArr) == 3: slotInfo = d.server.adb.device_serial( ) + '_' + self.type + '_' + slotnum cateId = remarkArr[2] numbers = self.repo.Getserial(cateId, slotInfo) featureCodeInfo = numbers[0]['imei'] z.set_serial("com.tencent.mobileqq", featureCodeInfo) self.slot.restore(slotnum) # 有time_limit分钟没用过的卡槽情况,切换卡槽 d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"卡槽成功切换为" + str(slotnum) + "号\"").communicate() z.sleep(2) if d(textContains='主题装扮').exists: d(text='关闭').click() z.sleep(1) d.server.adb.cmd( "shell", "am start -n com.tencent.mobileqq/com.tencent.mobileqq.activity.SplashActivity" ).communicate() # 拉起来 z.sleep(2) z.heartbeat() loginStatusList = z.qq_getLoginStatus(d) if loginStatusList is None: if d(text='消息').exists and d(text='联系人').exists and d( text='动态').exists: loginStatusList = {'success': True} else: z.toast("登陆新场景,现无法判断登陆状态") loginStatusList = {'success': False} loginStatus = loginStatusList['success'] if loginStatus: z.toast("卡槽QQ状态正常,继续执行") else: obj = self.slot.getSlotInfo(slotnum) remark = obj['remark'] remarkArr = remark.split("_") QQnumber = remarkArr[1] if d(text='去安全中心').exists: self.repo.BackupInfo(cate_id, 'frozen', QQnumber, '', '') # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber else: self.repo.BackupInfo(cate_id, 'normal', QQnumber, '', '') self.slot.clear(slotnum) # 清空改卡槽,并补登 z.toast("卡槽QQ状态异常,补登陆卡槽") self.action(d, z, args) if d(text='马上绑定').exists: self.BindAddressBook(z, d, args) if d(textContains="请在小米神隐模式中将TIM设置为“无限制”。").exists: z.toast("我是小米神隐") d(text='我知道了').click() if d(text='匹配手机通讯录').exists: # 登陆上后弹出t通讯录的情况 d(text='匹配手机通讯录').click() z.sleep(1.5) if d(text='取消').exists: d(text='取消').child() def action(self, d, z, args): z.toast("正在ping网络是否通畅") z.heartbeat() i = 0 while i < 200: i += 1 ping = d.server.adb.cmd("shell", "ping -c 3 baidu.com").communicate() print(ping) if 'icmp_seq' and 'bytes from' and 'time' in ping[0]: z.toast("网络通畅。开始执行:普通QQ登录有卡槽") break z.sleep(2) if i > 200: z.toast("网络不通,请检查网络状态") if (args["time_delay"]): z.sleep(int(args["time_delay"])) return z.heartbeat() z.generate_serial("com.tencent.mobileqq") # 随机生成手机特征码 time_limit = int(args['time_limit']) cate_id = args["repo_cate_id"] serial = d.server.adb.device_serial() self.slot = Slot(serial, self.type) slotnum = self.slot.getEmpty() # 取空卡槽 if slotnum == 0: #没有空卡槽的话 slotObj = self.slot.getAvailableSlot(time_limit) # 取空卡槽,取2小时没用过的卡槽 if not slotObj is None: slotnum = slotObj['id'] print(slotnum) while slotObj is None: # 2小时没用过的卡槽也为没有的情况 d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"QQ卡槽全满,无间隔时间段未用\"" ).communicate() z.heartbeat() z.sleep(30) slotObj = self.slot.getAvailableSlot(time_limit) if not slotObj is None: slotnum = slotObj['id'] z.heartbeat() d.server.adb.cmd( "shell", "pm clear com.tencent.mobileqq").communicate() # 清除缓存 d.server.adb.cmd( "shell", "settings put global airplane_mode_on 1").communicate() #开飞行模式 d.server.adb.cmd( "shell", "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true" ).communicate() z.sleep(6) z.heartbeat() d.server.adb.cmd("shell", "settings put global airplane_mode_on 0" ).communicate() # 关飞行模式 d.server.adb.cmd( "shell", "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false" ).communicate() z.heartbeat() while True: ping = d.server.adb.cmd("shell", "ping -c 3 baidu.com").communicate() print(ping) if 'icmp_seq' and 'bytes from' and 'time' in ping[0]: break z.sleep(2) obj = self.slot.getSlotInfo(slotnum) remark = obj['remark'] remarkArr = remark.split("_") if len(remarkArr) == 3: slotInfo = d.server.adb.device_serial( ) + '_' + self.type + '_' + slotnum cateId = remarkArr[2] numbers = self.repo.Getserial(cateId, slotInfo) featureCodeInfo = numbers[0]['imei'] z.set_serial("com.tencent.mobileqq", featureCodeInfo) self.slot.restore(slotnum) # 有time_limit分钟没用过的卡槽情况,切换卡槽 z.sleep(2) d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"卡槽成功切换为" + slotnum + "号\"").communicate() z.sleep(2) d.server.adb.cmd( "shell", "am start -n com.tencent.mobileqq/com.tencent.mobileqq.activity.SplashActivity" ).communicate() # 拉起来 z.sleep(2) z.heartbeat() loginStatusList = z.qq_getLoginStatus(d) if loginStatusList is None: if d(text='消息').exists and d(text='联系人').exists and d( text='动态').exists: loginStatusList = {'success': True} else: z.toast("登陆新场景,现无法判断登陆状态") loginStatusList = {'success': False} loginStatus = loginStatusList['success'] if loginStatus: z.toast("卡槽QQ状态正常,继续执行") else: obj = self.slot.getSlotInfo(slotnum) remark = obj['remark'] remarkArr = remark.split("_") QQnumber = remarkArr[1] if d(text='去安全中心').exists: self.repo.BackupInfo(cate_id, 'frozen', QQnumber, '', '') # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber else: self.repo.BackupInfo(cate_id, 'normal', QQnumber, '', '') self.slot.clear(slotnum) # 清空改卡槽,并补登 z.toast("卡槽QQ状态异常,补登陆卡槽") self.action(d, z, args) if d(text='马上绑定').exists: self.BindAddressBook(z, d, args) if d(textContains="请在小米神隐模式中将TIM设置为“无限制”。").exists: z.toast("我是小米神隐") d(text='我知道了').click() if d(text='匹配手机通讯录').exists: # 登陆上后弹出t通讯录的情况 d(text='匹配手机通讯录').click() z.sleep(1.5) if d(text='取消').exists: d(text='取消').child() else: # 有空卡槽的情况 d.server.adb.cmd( "shell", "pm clear com.tencent.mobileqq").communicate() # 清除缓存 d.server.adb.cmd( "shell", "settings put global airplane_mode_on 1").communicate() d.server.adb.cmd( "shell", "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true" ).communicate() z.sleep(6) d.server.adb.cmd( "shell", "settings put global airplane_mode_on 0").communicate() d.server.adb.cmd( "shell", "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false" ).communicate() z.heartbeat() while True: ping = d.server.adb.cmd("shell", "ping -c 3 baidu.com").communicate() print(ping) if 'icmp_seq' and 'bytes from' and 'time' in ping[0]: break z.sleep(2) serialinfo = d.server.adb.device_serial() # print('登陆时的serial%s'%serialinfo) z.heartbeat() QQnumber = self.login(d, args, z) if QQnumber == 'nothing': self.slot.clear(slotnum) # 清空改卡槽,并补登 self.action(d, z, args) if QQnumber == 0: z.toast("仓库为空,无法登陆。开始切换卡槽") self.qiehuan(d, z, args) z.heartbeat() featureCodeInfo = z.get_serial("com.tencent.mobileqq") self.slot.backup(slotnum, str(slotnum) + '_' + QQnumber + '_' + cate_id) # 设备信息,卡槽号,QQ号 self.repo.BackupInfo(cate_id, 'using', QQnumber, featureCodeInfo, '%s_%s_%s' % (d.server.adb.device_serial(), self.type, slotnum)) # 仓库号,使用中,QQ号,设备号_卡槽号 if (args["time_delay"]): z.sleep(int(args["time_delay"]))
class InternationqqLogin: def __init__(self): self.type = 'mobileqqi' self.repo = Repo() self.codedll = codeDLL() def GetUnique(self): nowTime = datetime.datetime.now().strftime("%Y%m%d%H%M%S"); # 生成当前时间 randomNum = random.randint(0, 1000); # 生成的随机整数n,其中0<=n<=100 if randomNum <= 10: randomNum = str(00) + str(randomNum); uniqueNum = str(nowTime) + str(randomNum); return uniqueNum def playCode(self, codeImgObj): z.toast("非网页视图打码") self.scode = smsCode(d.server.adb.device_serial()) base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir, "tmp")) if not os.path.isdir(base_dir): os.mkdir(base_dir) sourcePng = os.path.join(base_dir, "%s_s.png" % (self.GetUnique())) codePng = os.path.join(base_dir, "%s_c.png" % (self.GetUnique())) icode = imageCode() im_id = "" for i in range(0, 4): # 打码循环 if i > 0: icode.reportError(im_id) obj = d(resourceId='com.tencent.mobileqqi:id/0', className='android.widget.ImageView') # 当弹出选择QQ框的时候,定位不到验证码图片 if not obj.exists: return False obj = obj.info obj = obj['bounds'] # 验证码处的信息 left = obj["left"] # 验证码的位置信息 top = obj['top'] right = obj['right'] bottom = obj['bottom'] d.screenshot(sourcePng) # 截取整个输入验证码时的屏幕 img = Image.open(sourcePng) box = (left, top, right, bottom) # left top right bottom region = img.crop(box) # 截取验证码的图片 img = Image.new('RGBA', (right - left, bottom - top)) img.paste(region, (0, 0)) img.save(codePng) with open( codePng, 'rb' ) as im: codeResult = self.codedll.QQPlayCode( im ) # im = open(codePng, 'rb') # # codeResult = icode.getCode(im, icode.CODE_TYPE_4_NUMBER_CHAR, 60) # # code = codeResult["Result"] # im_id = codeResult["Id"] # os.remove(sourcePng) # os.remove(codePng) # # z.sleep(3) # z.heartbeat() # codeImgObj.set_text(code) # 输入获取的验证码 # # z.sleep(2) # d(description='完成').click() # # z.sleep(10) # z.heartbeat() # if codeImgObj.exists: # continue # else: # break # z.sleep(3) # if d(textContains='验证码').exists: # return True # else: # return False def login(self, d, args, z, numbers): QQNumber = numbers[0]['number'] # 即将登陆的QQ号 QQPassword = numbers[0]['password'] z.heartbeat() d.server.adb.cmd("shell", "pm clear com.tencent.mobileqqi").communicate() # 清除缓存 d.server.adb.cmd("shell", "am start -n com.tencent.mobileqqi/com.tencent.mobileqq.activity.SplashActivity").communicate() # 拉起来 z.sleep(5) while d(textContains='正在更新数据').exists: z.sleep(2) z.sleep(15) z.heartbeat() d.dump(compressed=False) d(className='android.widget.EditText', index=0).click() # 1918697054----xiake1234. QQNumber z.input(QQNumber) z.sleep(1) d(resourceId='com.tencent.mobileqqi:id/password').click() # Bn2kJq5l QQPassword z.input(QQPassword) print('QQ号:%s,QQ密码:%s' % (QQNumber, QQPassword)) z.sleep(1) d.dump(compressed=False) d(resourceId='com.tencent.mobileqqi:id/login').click() # 点击登陆按钮 z.sleep(2) flag = 0 while not d(text='输入验证码').exists and flag < 3: flag += 1 z.sleep(10) z.heartbeat() not_detection_robot = d(resourceId='com.tencent.mobileqqi:id/0', className="android.widget.EditText") if not_detection_robot.exists: if self.playCode(not_detection_robot): return False z.sleep(5) z.heartbeat() loginStatusList = z.qq_getLoginStatus(d) if loginStatusList is None: if d(resourceId='com.tencent.mobileqqi:id/0').exists and d(description='建讨论组').exists: loginStatusList = {'success': True} elif d(textContains="请在小米神隐模式中将TIM设置为“无限制”。").exists: z.toast(u"我是小米神隐") d(text='我知道了').click() else: loginStatusList = {'success': False} loginStatus = loginStatusList['success'] if loginStatus: z.toast("QQ登陆成功,模块结束运行") return True else: if d(text='去安全中心').exists: self.repo.BackupInfo(args["repo_cate_id"], 'frozen', QQNumber, '', '') # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber else: self.repo.BackupInfo(args["repo_cate_id"], 'normal', QQNumber, '', '') z.toast(u"QQ登陆失败,模块重新运行。") return False # if d(text='马上绑定').exists: # self.BindAddressBook(z, d, args) def qiehuan(self , d, z, args): time_limit = int(args['time_limit']) serial = d.server.adb.device_serial() self.slot = Slot(serial, self.type) slotObj = self.slot.getAvailableSlot(time_limit) # 没有空卡槽,取2小时没用过的卡槽 slotnum = None if not slotObj is None: slotnum = slotObj['id'] while slotObj is None: # 2小时没用过的卡槽也为没有的情况 d.server.adb.cmd("shell", "am broadcast -a com.zunyun.zime.toast --es msg \"QQ卡槽全满,无间隔时间段未用\"").communicate() z.heartbeat() z.sleep(30) slotObj = self.slot.getAvailableSlot(time_limit) if not slotObj is None: slotnum = slotObj['id'] break z.heartbeat() d.server.adb.cmd("shell", "pm clear com.tencent.mobileqqi").communicate() # 清除缓存 # d.server.adb.cmd("shell", "settings put global airplane_mode_on 1").communicate() # 开飞行模式 # d.server.adb.cmd("shell", # "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true").communicate() # d.server.adb.cmd("shell", "settings put global airplane_mode_on 0").communicate() # 关飞行模式 # d.server.adb.cmd("shell", # "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false").communicate() z.heartbeat() while True: ping = d.server.adb.cmd("shell", "ping -c 3 baidu.com").communicate() print(ping) if 'icmp_seq' and 'bytes from' and 'time' in ping[0]: break z.sleep(2) obj = self.slot.getSlotInfo(slotnum) remark = obj['remark'] remarkArr = remark.split("_") cateId = "" if len(remarkArr) == 3: slotInfo = d.server.adb.device_serial() + '_' + self.type + '_' + slotnum cateId = remarkArr[2] numbers = self.repo.Getserial(cateId, slotInfo) if len(numbers) != 0: featureCodeInfo = numbers[0]['imei'] z.set_serial("com.tencent.mobileqqi", featureCodeInfo) self.slot.restore(slotnum) # 有time_limit分钟没用过的卡槽情况,切换卡槽 z.sleep(2) d.server.adb.cmd("shell", "am broadcast -a com.zunyun.zime.toast --es msg \"卡槽成功切换为" + slotnum + "号\"").communicate() z.sleep(2) d.server.adb.cmd("shell", "am start -n com.tencent.mobileqqi/com.tencent.mobileqq.activity.SplashActivity").communicate() # 拉起来 z.sleep(5) while d(textContains='正在更新数据').exists: z.sleep(2) z.sleep(15) z.heartbeat() loginStatusList = z.qq_getLoginStatus(d) if loginStatusList is None: if d(resourceId='com.tencent.mobileqqi:id/0').exists and d(description='建讨论组').exists: loginStatusList = {'success': True} elif d(textContains="请在小米神隐模式中将TIM设置为“无限制”。").exists: z.toast(u"我是小米神隐") d(text='我知道了').click() loginStatusList = {'success': True} else: z.toast("登陆新场景,现无法判断登陆状态") loginStatusList = {'success': False} loginStatus = loginStatusList['success'] if loginStatus: z.toast(u"卡槽QQ状态正常,继续执行") return True else: QQnumber = remarkArr[1] if d(text='去安全中心').exists: self.repo.BackupInfo(cateId, 'frozen', QQnumber, '', '') # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber else: self.repo.BackupInfo(cateId, 'normal', QQnumber, '', '') self.slot.clear(slotnum) # 清空改卡槽,并补登 z.toast(u"卡槽QQ状态异常,补登陆卡槽") return False def action(self, d, z, args): while True: z.toast("正在ping网络是否通畅") i = 0 # while i < 200: # i += 1 # ping = d.server.adb.cmd("shell", "ping -c 3 baidu.com").communicate() # print(ping) # if 'icmp_seq' and 'bytes from' and 'time' in ping[0]: # z.toast(u"网络通畅。开始执行:国际版QQ登录 有卡槽") # break # z.sleep(2) # if i > 200 : # z.toast(u"网络不通,请检查网络状态") # if (args["time_delay"]): # z.sleep(int(args["time_delay"])) # return # # z.heartbeat() # z.generate_serial("com.tencent.mobileqqi") # 随机生成手机特征码 cate_id = args["repo_cate_id"] time_limit1 = args['time_limit1'] numbers = self.repo.GetAccount(cate_id, time_limit1, 1) if len(numbers) == 0: d.server.adb.cmd("shell", "am broadcast -a com.zunyun.zime.toast --es msg \"QQ帐号库%s号仓库无%s分钟未用,开始切换卡槽\"" % (cate_id, time_limit1)).communicate() serial = d.server.adb.device_serial() self.slot = Slot(serial, self.type) slotnum = self.slot.getEmpty() # 取空卡槽 if slotnum == 0 or len(numbers) == 0: #没有空卡槽的话 if self.qiehuan(d, z, args): break else: # 有空卡槽的情况 # d.server.adb.cmd("shell", "settings put global airplane_mode_on 1").communicate() # d.server.adb.cmd("shell", "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true").communicate() # z.sleep(6) # d.server.adb.cmd("shell", "settings put global airplane_mode_on 0").communicate() # d.server.adb.cmd("shell", "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false").communicate() z.heartbeat() while True: ping = d.server.adb.cmd("shell", "ping -c 3 baidu.com").communicate() print(ping) if 'icmp_seq'and 'bytes from'and'time' in ping[0]: break z.sleep(2) z.heartbeat() if self.login(d, args, z, numbers): z.heartbeat() featureCodeInfo = z.get_serial("com.tencent.mobileqq") self.slot.backup(slotnum, str(slotnum) + '_' + numbers[0]['number'] + '_' + cate_id) # 设备信息,卡槽号,QQ号 self.repo.BackupInfo(cate_id, 'using', numbers[0]['number'], featureCodeInfo, '%s_%s_%s' % (d.server.adb.device_serial(), self.type, slotnum)) # 仓库号,使用中,QQ号,设备号_卡槽号 break if args["time_delay"]: z.sleep(int(args["time_delay"]))
class TIMLoginSlot: def __init__(self): self.repo = Repo() self.type = 'tim' def GetUnique(self): nowTime = datetime.datetime.now().strftime("%Y%m%d%H%M%S"); # 生成当前时间 randomNum = random.randint(0, 1000); # 生成的随机整数n,其中0<=n<=100 if randomNum <= 10: randomNum = str(00) + str(randomNum); uniqueNum = str(nowTime) + str(randomNum); return uniqueNum def WebViewBlankPages(self, d): z.toast( "判断是否是空白页" ) Str = d.info # 获取屏幕大小等信息 height = float( Str["displayHeight"] ) width = float( Str["displayWidth"] ) W_H = width / height screenScale = round( W_H, 2 ) base_dir = os.path.abspath( os.path.join( os.path.dirname( __file__ ), os.path.pardir, "tmp" ) ) if not os.path.isdir( base_dir ): os.mkdir( base_dir ) sourcePng = os.path.join( base_dir, "%s_s.png" % (self.GetUnique( )) ) if screenScale == 0.56: left = 60 # 验证码的位置信息 top = 655 right = 290 bottom = 680 if screenScale == 0.61: left = 60 # 验证码的位置信息 top = 490 right = 210 bottom = 510 left = width * 7 / 135 # 验证码的位置信息 top = height * 245 / 444 right = width * 51 / 54 bottom = height * 275 / 444 d.screenshot( sourcePng ) # 截取整个输入验证码时的屏幕 img = Image.open( sourcePng ) box = (left, top, right, bottom) # left top right bottom region = img.crop( box ) # 截取验证码的图片 # show(region) #展示资料卡上的信息 image = region.convert( 'RGBA' ) # 生成缩略图,减少计算量,减小cpu压力 image.thumbnail( (200, 200) ) max_score = None dominant_color = None for count, (r, g, b, a) in image.getcolors( image.size[0] * image.size[1] ): # 跳过纯黑色 if a == 0: continue saturation = colorsys.rgb_to_hsv( r / 255.0, g / 255.0, b / 255.0 )[1] y = min( abs( r * 2104 + g * 4130 + b * 802 + 4096 + 131072 ) >> 13, 235 ) y = (y - 16.0) / (235 - 16) # 忽略高亮色 if y > 0.9: continue score = (saturation + 0.1) * count if score > max_score: max_score = score dominant_color = (r, g, b) # 红绿蓝 return dominant_color def WebViewPlayCode(self, d, z): z.toast( "开始截图打码" ) Str = d.info # 获取屏幕大小等信息 height = float( Str["displayHeight"] ) width = float( Str["displayWidth"] ) W_H = width / height screenScale = round( W_H, 2 ) base_dir = os.path.abspath( os.path.join( os.path.dirname( __file__ ), os.path.pardir, "tmp" ) ) if not os.path.isdir( base_dir ): os.mkdir( base_dir ) sourcePng = os.path.join( base_dir, "%s_s.png" % (self.GetUnique( )) ) icode = imageCode( ) im_id = "" for i in range( 0, 1 ): # 打码循环 if i > 0: icode.reportError( im_id ) d.screenshot( sourcePng ) # 截取整个输入验证码时的屏幕 if screenScale == 0.61: p = {"x1": 30 / width, "y1": 283 / height, "x2": 271 / width, "y2": 379 / height} if screenScale == 0.56: p = {"x1": 40 / width, "y1": 375 / height, "x2": 362 / width, "y2": 505 / height} cropedImg = z.img_crop( sourcePng, p ) im = open( cropedImg, 'rb' ) codeResult = icode.getCode( im, icode.CODE_TYPE_4_NUMBER_CHAR, 60 ) code = codeResult["Result"] im_id = codeResult["Id"] os.remove( sourcePng ) z.heartbeat( ) z.sleep( 5 ) d.click( width * 300 / 540, height * 330 / 888 ) self.input( z, height, code ) z.sleep( 2 ) d.click( width * 270 / 540, height * 525 / 888 ) while d( className='android.widget.ProgressBar', index=0 ).exists: # 网速不给力时,点击完成后仍然在加载时的状态 z.sleep( 2 ) z.sleep( 8 ) z.toast( "机器人打码--" ) if not d( textContains='验证码' ).exists: z.toast( "机器人打码跳出--" ) break def LoginPlayCode(self, d, z): self.scode = smsCode( d.server.adb.device_serial( ) ) base_dir = os.path.abspath( os.path.join( os.path.dirname( __file__ ), os.path.pardir, "tmp" ) ) if not os.path.isdir( base_dir ): os.mkdir( base_dir ) sourcePng = os.path.join( base_dir, "%s_s.png" % (self.GetUnique( )) ) codePng = os.path.join( base_dir, "%s_c.png" % (self.GetUnique( )) ) detection_robot = d( index='3', className="android.widget.EditText" ) not_detection_robot = d( resourceId='com.tencent.tim:id/name', index='2', className="android.widget.EditText" ) if detection_robot.exists or not_detection_robot.exists: # 需要验证码的情况 icode = imageCode( ) im_id = "" for i in range( 0, 4 ): # 打码循环 # if i > 0: # icode.reportError( im_id ) obj = d( resourceId='com.tencent.tim:id/name', className='android.widget.ImageView' ) # 当弹出选择QQ框的时候,定位不到验证码图片 if not obj.exists: obj = d( index='2', className='android.widget.Image' ) obj = obj.info obj = obj['bounds'] # 验证码处的信息 left = obj["left"] # 验证码的位置信息 top = obj['top'] right = obj['right'] bottom = obj['bottom'] d.screenshot( sourcePng ) # 截取整个输入验证码时的屏幕 img = Image.open( sourcePng ) box = (left, top, right, bottom) # left top right bottom region = img.crop( box ) # 截取验证码的图片 img = Image.new( 'RGBA', (right - left, bottom - top) ) img.paste( region, (0, 0) ) img.save( codePng ) with open( codePng, 'rb' ) as f: # file = f.read() file = "data:image/jpeg;base64," + base64.b64encode( f.read( ) ) da = {"IMAGES": file} path = "/ocr.index" headers = {"Content-Type": "application/x-www-form-urlencoded", "Connection": "Keep-Alive"} conn = httplib.HTTPConnection( "162626i1w0.51mypc.cn", 10082, timeout=30 ) params = urllib.urlencode( da ) conn.request( method="POST", url=path, body=params, headers=headers ) response = conn.getresponse( ) if response.status == 200: code = response.read( ) else: continue os.remove( sourcePng ) os.remove( codePng ) z.heartbeat( ) z.sleep( 5 ) if not_detection_robot.exists: d( resourceId='com.tencent.tim:id/name', index='2', className="android.widget.EditText" ).set_text( code ) else: detection_robot.set_text( code ) z.sleep( 3 ) if d( descriptionContains='验证', className='android.view.View' ).exists: d( descriptionContains='验证', className='android.view.View' ).click( ) else: d( text='完成', resourceId='com.tencent.tim:id/ivTitleBtnRightText' ).click( ) z.sleep( 5 ) z.heartbeat( ) while d( className='android.widget.ProgressBar', index=0 ).exists: # 网速不给力时,点击完成后仍然在加载时的状态 z.sleep( 2 ) z.heartbeat( ) if detection_robot.exists or not_detection_robot.exists: continue else: break z.sleep( 5 ) if d( textContains='验证码' ).exists: return "no" else: return "yes" else: return "no" def login(self,d,args,z): z.heartbeat() Str = d.info # 获取屏幕大小等信息 height = float( Str["displayHeight"] ) width = float( Str["displayWidth"] ) cate_id = args["repo_cate_id"] time_limit1 = args['time_limit1'] numbers = self.repo.GetAccount( cate_id, time_limit1, 1 ) while len( numbers ) == 0: z.heartbeat( ) d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"QQ帐号库%s号仓库无%s分钟未用,开始切换卡槽\"" % ( cate_id, time_limit1) ).communicate( ) z.sleep( 2 ) return 0 QQNumber = numbers[0]['number'] # 即将登陆的QQ号 QQPassword = numbers[0]['password'] z.sleep( 1 ) z.heartbeat( ) d.server.adb.cmd("shell", "pm clear com.tencent.tim").communicate( ) # 清除缓存 # d.server.adb.cmd("shell", # "am start -n com.tencent.tim/com.tencent.mobileqq.activity.SplashActivity" ).communicate( ) # 拉起来 z.server.adb.run_cmd( "shell", "am start -n com.tencent.tim/com.tencent.mobileqq.activity.SplashActivity" ) z.sleep(10) while d( textContains='正在更新数据' ).exists: z.sleep( 2 ) z.sleep(10) z.heartbeat() z.server.adb.run_cmd( "shell", "am start -n com.tencent.tim/com.tencent.mobileqq.activity.SplashActivity" ) z.sleep( 5 ) z.heartbeat( ) if d(className='android.widget.ImageView',resourceId='com.tencent.tim:id/title',index=1).exists: for i in range(0,2): d.swipe( width - 20, height / 2, 0, height / 2, 5 ) z.sleep(1.5) if d(text='立即体验').exists: d(text='立即体验').click() z.sleep(2) if d(text='登 录').exists: d(text='登 录').click() else: d( text='QQ号登录' ).click( ) z.sleep( 1 ) # d(className='android.widget.EditText', index=0).set_text(QQNumber) # 1918697054----xiake1234. QQNumber d(className='android.widget.EditText', index=0).click() # 1918697054----xiake1234. QQNumber self.input( z, height, QQNumber ) z.sleep( 1 ) # d(resourceId='com.tencent.mobileqq:id/password').set_text(QQPassword) # Bn2kJq5l QQPassword d(resourceId='com.tencent.tim:id/password').click() # Bn2kJq5l QQPassword self.input( z, height, QQPassword ) z.heartbeat() logger = util.logger print('QQ号:%s,QQ密码:%s' % (QQNumber, QQPassword)) d.dump(compressed=False ) d( text='登 录', resourceId='com.tencent.tim:id/login' ).click( ) z.sleep(1) while d(text='登录中').exists: z.sleep(2) z.sleep(int(args['time_delay1'])) z.heartbeat() detection_robot = d( index='3', className="android.widget.EditText" ) not_detection_robot = d( resourceId='com.tencent.tim:id/name', index='2', className="android.widget.EditText" ) playCodeResult = '' if detection_robot.exists or not_detection_robot.exists: playCodeResult = self.LoginPlayCode( d, z ) # 打验证码 else: if self.WebViewBlankPages( d )[2] > 200: z.toast( "不是空白页" ) self.WebViewPlayCode( d, z ) else: z.toast( "是空白页" ) return "nothing" if playCodeResult == "no": return "nothing" z.sleep(10) z.heartbeat() if d( text='马上绑定' ).exists: return QQNumber if d(textContains="请在小米神隐模式中将TIM设置为“无限制”。").exists: z.toast("我是小米神隐") return QQNumber if d( text='匹配手机通讯录' ).exists: # 登陆上后弹出t通讯录的情况 d( text='匹配手机通讯录' ).click() z.sleep(1.5) if d(text='取消').exists: d(text='取消').child() return QQNumber if d(text='消息').exists and d(description='快捷入口').exists: z.toast("卡槽QQ状态正常,继续执行") return QQNumber if d( text='去安全中心' ).exists: self.repo.BackupInfo( cate_id, 'frozen', QQNumber, '', '' ) # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber z.toast( "登陆失败,重新登陆" ) return "nothing" elif d(resourceId="com.tencent.tim:id/login",description="登录").exists: failCount = int(args["failCount"]) for r in range(failCount): result = self.againLogin(d,z) if result is True: return QQNumber elif result is False: self.repo.BackupInfo( cate_id, 'frozen', QQNumber, '', '' ) # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber return "nothing" elif result is None: return "nothing" else: self.repo.BackupInfo( cate_id, 'normal', QQNumber, '', '' ) # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber z.toast( "登陆失败,重新登陆" ) return "nothing" def qiehuan(self, d, z, args): Str = d.info # 获取屏幕大小等信息 height = float( Str["displayHeight"] ) width = float( Str["displayWidth"] ) time_limit = int(args['time_limit']) cate_id = args["repo_cate_id"] serial = d.server.adb.device_serial( ) self.slot = Slot( serial, self.type ) slotObj = self.slot.getAvailableSlot(time_limit) # 没有空卡槽,取2小时没用过的卡槽 while slotObj is None: # 2小时没有用过的卡槽也为空的情况 d.server.adb.cmd("shell", "am broadcast -a com.zunyun.zime.toast --es msg \"QQ卡槽全满,无间隔时间段未用\"").communicate() z.heartbeat() z.sleep(10) slotObj = self.slot.getAvailableSlot( time_limit ) # 没有空卡槽,取2小时没用过的卡槽 if not slotObj is None: slotnum = slotObj['id'] z.heartbeat() d.server.adb.cmd("shell", "pm clear com.tencent.tim").communicate() # 清除缓存 # d.server.adb.cmd("shell", "settings put global airplane_mode_on 1").communicate() # d.server.adb.cmd("shell", "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true").communicate() # z.sleep(6) # z.heartbeat() # d.server.adb.cmd("shell", "settings put global airplane_mode_on 0").communicate() # d.server.adb.cmd("shell", "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false").communicate() z.heartbeat() z.toast( "正在ping网络是否通畅" ) while True: ping = d.server.adb.cmd("shell", "ping -c 3 baidu.com").communicate() print(ping) if 'icmp_seq' and 'bytes from' and 'time' in ping[0]: break z.sleep(2) obj = self.slot.getSlotInfo( slotnum ) remark = obj['remark'] remarkArr = remark.split( "_" ) if len( remarkArr ) == 3: slotInfo = d.server.adb.device_serial( ) + '_' + self.type + '_' + slotnum cateId = remarkArr[2] numbers = self.repo.Getserial( cateId, slotInfo ) if len( numbers ) != 0: featureCodeInfo = numbers[0]['imei'] z.set_serial( "com.tencent.tim", featureCodeInfo ) self.slot.restore( slotnum ) # 有time_limit分钟没用过的卡槽情况,切换卡槽 d.server.adb.cmd("shell", "am broadcast -a com.zunyun.zime.toast --es msg \"卡槽成功切换为" + str(slotnum) + "号\"").communicate() z.sleep(2) # d.server.adb.cmd("shell", "am start -n com.tencent.tim/com.tencent.mobileqq.activity.SplashActivity").communicate() # 拉起来 z.server.adb.run_cmd( "shell", "am start -n com.tencent.tim/com.tencent.mobileqq.activity.SplashActivity" ) z.sleep( 5 ) while d( textContains='正在更新数据' ).exists: z.sleep( 2 ) z.sleep( 3 ) z.server.adb.run_cmd( "shell", "am start -n com.tencent.tim/com.tencent.mobileqq.activity.SplashActivity" ) z.sleep(3) z.heartbeat() if d(className='android.widget.ImageView',resourceId='com.tencent.tim:id/title',index=1).exists: for i in range(0,2): d.swipe( width - 20, height / 2, 0, height / 2, 5 ) z.sleep(1.5) if d(text='立即体验').exists: d(text='立即体验').click() z.sleep(3) if d( textContains="请在小米神隐模式中将TIM设置为“无限制”。" ).exists: z.toast( "我是小米神隐" ) d( text='我知道了' ).click( ) d( text='我知道了' ).click( ) elif d( text='消息' ).exists or d( text='马上绑定' ).exists or d( text='匹配手机通讯录' ).exists: if d( text='匹配手机通讯录' ).exists: # 登陆上后弹出t通讯录的情况 d( text='匹配手机通讯录' ).click( ) z.sleep( 1.5 ) if d( text='取消' ).exists: d( text='取消' ).child( ) z.toast( "卡槽QQ切换成功,继续执行" ) else: obj = self.slot.getSlotInfo( slotnum ) remark = obj['remark'] remarkArr = remark.split( "_" ) QQnumber = remarkArr[1] if d( text='去安全中心' ).exists: self.repo.BackupInfo( cate_id, 'frozen', QQnumber, '', '' ) # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber else: self.repo.BackupInfo( cate_id, 'normal', QQnumber, '', '' ) self.slot.clear( slotnum ) # 清空改卡槽,并补登 z.toast( "卡槽QQ状态异常,补登陆卡槽" ) self.action( d, z, args ) def againLogin(self, d , z): if d(resourceId="com.tencent.tim:id/login",description="登录").exists: d( resourceId="com.tencent.tim:id/login", description="登录" ).click() z.sleep( 1 ) while d( text='登录中' ).exists: z.sleep( 2 ) z.sleep( int( args['time_delay1'] ) ) z.heartbeat( ) detection_robot = d( index='3', className="android.widget.EditText" ) not_detection_robot = d( resourceId='com.tencent.tim:id/name', index='2', className="android.widget.EditText" ) playCodeResult = '' if detection_robot.exists or not_detection_robot.exists: playCodeResult = self.LoginPlayCode( d, z ) # 打验证码 else: if self.WebViewBlankPages( d )[2] > 200: z.toast( "不是空白页" ) self.WebViewPlayCode( d, z ) else: z.toast( "是空白页" ) return "nothing" if playCodeResult == "no": return "nothing" z.sleep( 10 ) z.heartbeat( ) if d( text='马上绑定' ).exists: return True if d( textContains="请在小米神隐模式中将TIM设置为“无限制”。" ).exists: z.toast( "我是小米神隐" ) return True if d( text='匹配手机通讯录' ).exists: # 登陆上后弹出t通讯录的情况 d( text='匹配手机通讯录' ).click( ) z.sleep( 1.5 ) if d( text='取消' ).exists: d( text='取消' ).child( ) return True if d( text='消息' ).exists and d( description='快捷入口' ).exists: z.toast( "卡槽QQ状态正常,继续执行" ) return True if d( text='去安全中心' ).exists: # self.repo.BackupInfo( cate_id, 'frozen', QQNumber, '', '' ) # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber z.toast( "登陆失败,重新登陆" ) return False if d( resourceId="com.tencent.tim:id/login", description="登录" ).exists: return "nothing" else: # self.repo.BackupInfo( cate_id, 'normal', QQNumber, '', '' ) # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber z.toast( "登陆失败,重新登陆" ) return def input(self, z, height, text): if height>888: z.input(text) else: z.cmd( "shell", "am broadcast -a ZY_INPUT_TEXT --es text \\\"%s\\\"" % text ) def action(self,d,z,args): Str = d.info # 获取屏幕大小等信息 height = float( Str["displayHeight"] ) width = float( Str["displayWidth"] ) z.generate_serial("com.tencent.tim") # 随机生成手机特征码 z.toast("随机生成手机特征码") time_limit = int(args['time_limit']) cate_id = args["repo_cate_id"] serial = d.server.adb.device_serial() self.slot = Slot(serial, self.type) slotnum = self.slot.getEmpty() # 取空卡槽 if slotnum == 0: # 没有空卡槽的话 slotObj = self.slot.getAvailableSlot(time_limit) # 取空卡槽,取2小时没用过的卡槽 if not slotObj is None: slotnum = slotObj['id'] print(slotnum) while slotObj is None: # 2小时没用过的卡槽也为没有的情况 d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"QQ卡槽全满,无间隔时间段未用\"" ).communicate( ) z.heartbeat() z.sleep(10) slotObj = self.slot.getAvailableSlot(time_limit) if not slotObj is None: slotnum = slotObj['id'] z.heartbeat() d.server.adb.cmd( "shell", "pm clear com.tencent.tim" ).communicate( ) # 清除缓存 # d.server.adb.cmd( "shell", "am force-stop com.tencent.tim" ).communicate( ) # 强制停止 # d.server.adb.cmd("shell", "settings put global airplane_mode_on 1").communicate() #开数据流量 # d.server.adb.cmd("shell","am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true").communicate()#开飞行模式 # z.sleep( 6 ) # z.heartbeat( ) # d.server.adb.cmd("shell", "settings put global airplane_mode_on 0").communicate() # 关数据流量 # d.server.adb.cmd("shell", "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false").communicate()#开飞行模式 # z.heartbeat( ) # z.toast( "正在ping网络是否通畅" ) # while True: # ping = d.server.adb.cmd( "shell", "ping -c 3 baidu.com" ).communicate( ) # print( ping ) # if 'icmp_seq' and 'bytes from' and 'time' in ping[0]: # break # z.sleep( 2 ) obj = self.slot.getSlotInfo( slotnum ) remark = obj['remark'] remarkArr = remark.split( "_" ) if len( remarkArr ) == 3: slotInfo = d.server.adb.device_serial() + '_' + self.type + '_' + slotnum cateId = remarkArr[2] numbers = self.repo.Getserial( cateId, slotInfo) if len(numbers) != 0: featureCodeInfo = numbers[0]['imei'] z.set_serial( "com.tencent.tim", featureCodeInfo ) self.slot.restore( slotnum ) # 有time_limit分钟没用过的卡槽情况,切换卡槽 d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"卡槽成功切换为" + slotnum + "号\"" ).communicate( ) z.sleep( 2 ) # d.server.adb.cmd( "shell", # "am start -n com.tencent.tim/com.tencent.mobileqq.activity.SplashActivity" ).communicate( ) # 拉起来 z.server.adb.run_cmd( "shell", "am start -n com.tencent.tim/com.tencent.mobileqq.activity.SplashActivity" ) z.sleep(5) while d( textContains='正在更新数据' ).exists: z.sleep( 2 ) z.sleep( 3 ) z.server.adb.run_cmd( "shell", "am start -n com.tencent.tim/com.tencent.mobileqq.activity.SplashActivity" ) z.sleep( 3 ) if d( className='android.widget.ImageView', resourceId='com.tencent.tim:id/title', index=1 ).exists: for i in range( 0, 2 ): d.swipe( width - 20, height / 2, 0, height / 2, 5 ) z.sleep( 1.5 ) if d( text='立即体验' ).exists: d( text='立即体验' ).click( ) z.sleep( 2 ) z.heartbeat() if d( textContains="请在小米神隐模式中将TIM设置为“无限制”。" ).exists: z.toast( "我是小米神隐" ) d( text='我知道了' ).click( ) elif d( text='消息' ).exists or d( text='马上绑定' ).exists or d( text='匹配手机通讯录' ).exists: if d( text='匹配手机通讯录' ).exists: # 登陆上后弹出t通讯录的情况 d( text='匹配手机通讯录' ).click( ) z.sleep( 1.5 ) if d( text='取消' ).exists: d( text='取消' ).child( ) z.toast("卡槽QQ切换成功,继续执行") else: obj = self.slot.getSlotInfo( slotnum ) remark = obj['remark'] remarkArr = remark.split( "_" ) QQnumber = remarkArr[1] if d(text='去安全中心').exists: self.repo.BackupInfo(cate_id, 'frozen', QQnumber, '', '') # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber else: self.repo.BackupInfo(cate_id, 'normal', QQnumber, '', '') self.slot.clear( slotnum ) # 清空改卡槽,并补登 z.toast("卡槽QQ状态异常,补登陆卡槽") self.action( d, z, args ) else: # 有空卡槽的情况 d.server.adb.cmd( "shell", "pm clear com.tencent.tim" ).communicate( ) # 清除缓存 # d.server.adb.cmd("shell", "settings put global airplane_mode_on 1").communicate() # d.server.adb.cmd("shell", "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true").communicate() # z.sleep(3) # d.server.adb.cmd("shell", "settings put global airplane_mode_on 0").communicate() # d.server.adb.cmd("shell", "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false").communicate() z.heartbeat( ) # z.toast( "正在ping网络是否通畅" ) # while True: # ping = d.server.adb.cmd( "shell", "ping -c 3 baidu.com" ).communicate( ) # print( ping ) # if 'icmp_seq' and 'bytes from' and 'time' in ping[0]: # break # z.sleep( 2 ) serialinfo = d.server.adb.device_serial( ) # print('登陆时的serial%s'%serialinfo) z.heartbeat( ) QQnumber = self.login( d, args, z ) if QQnumber == 'nothing': self.slot.clear( slotnum ) # 清空改卡槽,并补登 self.action( d, z, args ) elif QQnumber == 0: z.toast( "仓库为空,无法登陆。开始切换卡槽" ) self.qiehuan( d, z, args ) elif QQnumber is None: return else: z.heartbeat() z.toast("登陆成功") featureCodeInfo = z.get_serial("com.tencent.tim") self.slot.backup( slotnum, str( slotnum ) + '_' + QQnumber + '_' + cate_id) # 设备信息,卡槽号,QQ号 self.repo.BackupInfo( cate_id, 'using', QQnumber, featureCodeInfo, '%s_%s_%s' % ( d.server.adb.device_serial( ), self.type, slotnum) ) # 仓库号,使用中,QQ号,设备号_卡槽号 if (args["time_delay"]): time.sleep(int(args["time_delay"]))
class QQMailLogin: def __init__(self): self.repo = Repo() self.type = 'qqmail' def GetUnique(self): nowTime = datetime.datetime.now().strftime("%Y%m%d%H%M%S") # 生成当前时间 randomNum = random.randint(0, 1000) # 生成的随机整数n,其中0<=n<=100 if randomNum <= 10: randomNum = str(00) + str(randomNum) uniqueNum = str(nowTime) + str(randomNum) return uniqueNum def input(self, z, text): z.cmd("shell", "am broadcast -a ZY_INPUT_TEXT --es text \\\"%s\\\"" % text) def palyCode(self, d, z, picObj): self.scode = smsCode(d.server.adb.device_serial()) base_dir = os.path.abspath( os.path.join(os.path.dirname(__file__), os.path.pardir, "tmp")) if not os.path.isdir(base_dir): os.mkdir(base_dir) sourcePng = os.path.join(base_dir, "%s_s.png" % (self.GetUnique())) codePng = os.path.join(base_dir, "%s_c.png" % (self.GetUnique())) icode = imageCode() im_id = "" code = "" for i in range(0, 2): # 打码循环 if i > 0: icode.reportError(im_id) obj = picObj.info obj = obj['bounds'] # 验证码处的信息 left = obj["left"] # 验证码的位置信息 top = obj['top'] right = obj['right'] bottom = obj['bottom'] d.screenshot(sourcePng) # 截取整个输入验证码时的屏幕 img = Image.open(sourcePng) box = (left, top, right, bottom) # left top right bottom region = img.crop(box) # 截取验证码的图片 img = Image.new('RGBA', (right - left, bottom - top)) img.paste(region, (0, 0)) img.save(codePng) im = open(codePng, 'rb') codeResult = icode.getCode(im, icode.CODE_TYPE_4_NUMBER_CHAR, 60) code = codeResult["Result"] im_id = codeResult["Id"] os.remove(sourcePng) os.remove(codePng) z.heartbeat() if code.isalpha() or code.isisdigitv() or code.isalnum(): break else: continue return code def login(self, d, z, args, accounts): try: d.server.adb.cmd( "shell", "pm clear com.tencent.androidqqmail").communicate() # 清除QQ邮箱缓存 d.server.adb.cmd( "shell", "am start -n com.tencent.androidqqmail/com.tencent.qqmail.LaunchComposeMail" ).communicate() # 拉起QQ邮箱 z.sleep(8) z.heartbeat() if args['mail_type'] == '163邮箱登录': if d(resourceId='com.tencent.androidqqmail:id/ee' ).exists: # 选择163邮箱点击进入登陆页面 d(resourceId='com.tencent.androidqqmail:id/ee').click() z.sleep(1) if args['mail_type'] == 'QQ邮箱登录': if d(resourceId='com.tencent.androidqqmail:id/ea' ).exists: # 选择QQ邮箱点击进入登陆页面 d(resourceId='com.tencent.androidqqmail:id/ea').click() z.sleep(1) if args['mail_type'] == '腾讯企业邮箱登录': if d(resourceId='com.tencent.androidqqmail:id/eb' ).exists: # 选择腾讯企业邮箱登录点击进入登陆页面 d(resourceId='com.tencent.androidqqmail:id/eb').click() z.sleep(1) account = accounts[0]['number'] password = accounts[0]['password'] if d(text='帐号密码登录').exists: d(text='帐号密码登录').click() if d(resourceId='com.tencent.androidqqmail:id/bi' ).exists: # 输入邮箱帐号 d(resourceId='com.tencent.androidqqmail:id/bi').click() # self.input(z,account) self.input(z, account) if d(resourceId='com.tencent.androidqqmail:id/bs' ).exists: # 输入邮箱密码 d(resourceId='com.tencent.androidqqmail:id/bs').click() self.input(z, password) if d(resourceId='com.tencent.androidqqmail:id/a_' ).exists: # 点击登录按钮 d(resourceId='com.tencent.androidqqmail:id/a_').click() z.sleep(25) while True: if d(text="验证中"): time.sleep(3) else: break if args['mail_type'] == 'QQ邮箱登录': if d(resourceId='com.tencent.androidqqmail:id/h' ).exists: # 判断是否要填写独立密码 self.input(z, "Abc" + account) z.sleep(1) if d(text='确定').exists: d(text='确定').click() z.sleep(5) while d(resourceId='com.tencent.androidqqmail:id/a16' ).exists: # 出现验证码 picObj = d(resourceId='com.tencent.androidqqmail:id/a19', index=0) code = self.palyCode(d, z, picObj) if code == "": return False if d(resourceId='com.tencent.androidqqmail:id/a17').exists: d(resourceId='com.tencent.androidqqmail:id/a17').click( ) self.input(z, code) if d(resourceId='com.tencent.androidqqmail:id/a_' ).exists: # 点击登陆 d(resourceId='com.tencent.androidqqmail:id/a_').click() z.sleep(8) if d(resourceId='com.tencent.androidqqmail:id/h' ).exists: # 判断是否要填写独立密码 self.input(z, "Abc" + account) z.sleep(1) if d(text='确定').exists: d(text='确定').click() if args['mail_type'] == '163邮箱登录': if d(resourceId='com.tencent.androidqqmail:id/a_' ).exists: # 点击登录按钮 d(resourceId='com.tencent.androidqqmail:id/a_').click() z.sleep(3) z.heartbeat() d.server.adb.cmd("shell", "am force-stop com.tencent.androidqqmail" ).wait() # 强制停止163邮箱 d.server.adb.cmd( "shell", "am start -n com.tencent.androidqqmail/com.tencent.qqmail.LaunchComposeMail" ).communicate() # 拉起163邮箱 if args['mail_type'] == '腾讯企业邮箱登录': if d(resourceId='com.tencent.androidqqmail:id/a_' ).exists: # 点击登录按钮 d(resourceId='com.tencent.androidqqmail:id/a_').click() z.sleep(3) z.heartbeat() if d(text='收件箱').exists: z.toast(u"登录成功。退出模块") d.server.adb.cmd( "shell", "am force-stop com.tencent.androidqqmail" ).wait() # 强制停止 return True else: return False # d.server.adb.cmd("shell", "am force-stop com.tencent.androidqqmail").wait() # 强制停止163邮箱 # d.server.adb.cmd("shell", "am start -n com.tencent.androidqqmail/com.tencent.qqmail.LaunchComposeMail").communicate() # 拉起163邮箱 z.sleep(12) z.heartbeat() if d(textContains='你有多个应用同时收到').exists: d(text='确定').click() z.sleep(2) if d(text='收件箱').exists: z.toast(u"登录成功。退出模块") d.server.adb.cmd( "shell", "am force-stop com.tencent.androidqqmail").wait() # 强制停止 return True else: return False except: logging.exception("exception") z.toast(u"程序出现异常,模块退出") d.server.adb.cmd( "shell", "am force-stop com.tencent.androidqqmail").wait() # 强制停止 return False def qiehuan(self, d, z, args): if args['mail_type'] == '163邮箱登录': self.type = '163mail' time_limit = int(args['slot_time_limit']) serial = d.server.adb.device_serial() self.slot = Slot(serial, self.type) slotObj = self.slot.getAvailableSlot(time_limit) # 没有空卡槽,取2小时没用过的卡槽 slotnum = None if not slotObj is None: slotnum = slotObj['id'] while slotObj is None: # 2小时没用过的卡槽也为没有的情况 d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"QQ卡槽全满,无间隔时间段未用\"" ).communicate() z.heartbeat() z.sleep(30) slotObj = self.slot.getAvailableSlot(time_limit) if not slotObj is None: slotnum = slotObj['id'] break z.heartbeat() d.server.adb.cmd( "shell", "pm clear com.tencent.androidqqmail").communicate() # 清除缓存 obj = self.slot.getSlotInfo(slotnum) remark = obj['remark'] remarkArr = remark.split("_") cateId = args['repo_account_id'] if len(remarkArr) == 3: slotInfo = d.server.adb.device_serial( ) + '_' + self.type + '_' + slotnum cateId = remarkArr[2] numbers = self.repo.Getserial(cateId, slotInfo) if len(numbers) != 0: featureCodeInfo = numbers[0]['imei'] z.set_serial("com.tencent.androidqqmail", featureCodeInfo) self.slot.restore(slotnum) # 有time_limit分钟没用过的卡槽情况,切换卡槽 z.sleep(2) d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"卡槽成功切换为" + slotnum + "号\"").communicate() z.sleep(2) d.server.adb.cmd( "shell", "am start -n com.tencent.androidqqmail/com.tencent.qqmail.LaunchComposeMail" ).communicate() # 拉起QQ邮箱 z.sleep(5) while d(textContains='正在更新数据').exists: z.sleep(2) z.sleep(20) z.heartbeat() d.dump(compressed=False) if d(text='密码错误,请重新输入').exists or d(description='QQ邮箱').exists: QQnumber = remarkArr[1] self.repo.BackupInfo(cateId, 'normal', QQnumber, '', '') # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber self.slot.clear(slotnum) # 清空改卡槽,并补登 z.toast("卡槽邮箱号状态异常,补登陆卡槽") return False else: z.toast("邮箱登陆状态正常,切换完毕。") return True def action(self, d, z, args): while True: # z.toast("正在ping网络是否通畅") # i = 0 # while i < 200: # i += 1 # ping = d.server.adb.cmd("shell", "ping -c 3 baidu.com").communicate() # # print(ping) # if 'icmp_seq' and 'bytes from' and 'time' in ping[0]: # z.toast(u"网络通畅。开始执行:" + args['mail_type'] + u" 有卡槽") # break # z.sleep(2) # if i > 200: # z.toast(u"网络不通,请检查网络状态") # return z.heartbeat() z.generate_serial("com.tencent.androidqqmail") # 随机生成手机特征码 if args['mail_type'] == '163邮箱登录': self.type = '163mail' accounts = self.repo.GetAccount(args['repo_account_id'], int(args['account_time_limit']), 1) # 去仓库获取QQ邮箱帐号 if len(accounts) == 0: z.toast(u"帐号库为空") serial = d.server.adb.device_serial() self.slot = Slot(serial, self.type) slotnum = self.slot.getEmpty() # 取空卡槽 if slotnum == 0 or len( accounts) == 0: # 没有空卡槽的话或者仓库没有可登陆的帐号,进行卡槽切换。 if self.qiehuan(d, z, args): break else: continue else: # 有空卡槽的情况 QQnumber = accounts[0]['number'] # print QQnumber if self.login(d, z, args, accounts): z.heartbeat() featureCodeInfo = z.get_serial("com.tencent.androidqqmail") self.slot.backup(slotnum, str(slotnum) + '_' + QQnumber + '_' + args["repo_account_id"]) # 设备信息,卡槽号,QQ号 self.repo.BackupInfo( args["repo_account_id"], 'using', QQnumber, featureCodeInfo, '%s_%s_%s' % (d.server.adb.device_serial(), self.type, slotnum)) # 仓库号,使用中,QQ号,设备号_卡槽号 break else: self.slot.clear(slotnum) # 清空改卡槽,并补登 if d(text='本次登录存在异常,如需帮助请前往安全中心').exists: z.toast(u"登录失败。重新登录") self.repo.BackupInfo(args["repo_account_id"], 'frozen', QQnumber, '', '') # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber elif d(text='帐号或密码错误').exists: z.toast(u"帐号或密码错误") self.repo.BackupInfo(args["repo_account_id"], 'frozen', QQnumber, '', '') # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber else: self.repo.BackupInfo(args["repo_account_id"], 'normal', QQnumber, '', '') # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber continue
class QQSafetyCenter: def __init__(self): self.repo = Repo() self.type = 'token' def GetUnique(self): nowTime = datetime.datetime.now().strftime("%Y%m%d%H%M%S") # 生成当前时间 randomNum = random.randint(0, 1000) # 生成的随机整数n,其中0<=n<=100 if randomNum <= 10: randomNum = str(00) + str(randomNum) uniqueNum = str(nowTime) + str(randomNum) return uniqueNum def LoginPlayCode(self, d, z): self.scode = smsCode(d.server.adb.device_serial()) base_dir = os.path.abspath( os.path.join(os.path.dirname(__file__), os.path.pardir, "tmp")) if not os.path.isdir(base_dir): os.mkdir(base_dir) sourcePng = os.path.join(base_dir, "%s_s.png" % (self.GetUnique())) codePng = os.path.join(base_dir, "%s_c.png" % (self.GetUnique())) codeEditTextObj = d(resourceId='com.tencent.mobileqq:id/name', index='2', className="android.widget.EditText") if codeEditTextObj.exists: # 需要验证码的情况 icode = imageCode() im_id = "" for i in range(0, 4): # 打码循环 if i > 0: icode.reportError(im_id) obj = d(resourceId='com.tencent.mobileqq:id/name', className='android.widget.ImageView' ) # 当弹出选择QQ框的时候,定位不到验证码图片 obj = obj.info obj = obj['bounds'] # 验证码处的信息 left = obj["left"] # 验证码的位置信息 top = obj['top'] right = obj['right'] bottom = obj['bottom'] d.screenshot(sourcePng) # 截取整个输入验证码时的屏幕 img = Image.open(sourcePng) box = (left, top, right, bottom) # left top right bottom region = img.crop(box) # 截取验证码的图片 img = Image.new('RGBA', (right - left, bottom - top)) img.paste(region, (0, 0)) img.save(codePng) im = open(codePng, 'rb') codeResult = icode.getCode(im, icode.CODE_TYPE_4_NUMBER_CHAR, 60) code = codeResult["Result"] im_id = codeResult["Id"] os.remove(sourcePng) os.remove(codePng) return code def CaseOne(self, d, z, QQNumber, QQPassword): # 登录情况一:手机上有qq登录或提示历史登陆过的帐号直接登陆 if d(text='切换帐号').exists and d(text='添加帐号').exists: if d(resourceId='com.tencent.mobileqq:id/name', index=0).exists: obj = d(resourceId='com.tencent.mobileqq:id/name', index=0, className='android.widget.RelativeLayout').child( className='android.widget.LinearLayout', index=1).child( resourceId='com.tencent.mobileqq:id/name', index=0, className='android.widget.LinearLayout').child( resourceId='com.tencent.mobileqq:id/name', index=0, className='android.widget.RelativeLayout') Str = obj.info["bounds"] # 获取该控件大小等信息 height = int(Str["bottom"]) - int(Str["top"]) d.swipe( int(Str["right"]) - 10, int(Str["bottom"]) - height / 2, int(Str["left"]) + 10, int(Str["bottom"]) - height / 2, 5) z.sleep(1.5) if d(text='删除').exists: d(text='删除').click() z.sleep(1) d(text='添加帐号').click() d(resourceId='com.tencent.mobileqq:id/account').click() z.input(QQNumber) d(resourceId='com.tencent.mobileqq:id/password').click() z.input(QQPassword) if d(text='登 录').exists: d(text='登 录').click() z.sleep(5) if d(text='输入验证码').exists: code = self.LoginPlayCode(d, z) z.input(code) z.sleep(1) if d(text='完成').exists: d(text='完成').click() def CaseTwo(self, d, z, QQNumber, QQPassword): #登录情况二:手机上没有登陆qq也没有登录过安全中心 d(className='android.view.View', index=1).click() z.input(QQNumber) d(className='android.view.View', index=2).click() z.input(QQPassword) if d(description='登 录').exists: d(description='登 录').click() def Login(self, d, z, args): #登录方法 self.scode = smsCode(d.server.adb.device_serial()) d.server.adb.cmd("shell", "pm clear com.tencent.token").communicate() # 清除缓存 if d(text='QQ安全中心').exists: d(text='QQ安全中心').click() z.sleep(6) else: z.toast("请返回有QQ安全中心的主页面,再运行") d.server.adb.cmd( "shell", "pm clear com.tencent.token").communicate() # 清除缓存 return d.server.adb.cmd("shell", "am start -n com.tencent.token/.ui.LogoActivity" ).communicate() # 拉起来 z.sleep(6) if d(resourceId='com.tencent.token:id/account_bind_qqface').exists: d(resourceId='com.tencent.token:id/account_bind_qqface').click() z.sleep(1) if d(text='登录').exists: d(text='登录').click() z.sleep(0.5) if d(text='QQ登录').exists: d(text='QQ登录').click() z.sleep(1) cate_id = args["repo_cate_id"] time_limit = args['time_limit'] numbers = self.repo.GetAccount(cate_id, time_limit, 1) print(numbers) while len(numbers) == 0: z.heartbeat() d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"QQ帐号库%s号仓库无%s分钟未用,开始切换卡槽\"" % (cate_id, time_limit)).communicate() z.sleep(2) return "none" QQNumber = numbers[0]['number'] # 即将登陆的QQ号 QQPassword = numbers[0]['password'] # QQNumber = '3518608471' # QQPassword = '******' z.sleep(1) if d(text='切换帐号').exists: d(text='切换帐号').click() z.sleep(1) self.CaseOne(d, z, QQNumber, QQPassword) z.sleep(5) else: self.CaseTwo(d, z, QQNumber, QQPassword) z.sleep(5) if d(description='请向右拖动滑块完成拼图').exists: z.toast("遇到安全验证,重新开始") return "again" if d(text='身份验证').exists: d(text='下一步').click() if d(text='请填写您收到的短信验证码:').exists: info = numbers[0]['qqtoken'] infoArray = info.split('----') number = infoArray[6] # number = "14773454349" try: PhoneNumber = self.scode.GetPhoneNumber( self.scode.QQ_TOKEN_BIND, number) # 获取接码平台手机号码 except: logging.exception("exception") PhoneNumber = None if PhoneNumber is None: self.repo.BackupInfo(cate_id, 'frozen', QQNumber, '', '') # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber z.toast('查不无此号') return "again" try: code = self.scode.GetVertifyCode( PhoneNumber, self.scode.QQ_TOKEN_BIND) # 获取接码验证码 self.scode.defriendPhoneNumber(PhoneNumber, self.scode.QQ_TOKEN_BIND) except: logging.exception("exception") code = '' if code == '': z.toast(PhoneNumber + '手机号,获取不到验证码') self.scode.defriendPhoneNumber(PhoneNumber, self.scode.QQ_TOKEN_BIND) return "again" z.input(code) if d(resourceId='com.tencent.token:id/sms_code' ).exists: #点击输入框输入验证码 d(resourceId='com.tencent.token:id/sms_code').click() z.input(code) if d(text='下一步').exists: d(text='下一步').click() z.sleep(5) if d(text='开启安全之旅').exists: d(text='开启安全之旅').click() return QQNumber if d(textContains='绑定QQ失败').exists: return "again" elif d(text='登录失败').exists: return "again" def QieHuanSolt(self, d, z, args): # 卡槽切换方法 time_limit_slot = int(args['time_limit_slot']) slotObj = self.slot.getAvailableSlot( time_limit_slot) # 取空卡槽,取2小时没用过的卡槽 if not slotObj is None: slotnum = slotObj['id'] print(slotnum) while slotObj is None: # 2小时没用过的卡槽也为没有的情况 d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"QQ卡槽全满,无间隔时间段未用\"" ).communicate() z.heartbeat() z.sleep(10) slotObj = self.slot.getAvailableSlot(time_limit_slot) if not slotObj is None: slotnum = slotObj['id'] d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"正在切换到" + slotnum + "号卡槽...\"").communicate() self.slot.restore(slotnum) # 有time_limit分钟没用过的卡槽情况,切换卡槽 d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"卡槽成功切换为" + slotnum + "号\"").communicate() if d(text='QQ安全中心').exists: d(text='QQ安全中心').click() z.sleep(6) d.server.adb.cmd("shell", "pm clear com.tencent.token").communicate() # 清除缓存 d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"正在切换到" + slotnum + "号卡槽...\"").communicate() self.slot.restore(slotnum) # 有time_limit分钟没用过的卡槽情况,切换卡槽 d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"卡槽成功切换为" + slotnum + "号\"").communicate() d.server.adb.cmd("shell", "am start -n com.tencent.token/.ui.LogoActivity" ).communicate() # 拉起来 z.sleep(10) if d(text='欢迎来到安全中心').exists: return "fail" return "success" def action(self, d, z, args): z.generate_serial("com.tencent.tim") # 随机生成手机特征码 z.toast("随机生成手机特征码") serial = d.server.adb.device_serial() cate_id = args["repo_cate_id"] self.slot = Slot(serial, self.type) slotnum = self.slot.getEmpty() # 取空卡槽 if slotnum == 0: QieHuanSolt_Result = self.QieHuanSolt(d, z, args) if QieHuanSolt_Result == "fail": obj = self.slot.getSlotInfo(slotnum) remark = obj['remark'] remarkArr = remark.split("_") QQnumber = remarkArr[1] self.repo.BackupInfo(cate_id, 'frozen', QQnumber, '', '') # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber self.slot.clear(slotnum) # 清空改卡槽,并补登 z.toast("卡槽恢复失败,进行补登") self.action(d, z, args) else: z.toast("卡槽恢复成功,帐号正常") else: Login_Result = self.Login(d, z, args) if Login_Result == "again": self.action(d, z, args) elif Login_Result == "none": # 有空卡槽,单仓库无帐号可登,继续继续切换卡槽 QieHuanSolt_Result = self.QieHuanSolt(d, z, args) if QieHuanSolt_Result == "fail": obj = self.slot.getSlotInfo(slotnum) remark = obj['remark'] remarkArr = remark.split("_") QQnumber = remarkArr[1] self.repo.BackupInfo(cate_id, 'frozen', QQnumber, '', '') # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber self.slot.clear(slotnum) # 清空改卡槽,并补登 z.toast("卡槽恢复失败,进行补登") self.action(d, z, args) else: z.toast("卡槽恢复成功,帐号正常") else: QQnumber = Login_Result self.slot.backup(slotnum, str(slotnum) + '_' + QQnumber) # 设备信息,卡槽号,QQ号 self.repo.BackupInfo(cate_id, 'using', QQnumber, serial, '%s_%s_%s' % (d.server.adb.device_serial(), self.type, slotnum)) # 仓库号,使用中,QQ号,设备号_卡槽号
class WeiXinRegister: def __init__(self): self.repo = Repo() self.type = 'wechat' def GenPassword(self, numOfNum=4, numOfLetter=4): # 选中numOfNum个数字 slcNum = [random.choice(string.digits) for i in range(numOfNum)] # 选中numOfLetter个字母 slcLetter = [ random.choice(string.lowercase) for i in range(numOfLetter) ] slcChar = slcLetter + slcNum genPwd = ''.join([i for i in slcChar]) return genPwd def RegisterWX(self, d, z, args, slotnum): z.generate_serial("com.tencent.mm") # 随机生成手机特征码 z.toast("随机生成手机特征码") nowTime = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") # 生成当前时间 saveCate = args['repo_information_id'] self.scode = smsCode(d.server.adb.device_serial()) password = self.GenPassword() d.press.home() d.server.adb.cmd( "shell", "pm clear com.tencent.mm").communicate() # 清除缓存,返回home页面 if d(text='微信').exists: d(text='微信').click() else: z.toast("该页面没有微信,请翻到有微信页面运行") while not d(text='注册').exists: z.toast("等待 登录按钮 出现") d.dump(compressed=False) z.sleep(3) if d(text='登录').exists: d(text='登录').click() z.sleep(2) if not d(textContains='中国').exists: d(text='国家/地区').click() z.sleep(1.5) d(resourceId='com.tencent.mm:id/aq').click() z.input('中') d(text='中国').click() information_cate_id = args['repo_information_id'] numbers = self.repo.GetInformation(information_cate_id) if len(numbers) == 0: d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"资料库%s号仓库为空,没有取到手机号\"" % information_cate_id).communicate() z.sleep(10) return "notphonenumber" z.heartbeat() number = numbers[0]['phonenumber'] try: PhoneNumber = self.scode.GetPhoneNumber(self.scode.WECHAT_REGISTER, number) # 获取接码平台手机号码 except: PhoneNumber = None # PhoneNumber = self.scode.GetPhoneNumber( self.scode.WECHAT_REGISTER) # 获取接码平台手机号码 if PhoneNumber is None: self.repo.DeleteInformation(saveCate, number) z.toast('讯码查不无此号') return "again" z.input(PhoneNumber) if d(text='下一步').exists: d(text='下一步').click() z.sleep(1.5) d(text='用短信验证码登录').click() z.sleep(1.5) d(text='获取验证码').click() z.sleep(1) if d(text='确认手机号码').exists: d(text='确定').click() z.sleep(3) try: code = self.scode.GetVertifyCode( PhoneNumber, self.scode.WECHAT_REGISTER) # 获取接码验证码 self.scode.defriendPhoneNumber(PhoneNumber, self.scode.WECHAT_REGISTER) except: self.scode.defriendPhoneNumber(PhoneNumber, self.scode.WECHAT_REGISTER) code = '' if code == '': self.repo.DeleteInformation(saveCate, PhoneNumber) z.toast(PhoneNumber + '手机号,获取不到验证码') return "again" z.input(code) print('手机号码:' + PhoneNumber + '验证码:' + code) z.sleep(2) d(text='登录', className='android.widget.Button').click() z.sleep(5) z.heartbeat() if d(textContains='看看手机通讯录').exists: d(text='是').click() z.sleep(15) z.heartbeat() if d(textContains='如果这不是你本人操作,你的短信内容已经泄露。请检查手机是否被植入木马导致短信被转发。' ).exists: d(text='确定').click() featureCodeInfo = z.get_serial("com.tencent.mm") # 信息入库 para = { "phoneNumber": PhoneNumber, 'x_02': slotnum, 'x_03': d.server.adb.device_serial(), 'x_04': featureCodeInfo, 'x_05': nowTime, 'x_19': 'WXRegister' } self.repo.PostInformation(saveCate, para) # 微信号入卡槽 self.slot.backup(slotnum, str(slotnum) + '_' + PhoneNumber) # 卡槽号,手机号 return "success" if d(textContains='当前手机号一个月内已成功注册微信号').exists: d(text='确定') self.repo.DeleteInformation(saveCate, PhoneNumber) return "again" if d(textContains='操作频率').exists: d(text='确定').click() return "stop" if d(text='该手机号码尚未被注册,是否立即注册微信?').exists: d(text='注册').click() z.sleep(2) if d(text='填写个人信息').exists: d(text='昵称').click() nicknameList = [ random.choice(string.lowercase) for i in range(4) ] nickname = ''.join([i for i in nicknameList]) z.input(nickname) d(text='注册').click() z.sleep(2) if d(textContains='相同手机号不可频繁重复注册微信帐号。').exists: self.repo.DeleteInformation(saveCate, PhoneNumber) return "again" while not d(text='查找你的微信朋友').exists: d.dump(compressed=False) z.sleep(3) featureCodeInfo = z.get_serial("com.tencent.mm") # 信息入库 para = { "phoneNumber": PhoneNumber, 'x_02': slotnum, 'x_03': d.server.adb.device_serial(), 'x_04': featureCodeInfo, 'x_05': nowTime, 'x_19': 'WXRegister' } self.repo.PostInformation(saveCate, para) # 微信号入卡槽 self.slot.backup(slotnum, str(slotnum) + '_' + PhoneNumber) # 卡槽号,手机号 if d(text='好').exists: d(text='好').click() z.sleep(10) return "success" n = 0 while True: z.sleep(5) n = n + 1 if d(text='登录', className='android.widget.Button').exists: d(text='登录', className='android.widget.Button').click() z.sleep(8) if d(textContains='是否立即验证').exists: d(text='确定').click() z.sleep(8) elif d(text='声纹验证').exists: d(className='android.widget.ImageView', description='返回').click() self.repo.DeleteInformation(saveCate, PhoneNumber) break elif d(text='系统检测到帐号有被盗风险。为了你的帐号安全,新设备的登录请求会被拒绝。请使用常用设备登录微信。' ).exists: d(text='确定').click() if n == 1: continue else: break else: self.repo.DeleteInformation(saveCate, PhoneNumber) break if d(text='确认登录').exists: if n == 1: d(className='android.widget.ImageView', description='返回').click() continue elif n == 2: self.repo.DeleteInformation(saveCate, PhoneNumber) break if d(text='设置密码').exists: d(className='android.widget.LinearLayout', index=2).child(className='android.widget.EditText', index=1).click() z.input(password) z.sleep(2) d(className='android.widget.LinearLayout', index=4).child(className='android.widget.EditText', index=1).click() z.input(password) d(text='完成').click() z.sleep(15) z.heartbeat() if d(textContains='看看手机通讯录').exists: d(text='是').click() z.sleep(15) z.heartbeat() if d(textContains='你的操作频繁过快,请稍后重试').exists: d(text='确定').click() z.sleep(15) z.heartbeat() if d(textContains='如果这不是你本人操作,你的短信内容已经泄露。请检查手机是否被植入木马导致短信被转发。' ).exists: d(text='确定').click() featureCodeInfo = z.get_serial("com.tencent.mm") # 入库信息 para = { "phoneNumber": PhoneNumber, 'x_02': slotnum, 'x_03': d.server.adb.device_serial(), 'x_04': featureCodeInfo, 'x_05': nowTime, 'x_06': password, 'x_19': 'WXRegister' } self.repo.PostInformation(saveCate, para) # 入卡槽信息 self.slot.backup(slotnum, str(slotnum) + '_' + PhoneNumber) # 卡槽号,手机号 return "success" if d(text='验证身份').exists: z.sleep(3) if d(description='通过扫码验证身份', className='android.view.View', index=1).exists: featureCodeInfo = z.get_serial("com.tencent.mm") # 入库信息 para = { "phoneNumber": PhoneNumber, 'x_02': slotnum, 'x_03': d.server.adb.device_serial(), 'x_04': featureCodeInfo, 'x_05': nowTime, 'x_19': 'WXRegister' } self.repo.PostInformation(saveCate, para) # 入卡槽信息 self.slot.backup(slotnum, str(slotnum) + '_' + PhoneNumber) # 卡槽号,手机号 break if d(descriptionContains='验证失败', className='android.view.View').exists: d(descriptionContains='关闭页面', className='android.view.View', index=3).click() break if d(descriptionContains='验证通过', className='android.view.View').exists: d(descriptionContains='关闭页面', className='android.view.View', index=3).click() featureCodeInfo = z.get_serial("com.tencent.mm") # 入库信息 para = { "phoneNumber": PhoneNumber, 'x_02': slotnum, 'x_03': d.server.adb.device_serial(), 'x_04': featureCodeInfo, 'x_05': nowTime, 'x_19': 'WXRegister' } self.repo.PostInformation(saveCate, para) # 入卡槽信息 self.slot.backup(slotnum, str(slotnum) + '_' + PhoneNumber) # 卡槽号,手机号 return "success" for i in range(1, 6): if i != 1: yibushiObj_HTC = d( className='android.widget.RadioButton', descriptionContains='以上都不是') if not yibushiObj_HTC.exists: break if d(description='请选择你最近一次登录设备的名称').exists: if d(className='android.widget.RadioButton', index=1).exists: number = random.randint(1, 5) if number == 1: d(className='android.widget.RadioButton', index=1).click() d(className='android.view.View', descriptionContains='下一步').click() # 下一步 z.sleep(2) if number == 2: d(className='android.widget.RadioButton', index=2).click() d(className='android.view.View', descriptionContains='下一步').click() # 下一步 z.sleep(2) if number == 3: d(className='android.widget.RadioButton', index=3).click() d(className='android.view.View', descriptionContains='下一步').click() # 下一步 z.sleep(2) if number == 4: d(className='android.widget.RadioButton', index=4).click() d(className='android.view.View', descriptionContains='下一步').click() # 下一步 z.sleep(2) if number == 5: d(className='android.widget.RadioButton', index=5).click() d(className='android.view.View', descriptionContains='下一步').click() # 下一步 z.sleep(2) else: if d(className='android.widget.RadioButton', descriptionContains='以上都不是').exists: d(className='android.widget.RadioButton', descriptionContains='以上都不是').click() d(className='android.view.View', descriptionContains='下一步').click() # 下一步 else: d.click(410, 540) d.click(410, 640) z.sleep(2) elif d(description='请从下面头像中选出两位你的好友').exists: d(className='android.widget.ImageView', description='返回').click() break else: if d(className='android.widget.RadioButton', descriptionContains='以上都不是').exists: d(className='android.widget.RadioButton', descriptionContains='以上都不是').click() d(className='android.view.View', descriptionContains='下一步').click() # 下一步 else: d.click(410, 540) d.click(410, 640) z.sleep(2) z.sleep(5) if d(text='确认登录').exists: d(className='android.widget.ImageView', description='返回').click() continue if d(descriptionContains='验证失败', className='android.view.View').exists: d(descriptionContains='关闭页面', className='android.view.View', index=3).click() continue if d(descriptionContains='验证通过', className='android.view.View').exists: d(descriptionContains='关闭页面', className='android.view.View', index=3).click() continue return "again" def action(self, d, z, args): logger = util.logger lock = "YES" while True: time_limit = 0 serial = d.server.adb.device_serial() self.slot = Slot(serial, self.type) if lock == "YES": slotnum = self.slot.getEmpty() # 取空卡槽 else: slotnum = 0 if slotnum == 0: # 没有空卡槽的话 slotObj = self.slot.getAvailableSlot( time_limit) # 取空卡槽,取2小时没用过的卡槽 if not slotObj is None: slotnum = slotObj['id'] print(slotnum) while slotObj is None: # 2小时没用过的卡槽也为没有的情况 d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"微信卡槽全满,无间隔时间段未用\"" ).communicate() z.heartbeat() z.sleep(30) slotObj = self.slot.getAvailableSlot(time_limit) if not slotObj is None: slotnum = slotObj['id'] z.heartbeat() obj = self.slot.getSlotInfo(slotnum) remark = obj['remark'] remarkArr = remark.split("_") if len(remarkArr) == 2: phonenumber = remarkArr[1] information_cate_id = args['repo_information_id'] numbers = self.repo.GetInformation(information_cate_id, phonenumber) featureCodeInfo = numbers[0]['x04'] z.set_serial("com.tencent.mm", featureCodeInfo) self.slot.restore(slotnum) # 有time_limit分钟没用过的卡槽情况,切换卡槽 d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"卡槽成功切换为" + slotnum + "号\"").communicate() d.server.adb.cmd( "shell", "am start -n com.tencent.mm/com.tencent.mm.ui.LauncherUI" ).communicate() # 将微信拉起来 z.sleep(15) z.heartbeat() if d(text='立刻安装').exists: z.toast("出现更新弹框") d(textContains='取消').click() z.sleep(1.5) d(text='是').click() if d(text='发现') and d(text='我') and d(text='通讯录').exists: z.toast("成功切换" + slotnum + "卡槽") break else: self.slot.clear(slotnum) # 清空改卡槽,并补登 z.toast("切换失败,开始补登") lock = "YES" self.action(d, z, args) else: result = self.RegisterWX(d, z, args, slotnum) if result == "again": continue elif result == "stop": z.toast("操作频繁,模块结束运行") break elif result == "notphonenumber": lock = "NO" continue else: continue
class TIMLogin03: def __init__(self): self.repo = Repo() self.type = 'tim' def IPCheckRepitition(self, z, d, args): z.toast("正在检测IP...") while True: # 开关飞行模式 d.server.adb.cmd( "shell", "settings put global airplane_mode_on 1").communicate() d.server.adb.cmd( "shell", "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true" ).communicate() z.sleep(3) d.server.adb.cmd( "shell", "settings put global airplane_mode_on 0").communicate() d.server.adb.cmd( "shell", "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false" ).communicate() t = 0 while t < 6: ping = d.server.adb.cmd("shell", "ping -c 3 baidu.com").communicate() print(ping) if 'icmp_seq' and 'bytes from' and 'time' in ping[0]: break z.sleep(10) z.heartbeat() z.sleep(10) t = t + 1 if t >= 6: z.toast("网络无法ping通,重新开关飞行模式") continue # 获取手机IP IPList = d.server.adb.cmd( "shell", "curl http://ipecho.net/plain").communicate() IP = IPList[0] print(IP) # IP添加到缓存 ip = cache.get(IP) print(ip) if ip is None: timeoutStr = args['time_out'] timeout = int(timeoutStr) * 60 cache.set(IP, IP, timeout) z.toast("IP检测完成") break else: continue def GetUnique(self): nowTime = datetime.datetime.now().strftime("%Y%m%d%H%M%S") # 生成当前时间 randomNum = random.randint(0, 1000) # 生成的随机整数n,其中0<=n<=100 if randomNum <= 10: randomNum = str(00) + str(randomNum) uniqueNum = str(nowTime) + str(randomNum) return uniqueNum def LoginPlayCode(self, d, z): self.scode = smsCode(d.server.adb.device_serial()) base_dir = os.path.abspath( os.path.join(os.path.dirname(__file__), os.path.pardir, "tmp")) if not os.path.isdir(base_dir): os.mkdir(base_dir) sourcePng = os.path.join(base_dir, "%s_s.png" % (self.GetUnique())) codePng = os.path.join(base_dir, "%s_c.png" % (self.GetUnique())) detection_robot = d(index='3', className="android.widget.EditText") not_detection_robot = d(resourceId='com.tencent.tim:id/name', index='2', className="android.widget.EditText") if detection_robot.exists or not_detection_robot.exists: # 需要验证码的情况 icode = imageCode() im_id = "" for i in range(0, 4): # 打码循环 if i > 0: icode.reportError(im_id) obj = d(resourceId='com.tencent.tim:id/name', className='android.widget.ImageView' ) # 当弹出选择QQ框的时候,定位不到验证码图片 if not obj.exists: obj = d(index='2', className='android.widget.Image') obj = obj.info obj = obj['bounds'] # 验证码处的信息 left = obj["left"] # 验证码的位置信息 top = obj['top'] right = obj['right'] bottom = obj['bottom'] d.screenshot(sourcePng) # 截取整个输入验证码时的屏幕 img = Image.open(sourcePng) box = (left, top, right, bottom) # left top right bottom region = img.crop(box) # 截取验证码的图片 img = Image.new('RGBA', (right - left, bottom - top)) img.paste(region, (0, 0)) img.save(codePng) im = open(codePng, 'rb') codeResult = icode.getCode(im, icode.CODE_TYPE_4_NUMBER_CHAR, 60) code = codeResult["Result"] im_id = codeResult["Id"] os.remove(sourcePng) os.remove(codePng) z.heartbeat() z.sleep(5) if not_detection_robot.exists: d(resourceId='com.tencent.tim:id/name', index='2', className="android.widget.EditText").set_text(code) else: detection_robot.set_text(code) z.sleep(3) if d(descriptionContains='验证', className='android.view.View').exists: d(descriptionContains='验证', className='android.view.View').click() else: d(text='完成', resourceId='com.tencent.tim:id/ivTitleBtnRightText' ).click() z.sleep(5) z.heartbeat() while d(className='android.widget.ProgressBar', index=0).exists: # 网速不给力时,点击完成后仍然在加载时的状态 z.sleep(2) z.heartbeat() if detection_robot.exists or not_detection_robot.exists: continue else: break z.sleep(5) if d(textContains='验证码').exists: return "no" else: return "yes" else: return "no" def login(self, d, args, z): z.heartbeat() Str = d.info # 获取屏幕大小等信息 height = float(Str["displayHeight"]) width = float(Str["displayWidth"]) W_H = width / height screenScale = round(W_H, 2) cate_id = args["repo_cate_id"] time_limit1 = args['time_limit1'] numbers = self.repo.GetAccount(cate_id, time_limit1, 1) while len(numbers) == 0: z.heartbeat() d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"QQ帐号库%s号仓库无%s分钟未用,开始切换卡槽\"" % (cate_id, time_limit1)).communicate() z.sleep(2) return 0 QQNumber = numbers[0]['number'] # 即将登陆的QQ号 QQPassword = numbers[0]['password'] z.sleep(1) z.heartbeat() d.server.adb.cmd("shell", "pm clear com.tencent.tim").communicate() # 清除缓存 # d.server.adb.cmd("shell", # "am start -n com.tencent.tim/com.tencent.mobileqq.activity.SplashActivity" ).communicate( ) # 拉起来 z.server.adb.run_cmd( "shell", "am start -n com.tencent.tim/com.tencent.mobileqq.activity.SplashActivity" ) z.sleep(5) while d(textContains='正在更新数据').exists: z.sleep(2) z.sleep(3) z.server.adb.run_cmd( "shell", "am start -n com.tencent.tim/com.tencent.mobileqq.activity.SplashActivity" ) z.heartbeat() if d(className='android.widget.ImageView', resourceId='com.tencent.tim:id/title', index=1).exists: for i in range(0, 2): d.swipe(width - 20, height / 2, 0, height / 2, 5) z.sleep(1.5) if d(text='立即体验').exists: d(text='立即体验').click() z.sleep(2) d.dump(compressed=False) if d(text='登 录', resourceId='com.tencent.tim:id/btn_login').exists: z.toast("控件点击") d(text='登 录').click() else: d(text='QQ号登录').click() z.sleep(1) # d(className='android.widget.EditText', index=0).set_text(QQNumber) # 1918697054----xiake1234. QQNumber d(className='android.widget.EditText', index=0).click() # 1918697054----xiake1234. QQNumber z.input(QQNumber) z.sleep(1) # d(resourceId='com.tencent.mobileqq:id/password').set_text(QQPassword) # Bn2kJq5l QQPassword d(resourceId='com.tencent.tim:id/password').click( ) # Bn2kJq5l QQPassword z.input(QQPassword) z.heartbeat() logger = util.logger print('QQ号:%s,QQ密码:%s' % (QQNumber, QQPassword)) d.dump(compressed=False) d(text='登 录', resourceId='com.tencent.tim:id/login').click() z.sleep(1) while d(text='登录中').exists: z.sleep(2) z.sleep(5) z.heartbeat() detection_robot = d(index='3', className="android.widget.EditText") not_detection_robot = d(resourceId='com.tencent.tim:id/name', index='2', className="android.widget.EditText") if detection_robot.exists or not_detection_robot.exists: playCodeResult = self.LoginPlayCode(d, z) # 打验证码 if playCodeResult == "no": return "nothing" z.sleep(5) z.heartbeat() if d(text='马上绑定').exists: return QQNumber if d(text='匹配手机通讯录').exists: # 登陆上后弹出t通讯录的情况 d(text='匹配手机通讯录').click() z.sleep(1.5) if d(text='取消').exists: d(text='取消').child() return QQNumber if d(text='消息').exists and d(description='快捷入口').exists: z.toast("卡槽QQ状态正常,继续执行") return QQNumber if d(text='去安全中心').exists: self.repo.BackupInfo(cate_id, 'frozen', QQNumber, '', '') # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber z.toast("登陆失败,重新登陆") return "nothing" else: self.repo.BackupInfo(cate_id, 'normal', QQNumber, '', '') # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber z.toast("登陆失败,重新登陆") return "nothing" def qiehuan(self, d, z, args): Str = d.info # 获取屏幕大小等信息 height = float(Str["displayHeight"]) width = float(Str["displayWidth"]) time_limit = int(args['time_limit']) cate_id = args["repo_cate_id"] serial = d.server.adb.device_serial() self.slot = Slot(serial, self.type) slotObj = self.slot.getAvailableSlot(time_limit) # 没有空卡槽,取2小时没用过的卡槽 while slotObj is None: # 2小时没有用过的卡槽也为空的情况 d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"QQ卡槽全满,无间隔时间段未用\"" ).communicate() z.heartbeat() z.sleep(10) slotObj = self.slot.getAvailableSlot( time_limit) # 没有空卡槽,取2小时没用过的卡槽 if not slotObj is None: slotnum = slotObj['id'] z.heartbeat() d.server.adb.cmd("shell", "pm clear com.tencent.tim").communicate() # 清除缓存 # d.server.adb.cmd("shell", "settings put global airplane_mode_on 1").communicate() # d.server.adb.cmd("shell", "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true").communicate() # z.sleep(6) # z.heartbeat() # d.server.adb.cmd("shell", "settings put global airplane_mode_on 0").communicate() # d.server.adb.cmd("shell", "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false").communicate() # z.heartbeat() # z.toast( "正在ping网络是否通畅" ) # while True: # ping = d.server.adb.cmd("shell", "ping -c 3 baidu.com").communicate() # print(ping) # if 'icmp_seq' and 'bytes from' and 'time' in ping[0]: # break # z.sleep(2) try: self.IPCheckRepitition(z, d, args) except: z.toast("IP检测出错了,请查找问题") self.slot.restore(slotnum) # 有time_limit分钟没用过的卡槽情况,切换卡槽 d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"卡槽成功切换为" + str(slotnum) + "号\"").communicate() z.sleep(2) # d.server.adb.cmd("shell", "am start -n com.tencent.tim/com.tencent.mobileqq.activity.SplashActivity").communicate() # 拉起来 z.server.adb.run_cmd( "shell", "am start -n com.tencent.tim/com.tencent.mobileqq.activity.SplashActivity" ) z.sleep(5) while d(textContains='正在更新数据').exists: z.sleep(2) z.sleep(3) z.server.adb.run_cmd( "shell", "am start -n com.tencent.tim/com.tencent.mobileqq.activity.SplashActivity" ) z.heartbeat() if d(className='android.widget.ImageView', resourceId='com.tencent.tim:id/title', index=1).exists: for i in range(0, 2): d.swipe(width - 20, height / 2, 0, height / 2, 5) z.sleep(1.5) if d(text='立即体验').exists: d(text='立即体验').click() z.sleep(2) if d(text='消息').exists or d(text='马上绑定').exists or d( text='匹配手机通讯录').exists: if d(text='匹配手机通讯录').exists: # 登陆上后弹出t通讯录的情况 d(text='匹配手机通讯录').click() z.sleep(1.5) if d(text='取消').exists: d(text='取消').child() z.toast("卡槽QQ切换成功,继续执行") else: obj = self.slot.getSlotInfo(slotnum) remark = obj['remark'] remarkArr = remark.split("_") QQnumber = remarkArr[1] if d(text='去安全中心').exists: self.repo.BackupInfo(cate_id, 'frozen', QQnumber, '', '') # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber else: self.repo.BackupInfo(cate_id, 'normal', QQnumber, '', '') self.slot.clear(slotnum) # 清空改卡槽,并补登 z.toast("卡槽QQ状态异常,补登陆卡槽") self.action(d, z, args) def action(self, d, z, args): Str = d.info # 获取屏幕大小等信息 height = float(Str["displayHeight"]) width = float(Str["displayWidth"]) z.generate_serial("com.tencent.tim") # 随机生成手机特征码 z.toast("随机生成手机特征码") time_limit = int(args['time_limit']) cate_id = args["repo_cate_id"] serial = d.server.adb.device_serial() self.slot = Slot(serial, self.type) slotnum = self.slot.getEmpty() # 取空卡槽 if slotnum == 0: # 没有空卡槽的话 slotObj = self.slot.getAvailableSlot(time_limit) # 取空卡槽,取2小时没用过的卡槽 if not slotObj is None: slotnum = slotObj['id'] print(slotnum) while slotObj is None: # 2小时没用过的卡槽也为没有的情况 d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"QQ卡槽全满,无间隔时间段未用\"" ).communicate() z.heartbeat() z.sleep(10) slotObj = self.slot.getAvailableSlot(time_limit) if not slotObj is None: slotnum = slotObj['id'] z.heartbeat() # d.server.adb.cmd( "shell", "pm clear com.tencent.tim" ).communicate( ) # 清除缓存 # d.server.adb.cmd( "shell", "am force-stop com.tencent.tim" ).communicate( ) # 强制停止 # d.server.adb.cmd("shell", "settings put global airplane_mode_on 1").communicate() #开数据流量 # d.server.adb.cmd("shell","am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true").communicate()#开飞行模式 # z.sleep( 6 ) # z.heartbeat( ) # d.server.adb.cmd("shell", "settings put global airplane_mode_on 0").communicate() # 关数据流量 # d.server.adb.cmd("shell", "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false").communicate()#开飞行模式 # # z.heartbeat( ) # z.toast( "正在ping网络是否通畅" ) # while True: # ping = d.server.adb.cmd( "shell", "ping -c 3 baidu.com" ).communicate( ) # print( ping ) # if 'icmp_seq' and 'bytes from' and 'time' in ping[0]: # break # z.sleep( 2 ) try: self.IPCheckRepitition(z, d, args) except: z.toast("IP检测出错了,请查找问题") self.slot.restore(slotnum) # 有time_limit分钟没用过的卡槽情况,切换卡槽 d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"卡槽成功切换为" + slotnum + "号\"").communicate() z.sleep(2) # d.server.adb.cmd( "shell", # "am start -n com.tencent.tim/com.tencent.mobileqq.activity.SplashActivity" ).communicate( ) # 拉起来 z.server.adb.run_cmd( "shell", "am start -n com.tencent.tim/com.tencent.mobileqq.activity.SplashActivity" ) z.sleep(5) while d(textContains='正在更新数据').exists: z.sleep(2) z.sleep(3) z.server.adb.run_cmd( "shell", "am start -n com.tencent.tim/com.tencent.mobileqq.activity.SplashActivity" ) if d(className='android.widget.ImageView', resourceId='com.tencent.tim:id/title', index=1).exists: for i in range(0, 2): d.swipe(width - 20, height / 2, 0, height / 2, 5) z.sleep(1.5) if d(text='立即体验').exists: d(text='立即体验').click() z.sleep(2) z.heartbeat() if d(text='消息').exists or d(text='马上绑定').exists or d( text='匹配手机通讯录').exists: if d(text='匹配手机通讯录').exists: # 登陆上后弹出t通讯录的情况 d(text='匹配手机通讯录').click() z.sleep(1.5) if d(text='取消').exists: d(text='取消').click() z.toast("卡槽QQ切换成功,继续执行") else: obj = self.slot.getSlotInfo(slotnum) remark = obj['remark'] remarkArr = remark.split("_") QQnumber = remarkArr[1] if d(text='去安全中心').exists: self.repo.BackupInfo(cate_id, 'frozen', QQnumber, '', '') # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber else: self.repo.BackupInfo(cate_id, 'normal', QQnumber, '', '') self.slot.clear(slotnum) # 清空改卡槽,并补登 z.toast("卡槽QQ状态异常,补登陆卡槽") self.action(d, z, args) else: # 有空卡槽的情况 d.server.adb.cmd("shell", "pm clear com.tencent.tim").communicate() # 清除缓存 # d.server.adb.cmd("shell", "settings put global airplane_mode_on 1").communicate() # d.server.adb.cmd("shell", "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true").communicate() # z.sleep(3) # d.server.adb.cmd("shell", "settings put global airplane_mode_on 0").communicate() # d.server.adb.cmd("shell", "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false").communicate() # z.heartbeat( ) # z.toast( "正在ping网络是否通畅" ) # while True: # ping = d.server.adb.cmd( "shell", "ping -c 3 baidu.com" ).communicate( ) # print( ping ) # if 'icmp_seq' and 'bytes from' and 'time' in ping[0]: # break # z.sleep( 2 ) try: self.IPCheckRepitition(z, d, args) except: logging.exception("exception") z.toast("IP检测出错了,请查找问题") serialinfo = d.server.adb.device_serial() # print('登陆时的serial%s'%serialinfo) z.heartbeat() QQnumber = self.login(d, args, z) if QQnumber == 'nothing': self.slot.clear(slotnum) # 清空改卡槽,并补登 self.action(d, z, args) elif QQnumber == 0: z.toast("仓库为空,无法登陆。开始切换卡槽") self.qiehuan(d, z, args) elif QQnumber is None: return else: z.heartbeat() self.slot.backup(slotnum, str(slotnum) + '_' + QQnumber) # 设备信息,卡槽号,QQ号 self.repo.BackupInfo(cate_id, 'using', QQnumber, serialinfo, '%s_%s_%s' % (d.server.adb.device_serial(), self.type, slotnum)) # 仓库号,使用中,QQ号,设备号_卡槽号 if (args["time_delay"]): time.sleep(int(args["time_delay"]))
class QLLogin: def __init__(self): self.repo = Repo() self.type = 'qqlite' def GetUnique(self): nowTime = datetime.datetime.now().strftime("%Y%m%d%H%M%S"); # 生成当前时间 randomNum = random.randint(0, 1000); # 生成的随机整数n,其中0<=n<=100 if randomNum <= 10: randomNum = str(00) + str(randomNum); uniqueNum = str(nowTime) + str(randomNum); return uniqueNum def LoginPlayCode(self, d, z): self.scode = smsCode( d.server.adb.device_serial( ) ) base_dir = os.path.abspath( os.path.join( os.path.dirname( __file__ ), os.path.pardir, "tmp" ) ) if not os.path.isdir( base_dir ): os.mkdir( base_dir ) sourcePng = os.path.join( base_dir, "%s_s.png" % (self.GetUnique( )) ) codePng = os.path.join( base_dir, "%s_c.png" % (self.GetUnique( )) ) detection_robot = d( index='3', className="android.widget.EditText" ) not_detection_robot = d( index='2', className="android.widget.EditText" ) if detection_robot.exists or not_detection_robot.exists: # 需要验证码的情况 icode = imageCode( ) im_id = "" for i in range( 0, 4 ): # 打码循环 if i > 0: icode.reportError( im_id ) obj = d( resourceId='com.tencent.qqlite:id/0', className='android.widget.ImageView' ) # 当弹出选择QQ框的时候,定位不到验证码图片 if not obj.exists: obj = d( index='2', className='android.widget.Image' ) obj = obj.info obj = obj['bounds'] # 验证码处的信息 left = obj["left"] # 验证码的位置信息 top = obj['top'] right = obj['right'] bottom = obj['bottom'] d.screenshot( sourcePng ) # 截取整个输入验证码时的屏幕 img = Image.open( sourcePng ) box = (left, top, right, bottom) # left top right bottom region = img.crop( box ) # 截取验证码的图片 img = Image.new( 'RGBA', (right - left, bottom - top) ) img.paste( region, (0, 0) ) img.save( codePng ) im = open( codePng, 'rb' ) codeResult = icode.getCode( im, icode.CODE_TYPE_4_NUMBER_CHAR, 60 ) code = codeResult["Result"] im_id = codeResult["Id"] os.remove( sourcePng ) os.remove( codePng ) z.heartbeat( ) z.sleep( 5 ) if not_detection_robot.exists: d( resourceId='com.tencent.qqlite:id/0', index='2', className="android.widget.EditText" ).set_text( code ) else: detection_robot.set_text( code ) z.sleep( 3 ) if d( descriptionContains='验证', className='android.view.View' ).exists: d( descriptionContains='验证', className='android.view.View' ).click( ) else: d( text='完成', resourceId='com.tencent.qqlite:id/ivTitleBtnRightText' ).click( ) z.sleep( 5 ) z.heartbeat( ) while d( className='android.widget.ProgressBar', index=0 ).exists: # 网速不给力时,点击完成后仍然在加载时的状态 z.sleep( 2 ) z.heartbeat( ) if detection_robot.exists or not_detection_robot.exists: continue else: break z.sleep( 5 ) if d( textContains='验证码' ).exists: return "no" else: return "yes" else: return "no" def BindAddressBook(self, z, d, args): z.toast( "点击启用" ) self.scode = smsCode( d.server.adb.device_serial( ) ) d( text='启用' ).click( ) while d( text='验证手机号码' ).exists: PhoneNumber = None j = 0 while PhoneNumber is None: j += 1 if j == 2: z.toast( '取不到手机号码' ) if (args["time_delay"]): z.sleep( int( args["time_delay"] ) ) return PhoneNumber = self.scode.GetPhoneNumber( self.scode.QQ_CONTACT_BIND ) # 获取接码平台手机号码 z.heartbeat( ) if not d( textContains='+86' ).exists: d( description='点击选择国家和地区' ).click( ) if d( text='中国' ).exists: d( text='中国' ).click( ) else: str = d.info # 获取屏幕大小等信息 height = str["displayHeight"] width = str["displayWidth"] d.click(width * 5 / 12, height * 5 / 32) z.sleep(1.5) z.input('中国') z.sleep(2) d(text='+86').click() z.input(PhoneNumber) z.sleep(1.5) if d(text='下一步').exists: d(text='下一步').click() z.sleep(3) while d( text='正在发送请求' ).exists: z.sleep( 2 ) z.sleep(2) z.heartbeat( ) if d( text='确定' ).exists: d( text='确定' ).click( ) z.sleep( 2 ) code = self.scode.GetVertifyCode( PhoneNumber, self.scode.QQ_CONTACT_BIND, '4' ) # 获取接码验证码 self.scode.defriendPhoneNumber( PhoneNumber, self.scode.QQ_CONTACT_BIND ) if code == '': z.toast( PhoneNumber + '手机号,获取不到验证码' ) if d( text='返回' ).exists: d( text='返回' ).click( ) if not d( textContains='中国' ).exists: if d( text='返回' ).exists: d( text='返回' ).click( ) if d( className='android.view.View', descriptionContains='删除' ).exists: d( className='android.view.View', descriptionContains='删除' ).click( ) continue z.heartbeat( ) z.input( code ) if d( text='下一步' ).exists: d( text='下一步' ).click( ) z.sleep(1.5) if d(text='好').exists: d(text='好').click() z.sleep(5) break def login(self,d,args,z): z.heartbeat() Str = d.info # 获取屏幕大小等信息 height = float( Str["displayHeight"] ) width = float( Str["displayWidth"] ) W_H = width / height screenScale = round( W_H, 2 ) cate_id = args["repo_cate_id"] time_limit1 = args['time_limit1'] numbers = self.repo.GetAccount( cate_id, time_limit1, 1 ) while len( numbers ) == 0: z.heartbeat( ) d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"QQ帐号库%s号仓库无%s分钟未用,开始切换卡槽\"" % ( cate_id, time_limit1) ).communicate( ) z.sleep( 2 ) return 0 QQNumber = numbers[0]['number'] # 即将登陆的QQ号 QQPassword = numbers[0]['password'] z.sleep( 1 ) z.heartbeat( ) d.server.adb.cmd("shell", "pm clear com.tencent.qqlite").communicate( ) # 清除缓存 # d.server.adb.cmd("shell", # "am start -n com.tencent.tim/com.tencent.mobileqq.activity.SplashActivity" ).communicate( ) # 拉起来 z.server.adb.run_cmd( "shell", "am start -n com.tencent.qqlite/com.tencent.mobileqq.activity.SplashActivity" ) z.sleep(5) while d( textContains='正在更新数据' ).exists: z.sleep( 2 ) z.sleep(3) z.heartbeat( ) d.dump(compressed=False) if d(text='登 录',resourceId='com.tencent.qqlite:id/btn_login').exists: z.toast("控件点击") d( text='登 录' ).click() else: if screenScale == 0.61: d.click(140, 788) if screenScale == 0.56: d.click(186, 1128) z.sleep( 1 ) # d(className='android.widget.EditText', index=0).set_text(QQNumber) # 1918697054----xiake1234. QQNumber d(className='android.widget.EditText', index=0).click() # 1918697054----xiake1234. QQNumber z.input( QQNumber ) z.sleep( 1 ) # d(resourceId='com.tencent.mobileqq:id/password').set_text(QQPassword) # Bn2kJq5l QQPassword d(resourceId='com.tencent.qqlite:id/password').click() # Bn2kJq5l QQPassword z.input( QQPassword ) z.heartbeat() logger = util.logger print('QQ号:%s,QQ密码:%s' % (QQNumber, QQPassword)) d.dump(compressed=False ) d( text='登 录', resourceId='com.tencent.qqlite:id/login' ).click( ) z.sleep(1) while d(text='登录中').exists: z.sleep(2) z.sleep(5) z.heartbeat() not_detection_robot = d(resourceId='com.tencent.qqlite:id/0',index='2', className="android.widget.EditText" ) if not_detection_robot.exists: playCodeResult = self.LoginPlayCode( d, z ) # 打验证码 elif d( text='QQ轻聊版', resourceId='com.tencent.qqlite:id/0',className='android.widget.TextView').exists or d( text='启用' ).exists: return QQNumber else: self.repo.BackupInfo( cate_id, 'frozen', QQNumber, '', '' ) # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber z.toast( "卡槽QQ状态异常,跳过此模块" ) return "nothing" if playCodeResult == "no": return "nothing" z.sleep(5) z.heartbeat() if d( text='启用' ).exists: # self.BindAddressBook(z, d, args) return QQNumber if d(text='QQ轻聊版', resourceId='com.tencent.qqlite:id/0',className='android.widget.TextView').exists: z.toast("卡槽QQ状态正常,继续执行") return QQNumber else: self.repo.BackupInfo( cate_id, 'frozen', QQNumber, '', '' ) # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber z.toast( "卡槽QQ状态异常,跳过此模块" ) return "nothing" def qiehuan(self,d,z,args): time_limit = int(args['time_limit']) cate_id = args["repo_cate_id"] serial = d.server.adb.device_serial( ) self.slot = Slot( serial, self.type ) slotObj = self.slot.getAvailableSlot(time_limit) # 没有空卡槽,取2小时没用过的卡槽 while slotObj is None: # 2小时没有用过的卡槽也为空的情况 d.server.adb.cmd("shell", "am broadcast -a com.zunyun.zime.toast --es msg \"QQ卡槽全满,无间隔时间段未用\"").communicate() z.heartbeat() z.sleep(10) slotObj = self.slot.getAvailableSlot( time_limit ) # 没有空卡槽,取2小时没用过的卡槽 if not slotObj is None: slotnum = slotObj['id'] z.heartbeat() d.server.adb.cmd("shell", "pm clear com.tencent.qqlite").communicate() # 清除缓存 d.server.adb.cmd("shell", "settings put global airplane_mode_on 1").communicate() d.server.adb.cmd("shell", "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true").communicate() z.sleep(6) z.heartbeat() d.server.adb.cmd("shell", "settings put global airplane_mode_on 0").communicate() d.server.adb.cmd("shell", "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false").communicate() obj = self.slot.getSlotInfo( slotnum ) remark = obj['remark'] remarkArr = remark.split( "_" ) if len(remarkArr) == 4: featureCodeInfo = remarkArr[2] z.set_serial( "com.tencent.qqlite", featureCodeInfo ) self.slot.restore( slotnum ) # 有time_limit分钟没用过的卡槽情况,切换卡槽 z.heartbeat() z.toast( "正在ping网络是否通畅" ) while True: ping = d.server.adb.cmd("shell", "ping -c 3 baidu.com").communicate() print(ping) if 'icmp_seq' and 'bytes from' and 'time' in ping[0]: break z.sleep(2) d.server.adb.cmd("shell", "am broadcast -a com.zunyun.zime.toast --es msg \"卡槽成功切换为" + str(slotnum) + "号\"").communicate() z.sleep(2) # d.server.adb.cmd("shell", "am start -n com.tencent.tim/com.tencent.mobileqq.activity.SplashActivity").communicate() # 拉起来 z.server.adb.run_cmd( "shell", "am start -n com.tencent.qqlite/com.tencent.mobileqq.activity.SplashActivity" ) z.sleep( 5 ) while d( textContains='正在更新数据' ).exists: z.sleep( 2 ) z.sleep( 3 ) z.heartbeat() if d(text='QQ轻聊版', resourceId='com.tencent.qqlite:id/0',className='android.widget.TextView').exists.exists or d( text='启用' ).exists: z.toast( "卡槽QQ切换成功,继续执行" ) else: obj = self.slot.getSlotInfo( slotnum ) remark = obj['remark'] remarkArr = remark.split( "_" ) QQnumber = remarkArr[1] self.repo.BackupInfo( cate_id, 'frozen', QQnumber, '', '' ) # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber self.slot.clear( slotnum ) # 清空改卡槽,并补登 z.toast( "卡槽QQ状态异常,补登陆卡槽" ) self.action( d, z, args ) def action(self,d,z,args): z.generate_serial("com.tencent.qqlite") # 随机生成手机特征码 z.toast("随机生成手机特征码") time_limit = int( args['time_limit'] ) cate_id = args["repo_cate_id"] serial = d.server.adb.device_serial( ) self.slot = Slot( serial, self.type ) slotnum = self.slot.getEmpty( ) # 取空卡槽 if slotnum == 0: # 没有空卡槽的话 slotObj = self.slot.getAvailableSlot( time_limit ) # 取空卡槽,取2小时没用过的卡槽 if not slotObj is None: slotnum = slotObj['id'] print( slotnum ) while slotObj is None: # 2小时没用过的卡槽也为没有的情况 d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"QQ卡槽全满,无间隔时间段未用\"" ).communicate( ) z.heartbeat( ) z.sleep( 10 ) slotObj = self.slot.getAvailableSlot( time_limit ) if not slotObj is None: slotnum = slotObj['id'] z.heartbeat() d.server.adb.cmd("shell", "pm clear com.tencent.qqlite" ).communicate() # 清除缓存 d.server.adb.cmd("shell", "settings put global airplane_mode_on 1").communicate() #开数据流量 d.server.adb.cmd("shell","am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true").communicate()#开飞行模式 z.sleep(6) z.heartbeat() d.server.adb.cmd("shell", "settings put global airplane_mode_on 0").communicate() # 关数据流量 d.server.adb.cmd("shell", "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false").communicate()#开飞行模式 obj = self.slot.getSlotInfo( slotnum ) remark = obj['remark'] remarkArr = remark.split( "_" ) if len( remarkArr ) == 4: featureCodeInfo = remarkArr[2] + remarkArr[3] print( featureCodeInfo ) z.set_serial( "com.tencent.qqlite", featureCodeInfo ) z.set_serial( "com.tencent.qqlite", featureCodeInfo ) self.slot.restore(slotnum) # 有time_limit分钟没用过的卡槽情况,切换卡槽 z.heartbeat() z.toast("正在ping网络是否通畅") while True: ping = d.server.adb.cmd("shell", "ping -c 3 baidu.com").communicate() print(ping) if 'icmp_seq' and 'bytes from' and 'time' in ping[0]: break z.sleep( 2 ) d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"卡槽成功切换为" + slotnum + "号\"" ).communicate( ) z.sleep( 2 ) # d.server.adb.cmd( "shell", # "am start -n com.tencent.tim/com.tencent.mobileqq.activity.SplashActivity" ).communicate( ) # 拉起来 z.server.adb.run_cmd( "shell", "am start -n com.tencent.qqlite/com.tencent.mobileqq.activity.SplashActivity" ) z.sleep(5) while d( textContains='正在更新数据' ).exists: z.sleep( 2 ) z.sleep( 3 ) z.heartbeat() if d(text='QQ轻聊版', resourceId='com.tencent.qqlite:id/0',className='android.widget.TextView').exists or d( text='启用' ).exists: z.toast("卡槽QQ切换成功,继续执行") else: obj = self.slot.getSlotInfo( slotnum ) remark = obj['remark'] remarkArr = remark.split( "_" ) QQnumber = remarkArr[1] self.repo.BackupInfo( cate_id, 'frozen', QQnumber, '', '' ) # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber self.slot.clear( slotnum ) # 清空改卡槽,并补登 z.toast( "卡槽QQ状态异常,补登陆卡槽" ) self.action( d, z, args ) else: # 有空卡槽的情况 d.server.adb.cmd( "shell", "pm clear com.tencent.qqlite" ).communicate( ) # 清除缓存 d.server.adb.cmd("shell", "settings put global airplane_mode_on 1").communicate() d.server.adb.cmd("shell", "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true").communicate() z.sleep(3) d.server.adb.cmd("shell", "settings put global airplane_mode_on 0").communicate() d.server.adb.cmd("shell", "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false").communicate() z.heartbeat( ) z.toast( "正在ping网络是否通畅" ) while True: ping = d.server.adb.cmd( "shell", "ping -c 3 baidu.com" ).communicate( ) print( ping ) if 'icmp_seq' and 'bytes from' and 'time' in ping[0]: break z.sleep( 2 ) serialinfo = d.server.adb.device_serial( ) # print('登陆时的serial%s'%serialinfo) z.heartbeat( ) QQnumber = self.login( d, args, z ) if QQnumber == 'nothing': self.slot.clear( slotnum ) # 清空改卡槽,并补登 self.action( d, z, args ) elif QQnumber == 0: z.toast( "仓库为空,无法登陆。开始切换卡槽" ) self.qiehuan( d, z, args ) elif QQnumber is None: return else: z.heartbeat() featureCodeInfo = z.get_serial( "com.tencent.qqlite" ) print(featureCodeInfo) self.slot.backup( slotnum, str( slotnum ) + '_' + QQnumber + "_" + featureCodeInfo) # 设备信息,卡槽号,QQ号 self.repo.BackupInfo( cate_id, 'using', QQnumber, serialinfo, '%s_%s_%s' % ( d.server.adb.device_serial( ), self.type, slotnum) ) # 仓库号,使用中,QQ号,设备号_卡槽号 if (args["time_delay"]): time.sleep(int(args["time_delay"]))
class QQMailLogin: def __init__(self): self.repo = Repo() self.type = 'qqmail' def GetUnique(self): nowTime = datetime.datetime.now().strftime("%Y%m%d%H%M%S") # 生成当前时间 randomNum = random.randint(0, 1000) # 生成的随机整数n,其中0<=n<=100 if randomNum <= 10: randomNum = str(00) + str(randomNum) uniqueNum = str(nowTime) + str(randomNum) return uniqueNum def againLogin(self, account, password, d, z, height): if d(text="确定", className="android.widget.Button").exists or d( text="重新输入", className="android.widget.Button").exists: if d(text="确定", className="android.widget.Button").exists: d(text="确定", className="android.widget.Button").click() else: d(text="重新输入", className="android.widget.Button").click() time.sleep(1) self.input(z, height, password) time.sleep(1) if d(resourceId="com.tencent.androidqqmail:id/a_").exists: d(resourceId="com.tencent.androidqqmail:id/a_").click() time.sleep(8) while True: if d(textContains="验证中"): time.sleep(3) else: break if d(resourceId='com.tencent.androidqqmail:id/h' ).exists: # 判断是否要填写独立密码 self.input(z, height, "Abc" + account) z.sleep(1) if d(text='确定').exists: d(text='确定').click() z.sleep(5) while d(resourceId='com.tencent.androidqqmail:id/a16' ).exists: # 出现验证码 picObj = d(resourceId='com.tencent.androidqqmail:id/a19', index=0) code = self.palyCode(d, z, picObj) if code == "": return False if d(resourceId='com.tencent.androidqqmail:id/a17').exists: d(resourceId='com.tencent.androidqqmail:id/a17').click() self.input(z, height, code) if d(resourceId='com.tencent.androidqqmail:id/a_' ).exists: # 点击登陆 d(resourceId='com.tencent.androidqqmail:id/a_').click() z.sleep(8) if d(resourceId='com.tencent.androidqqmail:id/h' ).exists: # 判断是否要填写独立密码 self.input(z, height, "Abc" + account) z.sleep(1) if d(text='确定').exists: d(text='确定').click() while True: if d(textContains="验证中"): time.sleep(3) else: break if d(textContains='你有多个应用同时收到').exists: d(text='确定').click() z.sleep(2) if d(text='收件箱').exists: z.toast(u"登录成功。退出模块") # d.server.adb.cmd("shell", "am force-stop com.tencent.androidqqmail").wait() # 强制停止 return True else: if d(textContains='帐号或密码错误').exists: z.toast(u"帐号或密码错误") return False elif d(textContains="未开启IMAP服务").exists: z.toast(u"未开启IMAP服务,标记为异常") self.repo.BackupInfo(args["repo_account_id"], 'exception', account, '', '') # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber return False def input(self, z, height, text): if height > 888: z.input(text) else: z.cmd("shell", "am broadcast -a ZY_INPUT_TEXT --es text \\\"%s\\\"" % text) def palyCode(self, d, z, picObj): self.scode = smsCode(d.server.adb.device_serial()) base_dir = os.path.abspath( os.path.join(os.path.dirname(__file__), os.path.pardir, "tmp")) if not os.path.isdir(base_dir): os.mkdir(base_dir) sourcePng = os.path.join(base_dir, "%s_s.png" % (self.GetUnique())) codePng = os.path.join(base_dir, "%s_c.png" % (self.GetUnique())) icode = imageCode() im_id = "" code = "" for i in range(0, 2): # 打码循环 # if i > 0: # icode.reportError(im_id) obj = picObj.info obj = obj['bounds'] # 验证码处的信息 left = obj["left"] # 验证码的位置信息 top = obj['top'] right = obj['right'] bottom = obj['bottom'] d.screenshot(sourcePng) # 截取整个输入验证码时的屏幕 img = Image.open(sourcePng) box = (left, top, right, bottom) # left top right bottom region = img.crop(box) # 截取验证码的图片 img = Image.new('RGBA', (right - left, bottom - top)) img.paste(region, (0, 0)) img.save(codePng) with open(codePng, 'rb') as f: # file = f.read() file = "data:image/jpeg;base64," + base64.b64encode(f.read()) da = {"IMAGES": file} path = "/ocr.index" headers = { "Content-Type": "application/x-www-form-urlencoded", "Connection": "Keep-Alive" } conn = httplib.HTTPConnection("162626i1w0.51mypc.cn", 10082, timeout=30) params = urllib.urlencode(da) conn.request(method="POST", url=path, body=params, headers=headers) response = conn.getresponse() if response.status == 200: code = response.read() else: continue os.remove(sourcePng) os.remove(codePng) z.heartbeat() if code.isalpha() or code.isisdigitv() or code.isalnum(): break else: continue return code def login(self, d, z, args, accounts): try: d.server.adb.cmd( "shell", "pm clear com.tencent.androidqqmail").communicate() # 清除QQ邮箱缓存 d.server.adb.cmd( "shell", "am start -n com.tencent.androidqqmail/com.tencent.qqmail.LaunchComposeMail" ).communicate() # 拉起QQ邮箱 z.sleep(15) z.heartbeat() Str = d.info # 获取屏幕大小等信息 height = int(Str["displayHeight"]) width = int(Str["displayWidth"]) for x in range(2): if args['mail_type'] == '163邮箱登录': if d(resourceId='com.tencent.androidqqmail:id/ee' ).exists: # 选择163邮箱点击进入登陆页面 d(resourceId='com.tencent.androidqqmail:id/ee').click() z.sleep(1) break else: d.server.adb.cmd( "shell", "am start -n com.tencent.androidqqmail/com.tencent.qqmail.LaunchComposeMail" ).communicate() # 拉起QQ邮箱 z.sleep(25) continue if args['mail_type'] == 'QQ邮箱登录': if d(resourceId='com.tencent.androidqqmail:id/ea' ).exists: # 选择QQ邮箱点击进入登陆页面 d(resourceId='com.tencent.androidqqmail:id/ea').click() z.sleep(1) break else: d.server.adb.cmd( "shell", "am start -n com.tencent.androidqqmail/com.tencent.qqmail.LaunchComposeMail" ).communicate() # 拉起QQ邮箱 z.sleep(25) continue if args['mail_type'] == '腾讯企业邮箱登录': if d(resourceId='com.tencent.androidqqmail:id/eb' ).exists: # 选择腾讯企业邮箱登录点击进入登陆页面 d(resourceId='com.tencent.androidqqmail:id/eb').click() z.sleep(1) break else: d.server.adb.cmd( "shell", "am start -n com.tencent.androidqqmail/com.tencent.qqmail.LaunchComposeMail" ).communicate() # 拉起QQ邮箱 z.sleep(25) continue account = accounts[0]['number'] password = accounts[0]['password'] if d(text='帐号密码登录').exists: d(text='帐号密码登录').click() if d(resourceId='com.tencent.androidqqmail:id/bi' ).exists: # 输入邮箱帐号 d(resourceId='com.tencent.androidqqmail:id/bi').click() # self.input(z,height,account) self.input(z, height, account) else: return if d(resourceId='com.tencent.androidqqmail:id/bs' ).exists: # 输入邮箱密码 d(resourceId='com.tencent.androidqqmail:id/bs').click() self.input(z, height, password) if d(resourceId='com.tencent.androidqqmail:id/a_' ).exists: # 点击登录按钮 d(resourceId='com.tencent.androidqqmail:id/a_').click() z.sleep(20) while True: if d(textContains="验证中"): time.sleep(3) else: break if args['mail_type'] == 'QQ邮箱登录': if d(resourceId='com.tencent.androidqqmail:id/h' ).exists: # 判断是否要填写独立密码 self.input(z, height, "Abc" + account) z.sleep(1) if d(text='确定').exists: d(text='确定').click() z.sleep(5) while d(resourceId='com.tencent.androidqqmail:id/a16' ).exists: # 出现验证码 picObj = d(resourceId='com.tencent.androidqqmail:id/a19', index=0) code = self.palyCode(d, z, picObj) if code == "": return False if d(resourceId='com.tencent.androidqqmail:id/a17').exists: d(resourceId='com.tencent.androidqqmail:id/a17').click( ) self.input(z, height, code) if d(resourceId='com.tencent.androidqqmail:id/a_' ).exists: # 点击登陆 d(resourceId='com.tencent.androidqqmail:id/a_').click() z.sleep(8) if d(resourceId='com.tencent.androidqqmail:id/h' ).exists: # 判断是否要填写独立密码 self.input(z, height, "Abc" + account) z.sleep(1) if d(text='确定').exists: d(text='确定').click() if args['mail_type'] == '163邮箱登录': if d(resourceId='com.tencent.androidqqmail:id/a_' ).exists: # 点击完成按钮 d(resourceId='com.tencent.androidqqmail:id/a_').click() time.sleep(3) d.server.adb.cmd( "shell", "am force-stop com.tencent.androidqqmail").communicate( ) # 强制停止 d.server.adb.cmd( "shell", "am start -n com.tencent.androidqqmail/com.tencent.qqmail.LaunchComposeMail" ).communicate() # 拉起QQ邮箱 # z.sleep(3) # z.heartbeat() # d.server.adb.cmd("shell", "am force-stop com.tencent.androidqqmail").wait() # 强制停止163邮箱 # d.server.adb.cmd("shell", "am start -n com.tencent.androidqqmail/com.tencent.qqmail.LaunchComposeMail").communicate() # 拉起163邮箱 if args['mail_type'] == '腾讯企业邮箱登录': if d(resourceId='com.tencent.androidqqmail:id/a_' ).exists: # 点击登录按钮 d(resourceId='com.tencent.androidqqmail:id/a_').click() z.sleep(3) z.heartbeat() d.server.adb.cmd( "shell", "am force-stop com.tencent.androidqqmail").communicate( ) # 强制停止 d.server.adb.cmd( "shell", "am start -n com.tencent.androidqqmail/com.tencent.qqmail.LaunchComposeMail" ).communicate() # 拉起QQ邮箱 if d(text='收件箱').exists: z.toast(u"登录成功。退出模块") # d.server.adb.cmd( "shell", "am force-stop com.tencent.androidqqmail" ).wait( ) # 强制停止 return True else: return False # d.server.adb.cmd("shell", "am force-stop com.tencent.androidqqmail").wait() # 强制停止163邮箱 # d.server.adb.cmd("shell", "am start -n com.tencent.androidqqmail/com.tencent.qqmail.LaunchComposeMail").communicate() # 拉起163邮箱 z.sleep(12) z.heartbeat() if d(textContains='你有多个应用同时收到').exists: d(text='确定').click() z.sleep(2) if d(text='收件箱').exists: z.toast(u"登录成功。退出模块") # d.server.adb.cmd("shell", "am force-stop com.tencent.androidqqmail").wait() # 强制停止 return True else: return False except: logging.exception("exception") z.toast(u"程序出现异常,模块退出") d.server.adb.cmd( "shell", "am force-stop com.tencent.androidqqmail").wait() # 强制停止 return False def qiehuan(self, d, z, args): Str = d.info # 获取屏幕大小等信息 height = int(Str["displayHeight"]) width = int(Str["displayWidth"]) if args['mail_type'] == '163邮箱登录': self.type = '163mail' time_limit = int(args['slot_time_limit']) serial = d.server.adb.device_serial() self.slot = Slot(serial, self.type) slotObj = self.slot.getAvailableSlot(time_limit) # 没有空卡槽,取2小时没用过的卡槽 slotnum = None if not slotObj is None: slotnum = slotObj['id'] while slotObj is None: # 2小时没用过的卡槽也为没有的情况 d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"QQ卡槽全满,无间隔时间段未用\"" ).communicate() z.heartbeat() z.sleep(30) slotObj = self.slot.getAvailableSlot(time_limit) if not slotObj is None: slotnum = slotObj['id'] break z.heartbeat() d.server.adb.cmd( "shell", "pm clear com.tencent.androidqqmail").communicate() # 清除缓存 obj = self.slot.getSlotInfo(slotnum) remark = obj['remark'] remarkArr = remark.split("_") cateId = args['repo_account_id'] if len(remarkArr) == 3: slotInfo = d.server.adb.device_serial( ) + '_' + self.type + '_' + slotnum cateId = remarkArr[2] numbers = self.repo.Getserial(cateId, slotInfo) if len(numbers) != 0: featureCodeInfo = numbers[0]['imei'] z.set_serial("com.tencent.androidqqmail", featureCodeInfo) self.slot.restore(slotnum) # 有time_limit分钟没用过的卡槽情况,切换卡槽 z.sleep(2) d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"卡槽成功切换为" + slotnum + "号\"").communicate() z.sleep(2) d.server.adb.cmd( "shell", "am start -n com.tencent.androidqqmail/com.tencent.qqmail.LaunchComposeMail" ).communicate() # 拉起QQ邮箱 z.sleep(5) while d(textContains='正在更新数据').exists: z.sleep(2) z.sleep(20) z.heartbeat() d.dump(compressed=False) if d(text='密码错误,请重新输入').exists or d(description='QQ邮箱').exists: QQnumber = remarkArr[1] self.repo.BackupInfo(cateId, 'normal', QQnumber, '', '') # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber self.slot.clear(slotnum) # 清空改卡槽,并补登 z.toast("卡槽邮箱号状态异常,补登陆卡槽") return False else: z.toast("邮箱登陆状态正常,切换完毕。") return True def action(self, d, z, args): while True: # z.toast("正在ping网络是否通畅") # i = 0 # while i < 200: # i += 1 # ping = d.server.adb.cmd("shell", "ping -c 3 baidu.com").communicate() # # print(ping) # if 'icmp_seq' and 'bytes from' and 'time' in ping[0]: # z.toast(u"网络通畅。开始执行:" + args['mail_type'] + u" 有卡槽") # break # z.sleep(2) # if i > 200: # z.toast(u"网络不通,请检查网络状态") # return Str = d.info # 获取屏幕大小等信息 height = int(Str["displayHeight"]) width = int(Str["displayWidth"]) z.heartbeat() z.generate_serial("com.tencent.androidqqmail") # 随机生成手机特征码 d.server.adb.cmd( "shell", "su -c 'rm -r -f /storage/emulated/0/tencent/QQmail'" ) # 删除/storage/emulated/0/tencent/QQmail文件夹 time.sleep(2) if args['mail_type'] == '163邮箱登录': self.type = '163mail' accounts = self.repo.GetAccount(args['repo_account_id'], int(args['account_time_limit']), 1) # 去仓库获取QQ邮箱帐号 if len(accounts) == 0: z.toast(u"帐号库为空") # self.qiehuan( d, z, args ) serial = d.server.adb.device_serial() self.slot = Slot(serial, self.type) slotnum = self.slot.getEmpty() # 取空卡槽 if slotnum == 0 or len( accounts) == 0: # 没有空卡槽的话或者仓库没有可登陆的帐号,进行卡槽切换。 if self.qiehuan(d, z, args): break else: continue else: # 有空卡槽的情况 QQnumber = accounts[0]['number'] password = accounts[0]['password'] # print QQnumber if self.login(d, z, args, accounts): z.heartbeat() featureCodeInfo = z.get_serial("com.tencent.androidqqmail") self.slot.backup(slotnum, str(slotnum) + '_' + QQnumber + '_' + args["repo_account_id"]) # 设备信息,卡槽号,QQ号 self.repo.BackupInfo( args["repo_account_id"], 'using', QQnumber, featureCodeInfo, '%s_%s_%s' % (d.server.adb.device_serial(), self.type, slotnum)) # 仓库号,使用中,QQ号,设备号_卡槽号 break else: self.slot.clear(slotnum) # 清空改卡槽,并补登 if d(text='本次登录存在异常,如需帮助请前往安全中心').exists: z.toast(u"登录失败。重新登录") self.repo.BackupInfo(args["repo_account_id"], 'frozen', QQnumber, '', '') # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber elif d(textContains='帐号或密码错误').exists: z.toast(u"帐号或密码错误") againCount = int(args["againCount"]) for ac in range(againCount): result = self.againLogin(QQnumber, password, d, z, height) if result is True: # z.toast( "跳出模块" ) return else: z.toast(u"一直登陆出现密码错误,跳出该帐号") # self.repo.BackupInfo(args["repo_account_id"], 'frozen', QQnumber, '', '') # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber elif d(textContains="未开启IMAP服务").exists: z.toast(u"未开启IMAP服务,标记为异常") self.repo.BackupInfo(args["repo_account_id"], 'exception', QQnumber, '', '') # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber else: self.repo.BackupInfo(args["repo_account_id"], 'normal', QQnumber, '', '') # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber continue
class MobilqqLogin3: def __init__(self): self.type = 'mobileqq' self.repo = Repo() self.codedll = codeDLL() def GetUnique(self): nowTime = datetime.datetime.now().strftime("%Y%m%d%H%M%S") # 生成当前时间 randomNum = random.randint(0, 1000) # 生成的随机整数n,其中0<=n<=100 if randomNum <= 10: randomNum = str(00) + str(randomNum) uniqueNum = str(nowTime) + str(randomNum) return uniqueNum def WebViewBlankPages(self, d, z): z.toast("判断是否是滑块") Str = d.info # 获取屏幕大小等信息 height = float(Str["displayHeight"]) width = float(Str["displayWidth"]) W_H = width / height screenScale = round(W_H, 2) base_dir = os.path.abspath( os.path.join(os.path.dirname(__file__), os.path.pardir, "tmp")) if not os.path.isdir(base_dir): os.mkdir(base_dir) sourcePng = os.path.join(base_dir, "%s_s.png" % (self.GetUnique())) if screenScale == 0.56: left = 115 # 验证码的位置信息 top = 670 right = 185 bottom = 720 if screenScale == 0.61: left = 115 # 验证码的位置信息 top = 670 right = 185 bottom = 720 d.screenshot(sourcePng) # 截取整个输入验证码时的屏幕 img = Image.open(sourcePng) box = (left, top, right, bottom) # left top right bottom region = img.crop(box) # 截取验证码的图片 # show(region) #展示资料卡上的信息 image = region.convert('RGBA') # 生成缩略图,减少计算量,减小cpu压力 image.thumbnail((200, 200)) max_score = None dominant_color = None for count, (r, g, b, a) in image.getcolors(image.size[0] * image.size[1]): # 跳过纯黑色 if a == 0: continue saturation = colorsys.rgb_to_hsv(r / 255.0, g / 255.0, b / 255.0)[1] y = min( abs(r * 2104 + g * 4130 + b * 802 + 4096 + 131072) >> 13, 235) y = (y - 16.0) / (235 - 16) # 忽略高亮色 if y > 0.9: continue score = (saturation + 0.1) * count if score > max_score: max_score = score dominant_color = (r, g, b) # 红绿蓝 return dominant_color def WebViewPlayCode(self, d, z): z.toast("非空白页,开始截图打码") Str = d.info # 获取屏幕大小等信息 height = float(Str["displayHeight"]) width = float(Str["displayWidth"]) W_H = width / height screenScale = round(W_H, 2) base_dir = os.path.abspath( os.path.join(os.path.dirname(__file__), os.path.pardir, "tmp")) if not os.path.isdir(base_dir): os.mkdir(base_dir) sourcePng = os.path.join(base_dir, "%s_s.png" % (self.GetUnique())) icode = imageCode() im_id = "" for i in range(0, 1): # 打码循环 if i > 0: icode.reportError(im_id) d.screenshot(sourcePng) # 截取整个输入验证码时的屏幕 if screenScale == 0.61: p = { "x1": 30 / width, "y1": 200 / height, "x2": 271 / width, "y2": 300 / height } if screenScale == 0.56: p = { "x1": 40 / width, "y1": 270 / height, "x2": 362 / width, "y2": 400 / height } cropedImg = z.img_crop(sourcePng, p) im = open(cropedImg, 'rb') codeResult = icode.getCode(im, icode.CODE_TYPE_4_NUMBER_CHAR, 60) code = codeResult["Result"] im_id = codeResult["Id"] os.remove(sourcePng) z.heartbeat() z.sleep(5) if screenScale == 0.61: d.click(360, 240) if screenScale == 0.56: d.click(500, 350) z.input(code) z.sleep(2) if screenScale == 0.61: d.click(270, 450) if screenScale == 0.56: d.click(360, 600) while d(className='android.widget.ProgressBar', index=0).exists: # 网速不给力时,点击完成后仍然在加载时的状态 z.sleep(2) z.sleep(8) if not d(textContains='验证码').exists: z.toast("机器人打码跳出--") break # def playCode(self, codeImgObj, type): # z.toast("非网页视图打码") # self.scode = smsCode(d.server.adb.device_serial()) # base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir, "tmp")) # if not os.path.isdir(base_dir): # os.mkdir(base_dir) # sourcePng = os.path.join(base_dir, "%s_s.png" % (self.GetUnique())) # codePng = os.path.join(base_dir, "%s_c.png" % (self.GetUnique())) # icode = imageCode() # im_id = "" # for i in range(0, 4): # 打码循环 # if i > 0: # icode.reportError(im_id) # obj = d(resourceId='com.tencent.mobileqq:id/name', # className='android.widget.ImageView') # 当弹出选择QQ框的时候,定位不到验证码图片 # if not obj.exists: # obj = d(index='2', className='android.widget.Image') # obj = obj.info # obj = obj['bounds'] # 验证码处的信息 # left = obj["left"] # 验证码的位置信息 # top = obj['top'] # right = obj['right'] # bottom = obj['bottom'] # # d.screenshot(sourcePng) # 截取整个输入验证码时的屏幕 # # img = Image.open(sourcePng) # box = (left, top, right, bottom) # left top right bottom # region = img.crop(box) # 截取验证码的图片 # # img = Image.new('RGBA', (right - left, bottom - top)) # img.paste(region, (0, 0)) # # img.save(codePng) # # with open(codePng, 'rb') as im: # codeResult = icode.getCode(im, icode.CODE_TYPE_4_NUMBER_CHAR, 60) # # code = codeResult["Result"] # im_id = codeResult["Id"] # os.remove(sourcePng) # os.remove(codePng) # z.heartbeat() # z.sleep(5) # if type == 0: # d(resourceId='com.tencent.mobileqq:id/name', index='2', # className="android.widget.EditText").set_text(code) # else: # codeImgObj.set_text(code) # z.sleep(3) # if d(descriptionContains='验证', className='android.view.View').exists: # d(descriptionContains='验证', className='android.view.View').click() # else: # d(text='完成', resourceId='com.tencent.mobileqq:id/ivTitleBtnRightText').click() # z.sleep(6) # z.heartbeat() # while d(className='android.widget.ProgressBar', index=0).exists: # 网速不给力时,点击完成后仍然在加载时的状态 # z.sleep(2) # z.sleep(3) # z.heartbeat() # if codeImgObj.exists: # continue # else: # break # z.sleep(5) # if d(textContains='验证码').exists: # return False # else: # return True def login(self, d, args, z, numbers): QQNumber = numbers[0]['number'] # 即将登陆的QQ号 QQPassword = numbers[0]['password'] z.heartbeat() d.server.adb.cmd("shell", "pm clear com.tencent.mobileqq").communicate() # 清除缓存 d.server.adb.cmd( "shell", "am start -n com.tencent.mobileqq/com.tencent.mobileqq.activity.SplashActivity" ).communicate() # 拉起来 z.sleep(5) while d(textContains='正在更新数据').exists: z.sleep(2) z.sleep(15) z.heartbeat() d.dump(compressed=False) if d(text='登 录', resourceId='com.tencent.mobileqq:id/btn_login').exists: d(text='登 录').click() z.sleep(1) d(className='android.widget.EditText', index=0).click() # 1918697054----xiake1234. QQNumber z.input(QQNumber) z.sleep(1) d(resourceId='com.tencent.mobileqq:id/password').click( ) # Bn2kJq5l QQPassword z.input(QQPassword) z.heartbeat() print('QQ号:%s,QQ密码:%s' % (QQNumber, QQPassword)) d.dump(compressed=False) d(text='登 录', resourceId='com.tencent.mobileqq:id/login').click() z.sleep(3) while d(text='登录中').exists: z.sleep(2) z.sleep(20) z.heartbeat() detection_robot = d(index='3', className="android.widget.EditText") not_detection_robot = d(resourceId='com.tencent.mobileqq:id/name', index='2', className="android.widget.EditText") if detection_robot.exists: # 需要验证码的情况 if not self.playCode(detection_robot, 1): return False if not_detection_robot.exists: if not self.playCode(not_detection_robot.exists, 0) == "nothing": return False if d(className='android.webkit.WebView').exists: if self.WebViewBlankPages(d, z)[2] < 200: self.WebViewPlayCode(d, z) else: y = 555 for r in range(1, 3): d.swipe(155, 703, y, 703) z.sleep(2) if not d(text='验证码', resourceId='com.tencent.mobileqq:id/ivTitleName' ).exists: break else: y += 20 if d(text='验证码', resourceId='com.tencent.mobileqq:id/ivTitleName' ).exists or d(text='去安全中心').exists: self.repo.BackupInfo(args["repo_cate_id"], 'frozen', QQNumber, '', '') # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber return False z.sleep(5) z.heartbeat() loginStatusList = z.qq_getLoginStatus(d) if loginStatusList is None: if d(text='消息').exists and d(text='联系人').exists and d( text='动态').exists: loginStatusList = {'success': True} elif d(textContains="请在小米神隐模式中将TIM设置为“无限制”。").exists: z.toast("我是小米神隐") d(text='我知道了').click() else: loginStatusList = {'success': False} loginStatus = loginStatusList['success'] if loginStatus: z.toast("卡槽QQ状态正常,继续执行") return True else: if d(text='去安全中心').exists: self.repo.BackupInfo(args["repo_cate_id"], 'frozen', QQNumber, '', '') # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber else: self.repo.BackupInfo(args["repo_cate_id"], 'normal', QQNumber, '', '') z.toast("卡槽QQ状态异常,跳过此模块") return False # if d(text='马上绑定').exists: # self.BindAddressBook(z, d, args) def qiehuan(self, d, z, args): time_limit = int(args['time_limit']) serial = d.server.adb.device_serial() self.slot = Slot(serial, self.type) slotObj = self.slot.getAvailableSlot(time_limit) # 没有空卡槽,取2小时没用过的卡槽 slotnum = None if not slotObj is None: slotnum = slotObj['id'] while slotObj is None: # 2小时没用过的卡槽也为没有的情况 d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"QQ卡槽全满,无间隔时间段未用\"" ).communicate() z.heartbeat() z.sleep(30) slotObj = self.slot.getAvailableSlot(time_limit) if not slotObj is None: slotnum = slotObj['id'] break z.heartbeat() d.server.adb.cmd("shell", "pm clear com.tencent.mobileqq").communicate() # 清除缓存 d.server.adb.cmd( "shell", "settings put global airplane_mode_on 1").communicate() # 开飞行模式 d.server.adb.cmd( "shell", "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true" ).communicate() z.sleep(6) z.heartbeat() d.server.adb.cmd( "shell", "settings put global airplane_mode_on 0").communicate() # 关飞行模式 d.server.adb.cmd( "shell", "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false" ).communicate() z.heartbeat() while True: ping = d.server.adb.cmd("shell", "ping -c 3 baidu.com").communicate() print(ping) if 'icmp_seq' and 'bytes from' and 'time' in ping[0]: break z.sleep(2) obj = self.slot.getSlotInfo(slotnum) remark = obj['remark'] remarkArr = remark.split("_") cateId = "" if len(remarkArr) == 3: slotInfo = d.server.adb.device_serial( ) + '_' + self.type + '_' + slotnum cateId = remarkArr[2] numbers = self.repo.Getserial(cateId, slotInfo) if len(numbers) != 0: featureCodeInfo = numbers[0]['imei'] z.set_serial("com.tencent.mobileqq", featureCodeInfo) self.slot.restore(slotnum) # 有time_limit分钟没用过的卡槽情况,切换卡槽 z.sleep(2) d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"卡槽成功切换为" + slotnum + "号\"").communicate() z.sleep(2) d.server.adb.cmd( "shell", "am start -n com.tencent.mobileqq/com.tencent.mobileqq.activity.SplashActivity" ).communicate() # 拉起来 z.sleep(5) while d(textContains='正在更新数据').exists: z.sleep(2) z.sleep(15) z.heartbeat() loginStatusList = z.qq_getLoginStatus(d) if loginStatusList is None: if d(text='消息').exists and d(text='联系人').exists and d( text='动态').exists: loginStatusList = {'success': True} elif d(textContains="请在小米神隐模式中将TIM设置为“无限制”。").exists: z.toast("我是小米神隐") d(text='我知道了').click() loginStatusList = {'success': True} else: z.toast("登陆新场景,现无法判断登陆状态") loginStatusList = {'success': False} loginStatus = loginStatusList['success'] if loginStatus: z.toast("卡槽QQ状态正常,继续执行") return True else: QQnumber = remarkArr[1] if d(text='去安全中心').exists: self.repo.BackupInfo(cateId, 'frozen', QQnumber, '', '') # 仓库号,使用中,QQ号,设备号_卡槽号QQNumber else: self.repo.BackupInfo(cateId, 'normal', QQnumber, '', '') self.slot.clear(slotnum) # 清空改卡槽,并补登 z.toast("卡槽QQ状态异常,补登陆卡槽") return False def action(self, d, z, args): while True: z.toast("正在ping网络是否通畅") i = 0 while i < 200: i += 1 ping = d.server.adb.cmd("shell", "ping -c 3 baidu.com").communicate() print(ping) if 'icmp_seq' and 'bytes from' and 'time' in ping[0]: z.toast("网络通畅。开始执行:普通QQ登录有卡槽") break z.sleep(2) if i > 200: z.toast("网络不通,请检查网络状态") if (args["time_delay"]): z.sleep(int(args["time_delay"])) return z.heartbeat() z.generate_serial("com.tencent.mobileqq") # 随机生成手机特征码 cate_id = args["repo_cate_id"] time_limit1 = args['time_limit1'] numbers = self.repo.GetAccount(cate_id, time_limit1, 1) if len(numbers) == 0: d.server.adb.cmd( "shell", "am broadcast -a com.zunyun.zime.toast --es msg \"QQ帐号库%s号仓库无%s分钟未用,开始切换卡槽\"" % (cate_id, time_limit1)).communicate() serial = d.server.adb.device_serial() self.slot = Slot(serial, self.type) slotnum = self.slot.getEmpty() # 取空卡槽 if slotnum == 0 or len(numbers) == 0: #没有空卡槽的话 if self.qiehuan(d, z, args): break else: # 有空卡槽的情况 d.server.adb.cmd( "shell", "pm clear com.tencent.mobileqq").communicate() # 清除缓存 d.server.adb.cmd( "shell", "settings put global airplane_mode_on 1").communicate() d.server.adb.cmd( "shell", "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true" ).communicate() z.sleep(6) d.server.adb.cmd( "shell", "settings put global airplane_mode_on 0").communicate() d.server.adb.cmd( "shell", "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false" ).communicate() z.heartbeat() while True: ping = d.server.adb.cmd( "shell", "ping -c 3 baidu.com").communicate() print(ping) if 'icmp_seq' and 'bytes from' and 'time' in ping[0]: break z.sleep(2) z.heartbeat() if self.login(d, args, z, numbers): z.heartbeat() featureCodeInfo = z.get_serial("com.tencent.mobileqq") self.slot.backup(slotnum, str(slotnum) + '_' + numbers[0]['number'] + '_' + cate_id) # 设备信息,卡槽号,QQ号 self.repo.BackupInfo( cate_id, 'using', numbers[0]['number'], featureCodeInfo, '%s_%s_%s' % (d.server.adb.device_serial(), self.type, slotnum)) # 仓库号,使用中,QQ号,设备号_卡槽号 break if args["time_delay"]: z.sleep(int(args["time_delay"]))
"x2": 502 / width, "y2": 473 / height } z.img_crop(source, p) out = d.server.adb.run_cmd('shell', 'ls') z.input("xxx") # d.server.adb.cmd("shell", "ime set com.zunyun.zime/.ZImeService").communicate() z.server.install() slot = Slot('cda0ae8d', 'mobileqq') print(slot.getSlots()) slot.backup('21', '22221111') print(slot.getSlots()) slot.clear('21') z.generateSerial() #z.input("6565wv=1027&k=48KHKLm") #d.server.adb.cmd("shell", "am", "start", "-a", "zime.clear.contacts").communicate() d.server.adb.cmd("shell", "pm clear com.android.providers.contacts").communicate() #d.server.adb.cmd("push", filename, "/data/local/tmp/contacts.txt").communicate() d.server.adb.cmd("shell", "am", "start", "-n", "com.zunyun.zime/.ImportActivity", "-t", "text/plain", "-d", "/data/local/tmp/contacts.txt").communicate() # d.dump(compressed=False) args = {