接上一篇案例:Python_批量下載1000個apk,我們只講瞭如何下載,
其實市場部提供的表格,不僅僅包含了apk的下載地址,還有apk的版本號,還有MD5信息等,
如何確保你下載的這1000個apk,是下載過程中未出錯,版本號對的上,MD5信息也對上?
附:市場部提供的包含apk版本號,md5信息的表。
本案例主要介紹:如何快速地實現對已經下載好的app進行批量地驗證。
準備階段
- 本篇只講驗證apk的版本號與md5信息,不講下載。
- 需要確保aapt已經成功地加入到了環境變量中去
- “aapt dump bagding XXX.apk | findstr version”命令可以解析某個apk的versionName信息。
- Windows操作系統可以用“certutil -hashfile XXX.apk MD5”命令可以計算某apk的MD5哈希值,
MD5是用於驗證文件下載過程完整性的常用的一套計算方法,確保被下載的文件,在網絡傳輸過程中,未被篡改或者損壞。 - Linux操作系統可以用“md5sum XXX.apk”命令來計算某個apk的MD5哈希值。
- 其實Python的hashlib模塊,也可以進行MD5哈希值的計算,可不受操作系統影響。
- 上一篇案例,我們已經下載好了的apk是放在“downloaded_apk”文件下,os.listdir()函數可以列出文件夾下的所有apk文件。
- 涉及Excel讀寫操作,依舊推薦openpyxl, 需要考慮與原始Excel上的版本號及MD5值自動做對比,
所以我們增加了2列用於做驗證對比, 如果值相同,我們回填Ok,如果值不相同,我們回填差異值並標記紅底色。
Python批處理腳本形式
記住批處理腳本的精髓:批量順序執行語句
# coding=utf-8
import os
import re
import openpyxl
from openpyxl.styles import PatternFill
# 第一步:再生成整個excel表格的字典,key是apk中文名稱,value是一個列表[所在行數, 版本號,MD5]
print("正在生成apk信息索引字典...")
apkinfo_dict = {}
apkname_col = 2
apkversion_col = 4
apkmd5_col = 6
apkversion_col_newadd = 5 # 新加的版本驗證列
apkmd5_col_newadd = 7 # 新加的MD5驗證列
error_fill = PatternFill(fill_type='solid', fgColor="FF3300") # 標記紅色底色
excel = openpyxl.load_workbook('Top_1000_apks.xlsx') # 讀取excel裏邊的內容
table = excel.active
rows = table.max_row
for r in range(2, rows + 1): # 跟excel的第一行標題行無關,從第二行文字內容開始做替換工作
apk_name = table.cell(row=r, column=apkname_col).value # 獲取apk名稱
apk_version = table.cell(row=r, column=apkversion_col).value # 獲取apk名稱
apk_md5 = table.cell(row=r, column=apkmd5_col).value # 獲取apk名稱
apkinfo_dict[apk_name] = [r, apk_version, apk_md5]
print(apkinfo_dict)
# 第二步:再讀取downloaded_apk文件夾下的所有文件,並進行對比及回填操作
curpath = os.getcwd()
apk_dir = os.path.join(curpath, "downloaded_apk")
apk_list = os.listdir(apk_dir)
for apk in apk_list:
print("正在進行%s的版本和MD5值對比與回填操作..." % apk)
apk_path = os.path.join(apk_dir, apk)
file_name = apk.replace(".apk", "") # 獲取apk文件名,去掉後綴
s1 = os.popen("aapt.exe dump badging %s | findstr version" % apk_path).read()
version_name = re.findall(r"versionName=\'(.*)\'", s1)[0]
print(version_name)
s2 = os.popen("certutil -hashfile %s MD5" % apk_path).read()
md5_value = s2.splitlines()[1]
md5_value = md5_value.replace(" ", "")
print(md5_value)
r = apkinfo_dict[file_name][0] # 獲得該apk所在行號
# 假如版本號匹配的上,回填Ok,假如匹配不上,回填新的版本號
if version_name == apkinfo_dict[file_name][1]:
table.cell(row=r, column=apkversion_col_newadd).value = "OK"
else:
table.cell(row=r, column=apkversion_col_newadd).value = version_name
table.cell(row=r, column=apkversion_col_newadd).fill = error_fill # 標記紅色底色
# 假如MD5匹配的上,回填Ok,假如匹配不上,回填新的MD5
if md5_value == apkinfo_dict[file_name][2]:
table.cell(row=r, column=apkmd5_col_newadd).value = "OK"
else:
table.cell(row=r, column=apkmd5_col_newadd).value = md5_value
table.cell(row=r, column=apkmd5_col_newadd).fill = error_fill # 標記紅色底色
print("對比及回填結束,並保存到了New_Top_1000_apks.xlsx,請查閱...")
excel.save("New_Top_1000_apks.xlsx")
os.system("pause")
Python面向過程函數形式
面向過程函數的編程思維應該是這樣的:
你需要多少個功能(函數),才能做成這個事,
最好把功能(函數)都儘量封裝好,只暴露一些的參數接口即可。
在命令行工具熟練運用後,就可以考慮儘量用Python模塊來實現命令行工具的功能,
比如certutil或md5sum就儘量不用了,而考慮用hashlib模塊來代替,
減少對某個命令行工具的依賴,這樣可移植性更強些(減少了對操作系統的限制)。
# coding=utf-8
import os
import re
import openpyxl
from openpyxl.styles import PatternFill
import hashlib
# 定義一些本模塊(當前.py文件)可能都需要調用的“全局變量”
apkname_col = 2
apkversion_col = 4
apkmd5_col = 6
apkversion_col_newadd = 5 # 新加的版本驗證列
apkmd5_col_newadd = 7 # 新加的MD5驗證列
error_fill = PatternFill(fill_type='solid', fgColor="FF3300") # 標記紅色底色
def parse_apk_excel(excel_file):
'''用於生成apk信息索引字典'''
print("正在生成apk信息索引字典...")
apk_info_dict = {}
excel = openpyxl.load_workbook(excel_file) # 讀取excel裏邊的內容
table = excel.active
rows = table.max_row
for r in range(2, rows + 1): # 跟excel的第一行標題行無關,從第二行文字內容開始做替換工作
apk_name = table.cell(row=r, column=apkname_col).value # 獲取apk名稱
apk_version = table.cell(row=r, column=apkversion_col).value # 獲取apk名稱
apk_md5 = table.cell(row=r, column=apkmd5_col).value # 獲取apk名稱
apk_info_dict[apk_name] = [r, apk_version, apk_md5]
return apk_info_dict, excel, table
def get_apk_version(apk_path):
s = os.popen("aapt.exe dump badging %s | findstr version" % apk_path).read()
version_name = re.findall(r"versionName=\'(.*)\'", s)[0]
print(version_name)
return version_name
def get_apk_md5(apk_path):
with open(apk_path, "rb") as hf:
apk_md5 = hashlib.md5(hf.read()).hexdigest()
print(apk_md5)
return apk_md5
def compare_rewrite(apk_info_dict, excel, table):
curpath = os.getcwd()
apk_dir = os.path.join(curpath, "downloaded_apk")
apk_list = os.listdir(apk_dir)
for apk in apk_list:
print("正在進行%s的版本和MD5值對比與回填操作..." % apk)
file_name = apk.replace(".apk", "") # 獲取apk文件名,去掉後綴
apk_path = os.path.join(apk_dir, apk)
version_name = get_apk_version(apk_path)
md5_value = get_apk_md5(apk_path)
r = apk_info_dict[file_name][0] # 獲得該apk所在行號
# 假如版本號匹配的上,回填Ok,假如匹配不上,回填新的版本號
if version_name == apk_info_dict[file_name][1]:
table.cell(row=r, column=apkversion_col_newadd).value = "OK"
else:
table.cell(row=r, column=apkversion_col_newadd).value = version_name
table.cell(row=r, column=apkversion_col_newadd).fill = error_fill # 標記紅色底色
# 假如MD5匹配的上,回填Ok,假如匹配不上,回填新的MD5
if md5_value == apk_info_dict[file_name][2]:
table.cell(row=r, column=apkmd5_col_newadd).value = "OK"
else:
table.cell(row=r, column=apkmd5_col_newadd).value = md5_value
table.cell(row=r, column=apkmd5_col_newadd).fill = error_fill # 標記紅色底色
print("對比及回填結束,並保存到了New_Top_1000_apks.xlsx,請查閱...")
excel.save("New_Top_1000_apks.xlsx")
apk_info_dict, excel, table = parse_apk_excel("Top_1000_apks.xlsx") # 獲取索引字典
compare_rewrite(apk_info_dict, excel, table) # 開始對比及回填
os.system("pause")
Python面向對象類形式
面向對象類的編程思維應該是這樣的:
如果給你一個空白的世界,在這個世界裏你需要哪些種類的事物,
這些種類的事物都具備哪些共有的屬性與方法,
這些種類(類)的事物(對象),和其他種類(其他類)的事物(其他對象)有什麼關係。
儘量把這些類封裝好,只暴露對外的屬性(變量)和方法(函數)即可。
# coding=utf-8
import os
import re
import openpyxl
from openpyxl.styles import PatternFill
import hashlib
# 定義一些本模塊(當前.py文件)可能都需要調用的“全局變量”
apkname_col = 2
apkversion_col = 4
apkmd5_col = 6
apkversion_col_newadd = 5 # 新加的版本驗證列
apkmd5_col_newadd = 7 # 新加的MD5驗證列
error_fill = PatternFill(fill_type='solid', fgColor="FF3300") # 標記紅色底色
class ExcelParser():
def __init__(self, excel_file):
self._excel_file = excel_file # 沒必要暴露到外界,加_
def parse_apk_excel(self): # 這是需要暴露的方法(函數),不能加_
'''用於生成apk信息索引字典'''
print("正在生成apk信息索引字典...")
apk_info_dict = {}
excel = openpyxl.load_workbook(self._excel_file) # 讀取excel裏邊的內容
table = excel.active
rows = table.max_row
for r in range(2, rows + 1): # 跟excel的第一行標題行無關,從第二行文字內容開始做替換工作
apk_name = table.cell(row=r, column=apkname_col).value # 獲取apk名稱
apk_version = table.cell(row=r, column=apkversion_col).value # 獲取apk名稱
apk_md5 = table.cell(row=r, column=apkmd5_col).value # 獲取apk名稱
apk_info_dict[apk_name] = [r, apk_version, apk_md5]
return apk_info_dict, excel, table
def get_apk_version(apk_path):
s = os.popen("aapt.exe dump badging %s | findstr version" % apk_path).read()
version_name = re.findall(r"versionName=\'(.*)\'", s)[0]
print(version_name)
return version_name
def get_apk_md5(apk_path):
with open(apk_path, "rb") as hf:
apk_md5 = hashlib.md5(hf.read()).hexdigest()
print(apk_md5)
return apk_md5
def compare_rewrite(apk_info_dict, excel, table):
curpath = os.getcwd()
apk_dir = os.path.join(curpath, "downloaded_apk")
apk_list = os.listdir(apk_dir)
for apk in apk_list:
print("正在進行%s的版本和MD5值對比與回填操作..." % apk)
file_name = apk.replace(".apk", "") # 獲取apk文件名,去掉後綴
apk_path = os.path.join(apk_dir, apk)
version_name = get_apk_version(apk_path)
md5_value = get_apk_md5(apk_path)
r = apk_info_dict[file_name][0] # 獲得該apk所在行號
# 假如版本號匹配的上,回填Ok,假如匹配不上,回填新的版本號
if version_name == apk_info_dict[file_name][1]:
table.cell(row=r, column=apkversion_col_newadd).value = "OK"
else:
table.cell(row=r, column=apkversion_col_newadd).value = version_name
table.cell(row=r, column=apkversion_col_newadd).fill = error_fill # 標記紅色底色
# 假如MD5匹配的上,回填Ok,假如匹配不上,回填新的MD5
if md5_value == apk_info_dict[file_name][2]:
table.cell(row=r, column=apkmd5_col_newadd).value = "OK"
else:
table.cell(row=r, column=apkmd5_col_newadd).value = md5_value
table.cell(row=r, column=apkmd5_col_newadd).fill = error_fill # 標記紅色底色
print("對比及回填結束,並保存到了New_Top_1000_apks.xlsx,請查閱...")
excel.save("New_Top_1000_apks.xlsx")
if __name__ == '__main__':
e_obj = ExcelParser("Top_1000_apks.xlsx")
apk_info_dict, excel, table = e_obj.parse_apk_excel() # 獲取索引字典
compare_rewrite(apk_info_dict, excel, table) # 開始對比及回填
os.system("pause")
本案例練手素材下載
跳轉到自拍教程官網下載素材
武散人出品,請放心下載並使用!
運行方式與效果
確保Android設備通過USB線與電腦連接了,adb設備有效連接,
以上代碼的3種實現形式都可以直接運行,比如保存爲verify_apks.py並和downloaded_apk文件夾還有Top_1000_apks.xlsx放在同一個文件夾下,
建議python verify_apks.py運行,當然也可以雙擊運行。
運行效果如下:
最終會新生成一個New_Top_1000_apks.xlsx, 其驗證及回填效果如下,
紅色的是代表實際下載下來的apk與市場部提供的Excel上的版本信息及Md5不一樣的標註。
更多更好的原創文章,請訪問官方網站:www.zipython.com
自拍教程(自動化測試Python教程,武散人編著)
原文鏈接:https://www.zipython.com/#/detail?id=f13a1efe25424b679e663a63fb64a10c
也可關注“武散人”微信訂閱號,隨時接受文章推送。