折腾:
【未解决】开启和运行另外一个设备id是1的红米Note8Pro的自动化测试安卓项目环境
和:
【未解决】安卓游戏批量测试:VivoGame的21个魔域类游戏20201210
遇到:
由于网络中断等原因,导致下载中断,下载到的安卓apk文件是部分文件。
[201210 12:07:44][DownloadApps.py 139] download com.door.of.magic.vivo/魔法之门Online speed: cur=4.4MB/s, time: total=00:01:07, size: 280.0MB 96.54%
去添加支持已下载,但是是部分已下载。
之前已有逻辑是:
判断apk是否存在,如果存在,则视为已下载。
isDownloaded = CommonUtils.isFileExistAndValid(filepath) @staticmethod def isFileExistAndValid(filePath): isExistFile = os.path.isfile(filePath) isValidFile = False if isExistFile: curFileSize = os.path.getsize(filePath) isValidFile = curFileSize > 0 isExistAndValid = isExistFile and isValidFile return isExistAndValid
是不对的。
应该检测已下载的文件,是否是完整的size
如果不是,则 获取已下载大小,接着继续 断点续传
现在去添加此逻辑。
src/common/DownloadApps.py
totalFileSize = CommonUtils.getFileSizeFromUrl(url)
totalSizeStr = ""
if totalFileSize:
totalSizeStr = CommonUtils.formatSize(totalFileSize)
logging.info("Get App total size %s from %s", totalSizeStr, url)
else:
logging.warning("Fail to get app total size from %s", url)
isDownloadedAndValid = CommonUtils.isFileExistAndValid(filepath, fullFileSize=totalFileSize)
if isDownloadedAndValid:
logging.info("{} is already download".format(appname))
return和:
utils/common_utils.py
@staticmethod
def getFileSizeFromUrl(fileUrl):
"""Get file size from file url
Args:
fileUrl (str): file url
Returns:
file size or None
Raises:
Examples:
input: https://gameapktxdl.vivo.com.cn/appstore/developer/soft/20201020/202010201805243ed5v.apk
output: 154551625
"""
totalFileSize = None
try:
resp = requests.get(fileUrl, stream=True)
respHeaders = resp.headers # {'Date': 'Thu, 10 Dec 2020 05:27:10 GMT', 'Content-Type': 'application/vnd.android.package-archive', 'Content-Length': '154551625', 'Connection': 'keep-alive', 'Server': 'NWS_TCloud_static_msoc1_xz', 'Cache-Control': 'max-age=600', 'Expires': 'Thu, 10 Dec 2020 05:37:09 GMT', 'Last-Modified': 'Thu, 09 Jan 2020 11:21:35 GMT', 'X-NWS-UUID-VERIFY': '94db2d14f135898d924fb249b13a0964', 'X-Verify-Code': '2871bd7acf67c7e298e9c8d8c865e27d', 'X-NWS-LOG-UUID': 'a83536f2-ab83-465d-ba09-0e19a15cc706', 'X-Cache-Lookup': 'Hit From Disktank3, Hit From Inner Cluster', 'Accept-Ranges': 'bytes', 'ETag': '"46C50A5CADB6BEE339236477BB6DDC14"', 'X-Daa-Tunnel': 'hop_count=2'}
contentLengthStr = respHeaders['Content-Length'] # '154551625'
contentLengthInt = int(contentLengthStr) # 154551625
totalFileSize = contentLengthInt
except:
totalFileSize = None
return totalFileSize # 154551625
@staticmethod
def isFileExistAndValid(filePath, fullFileSize=None):
"""Check file exist and valid or not
Args:
filePath (str): file path
fullFileSize (int): full file size
Returns:
existed and valid (bool)
Raises:
Examples:
"""
isExistFile = os.path.isfile(filePath)
isValidFile = False
if isExistFile:
curFileSize = os.path.getsize(filePath) # 260900226
if fullFileSize:
isValidFile = curFileSize == fullFileSize
else:
isValidFile = curFileSize > 0
isExistAndValid = isExistFile and isValidFile
return isExistAndValid去调试看看

【总结】
src/common/DownloadApps.py
# def download(self, task, taskIndex, taskpath):
def download(self,task):
# 下载单个文件
appname, filepath, url = task
# '018/永恒纪元', 'task/20201014_fengyun_YongHengJiYuan/20201014_fengyun_YongHengJiYuan_gameApp/018_永恒纪元.apk', 'https://dl.hz.37.com.cn/upload/1_1002464_10068/yonghengjiyuanjie_3384240.apk'
# # for debug
# totalFileSize = 447681304
totalFileSize = CommonUtils.getFileSizeFromUrl(url) # 154551625
totalSizeStr = ""
if totalFileSize:
totalSizeStr = CommonUtils.formatSize(totalFileSize)
logging.info("Get app total size %s from %s", totalSizeStr, url)
else:
logging.warning("Fail to get app total size from %s", url)
isDownloadedAndValid = CommonUtils.isFileExistAndValid(filepath, fullFileSize=totalFileSize)
if isDownloadedAndValid:
logging.info("{} is already download".format(appname))
return
logging.info("start to download {0},url {1}".format(appname, url))
downloadCalcTimeKey = "downloadAndroidApk_%s" % appname # 'downloadAndroidApk_018/永恒纪元'
CommonUtils.calcTimeStart(downloadCalcTimeKey)
totalDownloadedSize = os.path.getsize(filepath) if os.path.exists(filepath) else 0
if totalFileSize:
totalDownloadedPercent = float(totalDownloadedSize / totalFileSize) # 293601280 / 304130341 = 0.9653797744566367
else:
totalDownloadedPercent = 0.0
totalDownloadedPercent100 = totalDownloadedPercent * 100
logging.info("Has downloaded %.2f%%", totalDownloadedPercent100)
headers = {
'Range': 'bytes=%d-' % totalDownloadedSize,
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36",
}
r = requests.get(url, stream=True, headers=headers)
# ChunkSize = 1024*1024*10 # 10MB
ChunkSize = 1024*1024*20 # 20MB
with open(filepath, "ab") as f:
startTime = time.time()
prevTime = startTime
for chunkBytes in r.iter_content(chunk_size=ChunkSize):
if chunkBytes:
curDownloadedSize = len(chunkBytes) # 10485760
curTime = time.time() # 1606456020.0718982
totalDownloadedSize += curDownloadedSize # 10485760
f.write(chunkBytes)
f.flush()
if totalFileSize:
downloadedPercent = round(100 * totalDownloadedSize / totalFileSize, 2) # 0.7
else:
downloadedPercent = "Unknown"
downloadedSizeStr = CommonUtils.formatSize(totalDownloadedSize) # '10.0MB'
curDownloadTime = curTime - prevTime # 15.63818907737732
curSpeed = curDownloadedSize / curDownloadTime # 670522.651191692
curSpeedStr = CommonUtils.formatSize(curSpeed) # '654.8KB'
totalDownloadTime = curTime - startTime # 15.63818907737732
averageSpeed = totalDownloadedSize / totalDownloadTime # 670522.651191692
averageSpeedStr = CommonUtils.formatSize(averageSpeed) # '654.8KB'
totalDownloadTimeDict = CommonUtils.floatSecondsToDatetimeDict(totalDownloadTime)
totalDownloadTimeStr = CommonUtils.datetimeDictToStr(totalDownloadTimeDict, isShowMilliSecPart=False)
logging.info("download %s speed: cur=%s/s, time: total=%s, size: %s %s%%",
appname, curSpeedStr, totalDownloadTimeStr, downloadedSizeStr, downloadedPercent)
prevTime = curTime
downloadTimeSecondsFloat = CommonUtils.calcTimeEnd(downloadCalcTimeKey) # 259.60212874412537
downloadTimeDict = CommonUtils.floatSecondsToDatetimeDict(downloadTimeSecondsFloat) # {'days': 0, 'hours': 0, 'microseconds': 128, 'millseconds': 602, 'minutes': 4, 'seconds': 19}
del downloadTimeDict["millseconds"]
del downloadTimeDict["microseconds"]
downloadTimeStr = CommonUtils.datetimeDictToStr(downloadTimeDict) # '00:04:19'
if totalFileSize:
speedFloat = totalFileSize / downloadTimeSecondsFloat # 1724490.1117172781
speedStr = "%s/s" % CommonUtils.formatSize(speedFloat) # '1.6MB/s'
else:
speedStr = "Unknown"
logging.info("End download %s, size=%s, time=%s, speed=%s", appname, totalSizeStr, downloadTimeStr, speedStr)和:
utils/common_utils.py
@staticmethod
def getFileSizeFromUrl(fileUrl):
"""Get file size from file url
Args:
fileUrl (str): file url
Returns:
file size or None
Raises:
Examples:
input: https://gameapktxdl.vivo.com.cn/appstore/developer/soft/20201020/202010201805243ed5v.apk
output: 154551625
"""
totalFileSize = None
try:
resp = requests.get(fileUrl, stream=True)
respHeaders = resp.headers # {'Date': 'Thu, 10 Dec 2020 05:27:10 GMT', 'Content-Type': 'application/vnd.android.package-archive', 'Content-Length': '154551625', 'Connection': 'keep-alive', 'Server': 'NWS_TCloud_static_msoc1_xz', 'Cache-Control': 'max-age=600', 'Expires': 'Thu, 10 Dec 2020 05:37:09 GMT', 'Last-Modified': 'Thu, 09 Jan 2020 11:21:35 GMT', 'X-NWS-UUID-VERIFY': '94db2d14f135898d924fb249b13a0964', 'X-Verify-Code': '2871bd7acf67c7e298e9c8d8c865e27d', 'X-NWS-LOG-UUID': 'a83536f2-ab83-465d-ba09-0e19a15cc706', 'X-Cache-Lookup': 'Hit From Disktank3, Hit From Inner Cluster', 'Accept-Ranges': 'bytes', 'ETag': '"46C50A5CADB6BEE339236477BB6DDC14"', 'X-Daa-Tunnel': 'hop_count=2'}
contentLengthStr = respHeaders['Content-Length'] # '154551625'
contentLengthInt = int(contentLengthStr) # 154551625
totalFileSize = contentLengthInt
except:
totalFileSize = None
return totalFileSize # 154551625
@staticmethod
def isFileExistAndValid(filePath, fullFileSize=None):
"""Check file exist and valid or not
Args:
filePath (str): file path
fullFileSize (int): full file size
Returns:
existed and valid (bool)
Raises:
Examples:
"""
isExistFile = os.path.isfile(filePath)
isValidFile = False
if isExistFile:
curFileSize = os.path.getsize(filePath) # 154551625
if fullFileSize:
isValidFile = curFileSize == fullFileSize
else:
isValidFile = curFileSize > 0
isExistAndValid = isExistFile and isValidFile
return isExistAndValid输出:
[201210 13:34:38][DownloadApps.py 88 ] start to download com.door.of.magic.vivo/魔法之门Online,url https://gameapktxdl.vivo.com.cn/appstore/developer/soft/20201020/202010201805243ed5v.apk [201210 13:34:42][DownloadApps.py 98 ] Has downloaded 96.54% [201210 13:34:58][DownloadApps.py 136] download com.door.of.magic.vivo/魔法之门Online speed: cur=3.9MB/s, time: total=00:00:02, size: 290.0MB 100.0% [201210 13:35:09][DownloadApps.py 151] End download com.door.of.magic.vivo/魔法之门Online, size=290.0MB, time=00:00:19, speed=14.7MB/s