import os
import re
import time
from appium import webdriver
import uiautomator2 as u2
import logging
import subprocess
from datetime import datetime
import queue
import threading
import random
now = datetime.now()
# logging.basicConfig(level = logging.INFO,format = '%(asctime)s - %(name)s - %(funcName)s - %(message)s')
# logger = logging.getLogger(__name__)
# logger.info(d)
log_path = r'./log'
img_path = r'./img_screen'
titles_dir = './device_title'
os.makedirs(titles_dir,exist_ok=True)
os.makedirs(log_path,exist_ok=True)
os.makedirs(img_path,exist_ok=True)
def get_current_time():
return str(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())+' : ')
def append_file(d_sn,content):
with open(os.path.join(log_path,f'{d_sn}.txt'),"a",encoding='utf-8') as f:
f.write(f'{get_current_time()} {content}')
f.write('\n')
def append_title_file(file,content):
with open(file,"a",encoding='utf-8') as f:
f.write(content)
f.write('\n')
def get_devices():
s_d = ''
devices_info = os.popen('adb devices').readlines()
for i in range(len(devices_info)):
s_d+=devices_info[i]
device_sn = re.findall('\n(.+?)\t',s_d,re.S)
return device_sn
devices = get_devices()
def clean_screen_shots(driver,flag=True):
screen_files = run_adb(f'adb -s {driver.serial} shell ls /sdcard/DCIM/Screenshots').split('\r\n')
print('screen_files:',screen_files)
for f in screen_files:
if not len(f) > 0 :continue
run_adb(f'adb -s {driver.serial} shell rm -f /sdcard/DCIM/Screenshots/{f}')
# run_adb(f'adb -s {device} shell am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d file:///sdcard/DCIM/Screenshots/*.png')
time.sleep(1)
run_adb(f'adb -s {driver.serial} shell am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d file:///sdcard/DCIM/Screenshots/{f}')
time.sleep(1)
if flag:
driver.app_stop('com.smile.gifmaker')
# 判断屏幕是否锁屏,如果屏幕锁定就解锁
def get_screen_status(device):
status = device.info['screenOn']
if not status:
device.screen_on()
device.swipe_ext('up',scale=0.9)
return status
def run_adb(cmd):
process = subprocess.Popen(cmd.split(),stdout=subprocess.PIPE)
output ,error = process.communicate()
print(output,error)
return output.decode('utf-8')
def click_(driver,element='',text_='',resourceId_='', content='',error_path='',pkg='com.smile.gifmaker',sleepTime=3):
try:
if str(element).startswith("com"): # 若开头是com则使用ID定位
driver(resourceId=element).click() # 点击定位元素
elif re.findall("//", str(element)): # 若//开头则使用正则表达式匹配后用xpath定位
driver.xpath(element).click() # 点击定位元素
elif text_: # 若以上两种情况都不是,则使用描述定位
driver(text=text_).click() # 点击定位元素
elif resourceId_:
driver(resourceId=resourceId_).click()
else:
print('***********无操作************')
if content:
append_file(driver.serial,content)
time.sleep(sleepTime)
driver.implicitly_wait(15)
except Exception as e:
append_file(driver.serial,'异常中断本次商品发布' + content)
if error_path:
driver.screenshot(f'{error_path}/error_{content}.png')
time.sleep(sleepTime)
clean_screen_shots(driver,flag=True)
driver.app_stop(pkg)
# 点击详情图片,然后根据图片张数进行截图,并保存至/DCIM
def img_info_screen_shot(driver,s_title,current_index):
# 获取大图上面的图片index
img_info = driver(textContains='/').get_text().split('/')
left_step = int(img_info[1]) - int(img_info[0])
print(img_info,left_step)
# 每次截图前先讲Screenshots下的图片清空
if int(img_info[1]) ==1:
pass
else:
for j in range(int(img_info[0])):#将图片滑到第一张
driver.swipe_ext('right',scale=0.9)
time.sleep(2)
current_time = time.strftime('%Y_%m_%d_%H_%M_%S', time.localtime())
img_path_tmp =f'{img_path}/{driver.serial}/{current_time}_{current_index}'
title_file_tmp = f'{img_path}/{driver.serial}/{current_time}_{current_index}/{driver.serial}_title_{current_index}.txt'
os.makedirs(img_path_tmp,exist_ok=True)
append_title_file(title_file_tmp,s_title)
img_counts = driver(textContains='/').get_text().split('/')[-1] # 获取商品详情总共图片张数
append_file(driver.serial,f'Step 10 : 当前商品张数:{img_counts}')
for i in range(int(img_info[1])):
tt = time.time()
timestamp = int(round(tt * 1000))
time.sleep(1)
current_element = driver(textContains='/').get_text().split('/')
print('timestamp',current_element)
driver.screenshot(f'{img_path_tmp}/{timestamp}_{i+1}.png')
# append_file(device,f'{get_current_time()}当前商品截图title:{current_element}')
time.sleep(1)
append_file(driver.serial,f'Step 11 : 当前商品截图:{timestamp}_{i+1}.png')
time.sleep(1)
run_adb(f'adb -s {driver.serial} push {img_path_tmp}/{timestamp}_{i+1}.png /sdcard/DCIM/Screenshots')
time.sleep(1)
driver.swipe_ext('left',scale=0.9)
time.sleep(2)
# 截图后发送广播更新相册
run_adb(f'adb -s {driver.serial} shell am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d file:///sdcard/DCIM/Screenshots/{timestamp}_{i+1}.png')
# d.xpath('//android.app.Dialog/android.view.View[1]/android.view.View[1]/android.view.View[1]/android.view.View[1]/android.view.View[1]/android.view.View[4]').click()
driver.press("back")
# 刷新商品列表至最顶部
# driver.xpath('//*[@text="在售 "]').click()
click_(driver,element='//*[@text="在售 "]',content='Step 12 : 双击在售',error_path=img_path_tmp)
click_(driver,element='//*[@text="在售 "]',content='Step 12 : 双击在售',error_path=img_path_tmp)
# append_file(device,f'双击在售',12)
time.sleep(8)
driver.click(0.889, 0.377)
time.sleep(2)
# driver(text='拍短视频').click()
if not driver(text='拍短视频').exists():
driver.click(0.163, 0.056)#点空白处,隐藏弹框
time.sleep(1)
driver.click(0.856, 0.532)# 点击第二个item
time.sleep(1)
driver.click(0.494, 0.63)# 点击拍短视频按钮
append_file(driver.serial,'Step 13-1 : 拍短视频')
# click_(driver,text='拍短视频',content='Step 13-1 : 拍短视频')
else:
click_(driver,text_='拍短视频',content='Step 13 : 拍短视频',error_path=img_path_tmp)
# append_file(device,f'拍短视频',13)
time.sleep(2)
# driver(text='模板').click()
click_(driver,text_='模板',content='Step 14 : 选择模板',error_path=img_path_tmp)
# append_file(device,f'选择模板',14)
time.sleep(2)
# 收藏的模板
# driver(text='收藏').click()
click_(driver,text_='收藏',content='Step 15 : 选择收藏模板',error_path=img_path_tmp)
# append_file(device,f'选择收藏模板',15)
# d.xpath('//*[@resource-id="com.smile.gifmaker:id/ks_root_view"]/android.widget.HorizontalScrollView[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]').click(0)
time.sleep(1)
r = random.randint(1, 10)
# 随机选择模板
for s_r in range(r):
driver.swipe_ext('up',scale=0.5)
# driver(text='使用').click()
click_(driver,text_='使用',content=f'Step 16 : 选择收藏的模板,drag {r} 次',error_path=img_path_tmp)
# append_file(device,f'选择收藏的模板,drag {r} 次',16)
# driver.xpath(f'//*[@resource-id="com.smile.gifmaker:id/recycler_view"]/android.widget.RelativeLayout[{r}]/android.widget.RelativeLayout[1]').click()# 第一个收藏的模板
# d.swipe_ext('down',scale=0.9)
time.sleep(3)
driver.implicitly_wait(15)
# append_file(device,'Step 17 : 开始制作 - 开始选择图片')
# driver(text='开始制作').click()
click_(driver,text_='开始制作',content='Step 17 : 开始制作 - 开始选择图片',error_path=img_path_tmp)
print('需要截图张数:',img_counts,s_title)
# 根据截图数量选择图片
# //*[@resource-id="com.smile.gifmaker:id/album_view_list"]/android.widget.FrameLayout[6]
for c_i in range(int(img_counts)):
# driver.xpath(f'//*[@resource-id="com.smile.gifmaker:id/album_view_list"]/android.widget.FrameLayout[{c_i+1}]').click()
click_(driver,element=f'//*[@resource-id="com.smile.gifmaker:id/album_view_list"]/android.widget.FrameLayout[{c_i+1}]',content=f'Step 18 : 选择第 {c_i+1} 张图片',error_path=img_path_tmp)
# append_file(device,f'Step 18 : 选择第 {c_i+1} 张图片')
time.sleep(1)
# 选好图片后确认
time.sleep(2)
# append_file(device,'选好了',19)
# driver(resourceId="com.smile.gifmaker:id/right_container").click()# 选好了
click_(driver,resourceId_="com.smile.gifmaker:id/right_container",content='Step 18 : 选好了',sleepTime=15,error_path=img_path_tmp)
# time.sleep(10)
if not driver(text="下一步").exists():
append_file(driver.serial,'Step 19 : 下一步 控件没有找到,请检查资源是否违规')
return
# append_file(device,'Step 18 : 下一步',20)
# driver(text='下一步').click()
click_(driver,text_='下一步',content='Step 20 : 下一步',error_path=img_path_tmp)
time.sleep(1)
driver.xpath('//*[@resource-id="com.smile.gifmaker:id/editor_container"]').set_text(f'{s_title}')
time.sleep(5)
driver.press("back")
time.sleep(2)
# append_file(device,'Step 21 : 发布作品')
# driver.xpath('//*[@resource-id="com.smile.gifmaker:id/publish_button"]').click()
click_(driver,element='//*[@resource-id="com.smile.gifmaker:id/publish_button"]',content='发布作品',sleepTime=5,error_path=img_path_tmp)
sn_title_file = f'{titles_dir}/{driver.serial}_title.txt'
append_title_file(sn_title_file,s_title)
queue = queue.Queue()
lock = threading.Lock()
# 将每个设备添加至线程池
def add_device_2_queue():
for d_sn in devices:
queue.put(d_sn)
# 判断该商品是否发布过
def get_device_title(d_sn):
sn_title_file = f'{titles_dir}/{d_sn}_title.txt'
if not os.path.exists(sn_title_file):
return []
with open(sn_title_file, 'r', encoding='utf-8') as f:
data = [d.replace('\n','') for d in f.readlines()]
print(data)
return data
def exc_consum(q):
while not q.empty():
current_device = q.get()
# try:
for c_i in range(50):
print(current_device,c_i)
d = u2.connect(current_device)
s = d.info['screenOn']
clean_screen_shots(d,flag=False)
append_file(current_device,f'Step 0 : 当前连接设备:{current_device} {c_i}')
print('当前屏幕状态:',s)
append_file(current_device,f'Step 1 : 当前屏幕状态:{s}')
if not s:
d.screen_on()
d.swipe_ext('up',scale=0.9)
d.app_start('com.smile.gifmaker')
append_file(current_device,f'Step 2 : 启动快手应用')
# d.implicitly_wait(15)
time.sleep(10)
try:
d(resourceId="android:id/text1", text="我").click()
append_file(current_device,f'Step 3 : 进入我的')
except Exception as e:
print('e1',e)
append_file(current_device,f'Step 3-1 : Exception:点击我\n{e}')
# d(description="我").click()
continue
try:
d(text='我').click()
d(text='我').click()
time.sleep(3)
zuopin = d.xpath('//*[@resource-id="com.smile.gifmaker:id/tab_text"]').all()
# print(type(zuopin))
zuopins = [x.text for x in zuopin]
append_file(current_device,f'Step 4 : 作品详情:{zuopins}')
print('zuopin:',zuopins)
d.implicitly_wait(10)
# 点击进入快手小店
# d(text='快手小店').click()
click_(d,element='//*[@resource-id="com.smile.gifmaker:id/im_group_list"]/android.view.ViewGroup[1]')
except Exception as e2:
append_file(current_device,f'Step 5-1 : Exception : 进入快手小店')
print('exception2:',e2)
continue
append_file(current_device,f'Step 5 : 进入快手小店')
time.sleep(5)
# 点击货架
try:
# d.xpath('//*[@resource-id="com.smile.gifmaker:id/root_view"]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.FrameLayout[1]/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[3]').click()
click_(d,element='//*[@resource-id="com.smile.gifmaker:id/root_view"]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.FrameLayout[1]/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[3]',content='Step 6 : 进入货架')
# append_file(current_device,f'Step 6 : 进入货架')
except Exception as e3:
print('exception3:',e3)
append_file(current_device,f'Step 6-1 : Exception:点击货架\n{e3}')
continue
time.sleep(5)
# 获取商品布局宽高尺寸
info = d.xpath('//*[@resource-id="com.smile.gifmaker:id/root_view"]/android.widget.LinearLayout[1]/android.widget.LinearLayout[1]').info
wedith,high = info['bounds']['right'],info['bounds']['bottom']
# 商品列表向上滑动一个item,点击第一个item进入
for hj in range(c_i + 2):
d.swipe_ext('up',scale=0.5)
append_file(current_device,f'Step 7 : 进入列表第一个item')
d.click(0.074, 0.281)
time.sleep(5)
# 获取商品详情title
# title = d(className="android.widget.TextView").get_text()
for elem in d.xpath('//*[@resource-id="root"]/android.view.View[1]/android.view.View[1]/android.view.View[1]/android.view.View[1]/android.view.View[1]/android.view.View[1]/android.view.View[1]/android.view.View[1]/android.view.View[3]/android.view.View[1]').all():
children = elem.elem.getchildren()
if children:
title = children[0].get('text')
# print(children[0].get('text'),type(children))
print('商品标题:',title)
titles_tmp = get_device_title(current_device)
if not title:continue
if title in titles_tmp:
append_file(current_device,f'Step 8-1 : 该商品已经发布过:{title}')
clean_screen_shots(d,flag=True)
continue
append_file(current_device,f'Step 8 : 获取商品标题:{title}')
time.sleep(1)
# 点击商品大图
info = d.xpath('//*[@resource-id="root"]/android.view.View[1]/android.view.View[1]/android.view.View[1]/android.view.View[1]/android.view.View[1]/android.view.View[1]/android.view.View[1]/android.view.View[1]/android.view.View[2]').click()
append_file(current_device,f'Step 9 : 获取商品大图:{title}')
time.sleep(1)
# 获取当前图片显示的张数,截图
img_info_screen_shot(d,title,c_i)
time.sleep(5)
# d.app_stop('com.smile.gifmaker')
lock.acquire()
lock.release()
clean_screen_shots(d,flag=True)
# except Exception as ee:
# print('Exception:',ee)
# append_file(current_device,'异常状态,请检查设备连接状态')
# clean_screen_shots(d,flag=True)
add_device_2_queue()
thrds = []
for _ in range(len(devices)):
t = threading.Thread(target=exc_consum,args=(queue,))
t.start()
thrds.append(t)
for t in thrds:
t.join()