-- coding: utf-8 --
㊎ Author : XMZ
㊍ Time : 2023/11/26 13:30
㊌ File : android-adb->dy_automation.py
㊋ IDE : PyCharm
㊏ REMARKS:
import re
import os
import time
import cv2
import sys
import jieba
import base64
import random
import logging
import subprocess
import pytesseract
from PIL import Image
self_path = os.path.dirname(os.path.abspath(__file__))
father_path = os.path.dirname(self_path)
parent_path = os.path.dirname(father_path)
sys.path.append(self_path)
sys.path.append(father_path)
sys.path.append(parent_path)
from SystemEnvConfiguration.loger import LogGer
from SystemEnvConfiguration.plugins import requester
class DouyinAuto(object):
"""
#启动命令
adb shell am start -n com.ss.android.ugc.aweme/.main.MainActivity
"""
LogGer(str(os.path.basename(__file__))[:-3])
def __init__(self):
try:
adb_output = subprocess.check_output("adb devices", shell=True, text=True)
info = adb_output.split("attached\n")[1].strip().split("\t")[0]
logging.info(f"已连接设备:{info}")
except subprocess.CalledProcessError:
logging.info("没有连接的设备")
sys.exit()
self.package_name = "com.ss.android.ugc.aweme"
self.access_token = "xxxxxx"
def get_version(self) -> str:
"""
获取软件信息
:return:26.4.0
"""
adb_command = f"adb shell dumpsys package {self.package_name}"
try:
adb_output = subprocess.check_output(adb_command, shell=True, text=True)
version_info = None
for line in adb_output.splitlines():
if "versionName=" in line:
version_info = line.split("=")[1]
break
return version_info
except subprocess.CalledProcessError:
return "0.0.0"
@staticmethod
def get_hardware_info():
"""
获取机器的硬件信息
:return: Hisilicon Kirin985
"""
adb_command = "adb shell cat /proc/cpuinfo"
try:
adb_output = subprocess.check_output(adb_command, shell=True, text=True)
hardware_info = adb_output.split("\nHardware", 1)[1].strip().replace(': ', '')
return hardware_info
except subprocess.CalledProcessError:
return '0'
@staticmethod
def get_mm_size():
command = "adb shell wm size"
try:
mm_size = subprocess.check_output(command, shell=True, text=True).strip()
size = mm_size.split(":", 1)[1].split('x')
keys = ['x', 'y']
numeric_values = [int(value.strip()) for value in size]
result_dict = dict(zip(keys, numeric_values))
return result_dict
except subprocess.CalledProcessError:
return {'x': 1200, 'y': 2000}
@staticmethod
def get_android_version():
"""
获取android版本信息
:return:
"""
adb_command = "adb shell getprop ro.build.version.release"
try:
android_version = subprocess.check_output(adb_command, shell=True, text=True).strip()
return android_version
except subprocess.CalledProcessError:
return '0'
def print_info(self):
logging.info(f"获取APP版本号:{self.get_version()}")
logging.info(f"获取硬件信息:{self.get_hardware_info()}")
logging.info(f"获取android版本:Android {self.get_android_version()}")
def start_app(self):
"""
启动APP
:return:
"""
command = "adb shell am start -n com.ss.android.ugc.aweme/.main.MainActivity"
try:
output = subprocess.check_output(command, shell=True, text=True)
time.sleep(5)
return output.strip()
except subprocess.CalledProcessError as e:
logging.error(f"启动APP执行命令时出错: {command}")
logging.error(e.output)
return None
def slide(self, frequency=1, sleep_time=1):
"""
滑动
:return:
"""
for i in range(frequency):
start_x, start_y = random.randint(750, 950), random.randint(1480, 1615)
end_x, end_y = random.randint(900, 1000), random.randint(1000, 1100)
duration = random.randint(100, 200)
adb_command = f'adb shell input swipe {start_x} {start_y} {end_x} {end_y} {duration}'
try:
subprocess.run(adb_command, shell=True, check=True)
print(f"Screen swiped from ({start_x}, {start_y}) to ({end_x}, {end_y}) in {duration} milliseconds.")
except subprocess.CalledProcessError as e:
print(f"Error executing command: {adb_command}")
print(e.output)
time.sleep(sleep_time)
def capture_screen(self, retry=3):
"""
截图
:return:
"""
try:
filename = "Pictures/Screenshots/adb_screenshot.png"
adb_command = f'adb shell screencap -p /sdcard/{filename}'
subprocess.run(adb_command, shell=True, check=True)
except subprocess.CalledProcessError:
return None if retry == 0 else self.capture_screen(retry - 1)
def pull_screenshot(self, retry=3):
"""
使用adb pull命令将设备上的截图拉取到计算机上
:return:
"""
try:
filename = "Pictures/Screenshots/adb_screenshot.png"
adb_command = f'adb pull /sdcard/{filename} {self_path}'
subprocess.run(adb_command, shell=True, check=True)
except subprocess.CalledProcessError:
return None if retry == 0 else self.pull_screenshot(retry - 1)
def ocr_screen(self):
"""
裁剪图片
左上角坐标(left, top):(0, 1000)
右下角坐标(right, bottom):(1200, 2000)
:return:
"""
left, top = 10, 1500
right, bottom = 1097, 1900
image = Image.open('adb_screenshot.png')
img_cropped = image.crop((left, top, right, bottom))
img_cropped.save('screenshot_cropped.png')
def general_basic(self):
"""
百度OCR :general_basic,5W
:return:
"""
_url = f"https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic?access_token={self.access_token}"
headers = {'content-type': 'application/x-www-form-urlencoded'}
f = open('screenshot_cropped.png', 'rb')
img = base64.b64encode(f.read())
params = {"image": img}
response = requester(url=_url, method="post", headers=headers, data=params).json()
words_result = response.get("words_result")
words = [key.get("words") for key in words_result]
chinese_characters = re.findall(r'[\u4e00-\u9fff]+', "".join(words))
words_ = ','.join(jieba.cut_for_search(''.join(chinese_characters))).split(',')
return words_
def determine_keywords(self):
"""
判断关键字,是否评论
:return:
"""
self.capture_screen()
self.pull_screenshot()
self.ocr_screen()
words = self.general_basic()
keyword = "旗袍/爱看/擦边/穿衣自由/黑丝/甜妹/短裙/黄色/后妈/模特/实名/观看/丰满/碎花/男友/视角/反差/小妈/变装/性感/大长/长腿/腿/御姐/极品/身材/马甲/辣妹/美女/纯欲/艾特/jk/制服/不良/战袍/腰臀/热舞/少女/顶得住/制服".split(
'/')
common_elements = [word for word in words if word in keyword]
logging.info(f"百度识别关键词:{words}")
logging.info(f"自定义关键词:{keyword}")
logging.info(f"匹配到关键词:{common_elements}")
return common_elements if common_elements else False
def click_on(self):
"""
点击评论按钮
:return:
"""
logging.info("触发评论")
os.system('adb shell ime set com.android.adbkeyboard/.AdbIME')
x, y = 1139, 1425
os.system(f'adb shell input tap {x} {y}')
logging.info('点击评论按钮完成!')
time.sleep(0.5)
self.slide(random.randint(1, 3), random.randint(1, 3))
start_x, start_y = random.randint(100, 300), random.randint(1929, 1964)
os.system(f'adb shell input tap {start_x} {start_y}')
logging.info('点击输入框完成!')
time.sleep(1)
start_x, start_y = random.randint(150, 300), random.randint(1810, 1875)
os.system(f'adb shell input tap {start_x} {start_y}')
logging.info('二次点击输入框完成!')
time.sleep(1)
expression = ['[比心]', '[送心]', '[赞]', '[爱心]', '[玫瑰]', '[看]', '[干饭人]']
text = random.choice(expression) * random.randint(1, 4)
os.system(f"adb shell am broadcast -a ADB_INPUT_TEXT --es msg '{text}'")
logging.info(f'内容输入完成:{text}')
time.sleep(1)
start_x, start_y = random.randint(1085, 1155), random.randint(1837, 1888)
os.system(f'adb shell input tap {start_x} {start_y}')
logging.info('点击发送完成!')
time.sleep(0.5)
os.system(f'adb shell input tap {random.randint(300, 700)} {random.randint(280, 460)}')
def main_logic(self):
"""
串联完整进程
:return:
"""
self.start_app()
self.print_info()
random_number = random.randint(30, 100)
for _ in range(random_number):
result = self.determine_keywords()
logging.info(f"未匹配关键词:{result}") if result is False else None
if result:
time.sleep(random.randint(6, 12))
self.click_on() if random.randint(1, 10) == 8 else logging.info("未触发评论")
self.slide()
logging.info(f"总次数:{random_number},已完成次数:{_}")
def __del__(self):
time.sleep(1)
os.system('adb shell ime set com.baidu.input_hihonor/com.baidu.input_huawei.ImeService')
time.sleep(1)
os.system(f'adb shell am force-stop {self.package_name}')
if __name__ == '__main__':
dy = DouyinAuto()
dy.main_logic()