一、環境
windows10/mac + python3.6
python第三方庫 xlsxwriter、PIL、argparse
二、需求
1、運行每條測試case成功與否都需要把截圖放在img文件夾裏;
2、把 (平臺)_img 文件夾中的圖片壓縮寫到small_img文件夾裏;
3、根據圖片命名規則,順序寫入所屬case number對應行,順序寫入每條case所有截圖;
4、根據平臺來貼到excel最合適的位置;
5、最重要一點,是給媳婦寫的,提升工作效率;
三、文件樹示例
三、Paste_pictures.py
#!/usr/bin/env python3
# coding=utf-8
import xlsxwriter
import datetime
import os
import logging
LOGGER = logging.getLogger(__name__)
def write_img_for_xls(file_name="test.xlsx", img_dir_name="img", sheet_name="案例截圖",
set_img_row=210.75, set_img_column=23.38, x_scale=0.14, y_scale=0.14, ):
"""
讀取同目錄img文件夾下的所有圖片,格式支持png\jpg\bmp。
圖片必須遵從 1-1.png、1-2.png、2-1.png、2-2.png格式。
注意:是將圖片寫入新的excel文件,如果老的excel中有數據,將會替換所有數據。
file_name: 要寫入的xlsx文件名
img_dir_name: 圖片存放的目錄,必須與腳本在同一目錄下
set_img_row:設置行高
set_img_column:設置列寬
x_scale:圖片寬度縮放比例
y_scale:圖片高度縮放比例
:return: Nothing
"""
start_time = datetime.datetime.now()
xls_path = os.path.join(os.getcwd(), file_name)
if not os.path.isfile(xls_path):
raise MyException("what?你居然不把{}文件跟腳本放在同一個目錄下!".format(file_name))
img_path = os.path.join(os.getcwd(), img_dir_name)
if not os.path.isdir(img_path):
raise MyException("what?你都沒有{}文件夾,我咋給你貼圖啊~".format(img_dir_name))
all_img = os.listdir(img_path)
if not all_img:
raise MyException("忽悠我呢?{}文件夾下啥都沒有~".format(img_dir_name))
w_book = xlsxwriter.Workbook(xls_path)
img_sheet = w_book.add_worksheet(name=sheet_name)
count_num = 0
try:
for unit_img in all_img:
try:
img_num = unit_img.split("-")
row = int(img_num[0])
column = int(img_num[1].split(".")[0])
suffix = (unit_img.split(".")[1])
if column == 0:
LOGGER.warning("圖片名稱格式有誤直接略過!錯誤文件名:{},“-”前後數字必須從1開始!".format(unit_img))
continue
except ValueError:
LOGGER.warning("[-]圖片命名規則有誤直接略過!錯誤文件名是:{}".format(unit_img))
continue
LOGGER.info(">> 正在貼圖到第{}條用例,第{}列...".format(row, column))
img_sheet.set_column(firstcol=0, lastcol=0, width=8.38)
img_sheet.write(row - 1, 0, "案例{}".format(row))
small_img = os.path.join(os.getcwd(), "{}/{}-{}.{}".format(img_dir_name, row, column,
suffix))
img_sheet.set_column(firstcol=column, lastcol=column, width=set_img_column)
img_sheet.set_row(row=row - 1, height=set_img_row)
img_config = {
x_scale: x_scale,
y_scale: y_scale
}
result = img_sheet.insert_image(row - 1, column, small_img, img_config)
img_sheet.write_url(row - 1, column + 1, url="https://my.oschina.net/medivhxu/blog/1590012")
if not result:
LOGGER.info("[+] 寫入成功!")
count_num += 1
else:
LOGGER.error("[-] 寫入失敗!")
except Exception as e:
raise MyException("受到不明外力襲擊,程序...掛了....\n{}".format(e))
finally:
try:
w_book.close()
except PermissionError:
raise MyException("你開着{}文件我讓我咋寫。。。趕緊關了!".format(file_name))
LOGGER.info("--------------貼圖完成--------------")
LOGGER.info("程序貼圖數量:{},貼圖成功數量:{},貼圖失敗數量:{}".format(len(all_img), count_num, len(all_img) - count_num))
class MyException(Exception):
pass
write_img_for_xls()
四、run
五、result
價值:
手動貼圖需要半小時?1小時?貼錯了?不,這些我都不要,僅需不到5秒,全部搞定,然後就可以乾點想幹的事~
性能分析:
其實貼圖並不需要4秒+,因爲xlsxwriter這個模塊是自動創建cell的,但是這不是主要原因,主要原因是因爲圖片太大了,所以保存時間會隨着圖片加載到內存而線性增長(圖片較大或過多,容易導致腳本直接崩潰),優化方式是選用openpyxl模塊和最中要的圖片預處理。
六、PIL圖片壓縮
1、code
#!/usr/bin/env python3
# coding=utf-8
import os
from PIL import Image
def compression_img(read_dir_name="img", save_img_file=True, height_shrink_multiple=2, width_shrink_multiple=2):
'''
自動壓縮指定文件夾下的所有圖片
:param read_dir_name: 指定讀取圖片的文件夾名稱,必須在當前目錄下
:param save_img_file: 是否保存壓縮後的圖片
:param height_shrink_multiple: 設置圖片壓縮高度的倍數
:param width_shrink_multiple: 設置圖片壓縮寬度的倍數
:return: nothing
'''
img_path = os.path.join(os.getcwd(), read_dir_name)
all_img = os.listdir(img_path)
for unit_img in all_img:
try:
img_num = unit_img.split("-")
row = int(img_num[0])
column = int(img_num[1].split(".")[0])
suffix = (unit_img.split(".")[1])
if column == 0:
print("圖片名稱格式有誤直接略過!錯誤文件名:{},“-”前後數字必須從1開始!".format(unit_img))
continue
except ValueError:
print("[-]圖片命名規則有誤直接略過!請參考1-1.png格式從新運行或手動解決!")
print("錯誤文件名是:{}".format(unit_img))
continue
img_fp = os.path.join(img_path, unit_img)
origin_img = Image.open(img_fp)
w, h = origin_img.size
small_img = origin_img.resize((int(w / height_shrink_multiple), int(h / width_shrink_multiple)))
if save_img_file:
img_save_fp = os.path.join(os.getcwd(), "small_img")
if os.path.isdir(os.path.join(os.getcwd(), "small_img")):
print("warning, 已有small_img文件夾!直接保存到裏面了!")
small_img.save(os.path.join(img_save_fp, ("{}-{}.{}".format(row, column, suffix))))
else:
os.mkdir("small_img")
print("新建文件夾“small_img”,壓縮後的圖片將存儲在該文件夾中。")
small_img.save(os.path.join(img_save_fp, ("{}-{}.{}".format(row, column, suffix))))
print(">> 正在處理圖像{}-{}.{},原像素高和寬{},壓縮後的高和寬{}".format(row, column, suffix,
(w, h), small_img.size))
small_img.close()
print("--------------圖片壓縮完成--------------")
compression_img()
2、再次運行Paste_pictures.py
可以明顯看出,保存文件的時間有非常顯著的提升。
七、模塊化
把以上兩個功能合併,增加平臺類型,根據需求增加了3個平臺的圖片縮放比例和寬高,增加運行log,增加作爲主程序命令行運行。以後如果擴展的話直接調用或者寫個類,增加幾個返回值就可以了。
#!/usr/bin/env python3
# coding=utf-8
import xlsxwriter
import datetime
import os
import argparse
import logging
from PIL import Image
LOGGER = logging.getLogger(__name__)
PLATFORM = {"phone": {
"x_scale": 0.29,
"y_scale": 0.29,
"width": 23.38,
"height": 210.75
},
"pad": {
'x_scale': 0.2,
"y_scale": 0.2,
"width": 58,
"height": 230
},
"oppo": {
'x_scale': 0.29,
'y_scale': 0.3,
"width": 22.17,
"height": 230
}
}
def _check_os_dir(read_dir_name, small_dir_name="small", xlsx_file_name="test.xlsx"):
'''
檢測img文件夾及文件夾中的內容、xlsx文件是否存在
:param read_dir_name: 要讀取圖片的文件夾
:param small_dir_name: 壓縮的圖片文件夾
:param xlsx_file_name: excel文件名
:return:
all_img:所有圖片對象
xls_path:excel文件路徑
img_path:圖片文件路徑
'''
full_name = read_dir_name + "_img"
img_path = os.path.join(os.getcwd(), full_name)
LOGGER.info(img_path)
assert os.path.isdir(img_path), "what?你都沒有{}文件夾,我咋給你貼圖啊!!!".format(full_name)
all_img = os.listdir(img_path)
assert all_img, "{}文件夾裏啥也沒有,咋貼!!!".format(full_name)
xls_path = os.path.join(os.getcwd(), xlsx_file_name)
assert os.path.isfile(xls_path), "{}文件不存在!!!".format(xlsx_file_name)
# small_full_name = small_dir_name + datetime.datetime.now().strftime("%Y%m%d%H%M%S")
if full_name == small_dir_name:
return all_img, xls_path, img_path
# os.mkdir("{}".format(small_full_name))
# LOGGER.warning("新建文件夾{},壓縮後的圖片將存儲在該文件夾中。".format(small_dir_name))
return all_img, xls_path, img_path
def _compression_img(read_dir_name, small_dir_name="small", height_shrink_multiple=2, width_shrink_multiple=2):
'''
自動壓縮指定文件夾下的所有圖片
:param read_dir_name: 讀取圖片文件夾的名稱
:param small_dir_name:如果壓縮圖片就讀取該文件夾下的壓縮圖片
:param height_shrink_multiple: 設置圖片壓縮高度的倍數
:param width_shrink_multiple: 設置圖片壓縮寬度的倍數
:return: small_dir_name: 壓縮後的圖片文件名
'''
full_small_dir_name = small_dir_name + "_img"
_check_os_dir(read_dir_name=read_dir_name, small_dir_name=full_small_dir_name)
img_path = os.path.join(os.getcwd(), read_dir_name + "_img")
all_img = os.listdir(img_path)
for unit_img in all_img:
try:
img_num = unit_img.split("-")
row = int(img_num[0])
column = int(img_num[1].split(".")[0])
suffix = (unit_img.split(".")[1])
if column == 0:
LOGGER.warning("圖片名稱格式有誤直接略過!錯誤文件名:{},“-”前後數字必須從1開始!".format(unit_img))
continue
except ValueError:
LOGGER.warning("[-]圖片命名規則有誤直接略過!錯誤文件名是:{}".format(unit_img))
continue
img_fp = os.path.join(img_path, unit_img)
origin_img = Image.open(img_fp)
w, h = origin_img.size
small_img = origin_img.resize((int(w / height_shrink_multiple), int(h / width_shrink_multiple)))
small_img.save(os.path.join(os.getcwd(), "{}/{}-{}.{}".format(full_small_dir_name, row, column, suffix)))
LOGGER.info(">> 正在處理圖像{}-{}.{},原像素高和寬{},壓縮後的高和寬{}".format(row, column, suffix, (w, h), small_img.size))
try:
small_img.close()
except Exception as e:
LOGGER.debug("未知錯誤\n{}".format(e))
LOGGER.info("--------------圖片壓縮完成--------------")
return small_dir_name
def write_img_for_xls(platform, read_dir_name, sheet_name="案例截圖", xlsx_file_name="test.xlsx"):
"""
讀取同目錄img文件夾下的所有圖片,格式支持png\jpg\bmp。
圖片必須遵從 1-1.png、1-2.png、2-1.png、2-2.png格式。
注意:是將圖片寫入新的excel文件,如果老的excel中有數據,將會替換所有數據。
platform: 平臺名稱,包括phone、pad,web目前沒實現
read_dir_name: 要讀取圖片的文件夾名稱
xlsx_file_name: 要寫入的xlsx文件名
sheet_name: 寫入excel中sheet的名字
:return: nothing
"""
all_img, xls_path, img_path = _check_os_dir(xlsx_file_name=xlsx_file_name, read_dir_name=read_dir_name)
w_book = xlsxwriter.Workbook(xls_path)
img_sheet = w_book.add_worksheet(name=sheet_name)
count_num = 0
try:
for unit_img in all_img:
try:
img_num = unit_img.split("-")
row = int(img_num[0])
column = int(img_num[1].split(".")[0])
suffix = (unit_img.split(".")[1])
if column == 0:
LOGGER.warning("圖片名稱格式有誤直接略過!錯誤文件名:{},“-”前後數字必須從1開始!".format(unit_img))
continue
except ValueError:
LOGGER.warning("[-]圖片命名規則有誤直接略過!錯誤文件名是:{}".format(unit_img))
continue
LOGGER.info(">> 正在貼圖到第{}條用例,第{}列...".format(row, column))
img_sheet.set_column(firstcol=0, lastcol=0, width=8.38)
img_sheet.write(row - 1, 0, "案例{}".format(row))
small_img = os.path.join(os.getcwd(), "{}/{}-{}.{}".format(read_dir_name+"_img", row, column,
suffix))
img_sheet.set_column(firstcol=column, lastcol=column, width=PLATFORM.get(platform).get("width"))
img_sheet.set_row(row=row - 1, height=PLATFORM.get(platform).get("height"))
x_ = PLATFORM.get(platform).get("x_scale")
y_ = PLATFORM.get(platform).get("y_scale")
img_config = {"x_scale": x_, "y_scale": y_}
result = img_sheet.insert_image(row - 1, column, small_img, img_config)
img_sheet.write_url(row - 1, column + 1, url="https://my.oschina.net/medivhxu/blog/1590012")
if not result:
LOGGER.info("[+] 寫入成功!")
count_num += 1
else:
LOGGER.error("[-] 寫入失敗!")
except Exception as e:
raise MyException("受到不明外力襲擊,程序...掛了....\n{}".format(e))
finally:
try:
w_book.close()
except PermissionError:
raise MyException("你開着{}文件我讓我咋寫。。。趕緊關了!".format(xlsx_file_name))
LOGGER.info("--------------貼圖完成--------------")
LOGGER.info("程序貼圖數量:{},貼圖成功數量:{},貼圖失敗數量:{}".format(len(all_img), count_num, len(all_img) - count_num))
class MyException(Exception):
pass
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("-p", help="必須選擇平臺phone、pad、oppo")
group = parser.add_mutually_exclusive_group()
group.add_argument("-a", action="store_true", help="壓縮圖片且貼圖到excel")
group.add_argument("-w", action="store_true", help="直接貼圖到excel")
args = parser.parse_args()
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
datefmt='%a, %d %b %Y %H:%M:%S',
filename='Paste_pictures_{}.log'.format(datetime.datetime.now().strftime("%Y%m%d%H%M%S")),
filemode='w')
console = logging.StreamHandler()
console.setLevel(logging.INFO)
formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
console.setFormatter(formatter)
logging.getLogger('').addHandler(console)
if args.p not in PLATFORM.keys():
raise MyException("參數錯誤,必須在{}中選擇".format(PLATFORM.keys()))
if args.a:
LOGGER.info(">>> 選擇參數-a,即壓縮圖片,又貼圖。")
r_small_dir_name = _compression_img(read_dir_name=args.p, small_dir_name="small")
write_img_for_xls(platform=args.p, read_dir_name=r_small_dir_name)
elif args.w:
LOGGER.info(">>> 選擇參數-w,只貼圖。")
write_img_for_xls(platform=args.p, read_dir_name=args.p)
else:
LOGGER.error("參數錯誤")
windows command和linux/mac terminal下運行效果:
The end~