python實(shí)現(xiàn)自動(dòng)化報(bào)表功能(Oracle/plsql/Excel/多線程)
日常會(huì)有很多固定報(bào)表需要手動(dòng)更新,本文將利用python實(shí)現(xiàn)多線程運(yùn)行oracle代碼,并利用xlwings包和numpy包將結(jié)果寫入到指定excel模版(不改變模版內(nèi)容),并自動(dòng)生成帶日期命名的新excel。此外還添加了logging模塊記錄運(yùn)行日志,以及利用try…except實(shí)現(xiàn)遇到錯(cuò)誤自動(dòng)重新運(yùn)行。下面將介紹整個(gè)自動(dòng)化的實(shí)現(xiàn)過(guò)程。
# -*- coding: utf-8 -*- # Create time: 2019-10-16 # Update time: 2019-11-28 # Version: 1.0 # Version: 2.0 增加多線程/出錯(cuò)自動(dòng)重新運(yùn)行模塊 # 導(dǎo)入模塊 import cx_Oracle import os import pandas as pd import pandas.io.sql as sql import time import openpyxl import xlwings as xw import logging import re import threading # 獲取工作目錄 sqlpath = os.getcwd() + '\\' # 獲取當(dāng)前文件夾目錄,若不正確則使用后面的代碼直接輸入 sqlpath = 'E:\\' # 設(shè)置運(yùn)行日志 logging.basicConfig(format='%(asctime)s - %(pathname)s] - %(levelname)s: %(message)s', level=logging.INFO, filename=sqlpath+'log.txt') # 獲取系統(tǒng)日期(用于命名文件) time_start=time.time() date = time.strftime("%Y%m%d") # 定義變量 name = '經(jīng)營(yíng)日?qǐng)?bào)' # 模版名稱 print('開始運(yùn)行: %s' %name) # sql代碼文件名 sql1 = sqlpath + 'hangxian_ri.sql' sql2 = sqlpath + 'hangxian_zhou.sql' sql3 = sqlpath + 'hangxian_yue.sql' # 定義空DataFrame(函數(shù)中要使用,必須要先定義) result1 = pd.DataFrame() result2 = pd.DataFrame() result3 = pd.DataFrame() # 定義可以讀取運(yùn)行sql的函數(shù) def read_run_write1(sql_name): global result1 # 調(diào)用全局變量result1,使用global才能對(duì)全局變量進(jìn)行修改 print('正在運(yùn)行代碼: %s' %sql_name) with open(sql_name,encoding='utf-8-sig',mode='r') as f: # 讀取oracle代碼,中文編碼utf-8-sig, sql_list = f.read() sql_list = re.sub(r'--.*', '', sql_list) # 去除注釋 connection = cx_Oracle.connect('賬號(hào)/密碼@IP地址/數(shù)據(jù)庫(kù)名稱') code = sql_list.replace('\n', ' ').replace(';','') # 將換行符轉(zhuǎn)為空格,去除分號(hào) for i in range(5): # 運(yùn)行oracle代碼,若運(yùn)行失敗則10秒自動(dòng)重新運(yùn)行 try: result1 = sql.read_sql(code, connection) # 利用pd包的read_sql函數(shù)運(yùn)行代碼,返回DataFrame類型的結(jié)果 break # 代碼運(yùn)行成功則跳出循環(huán) except: print('代碼%s運(yùn)行出錯(cuò),正在重新運(yùn)行第%d次' %(sql_name,(i+1))) time.sleep(10) # 代碼運(yùn)行失敗則10秒后再重新運(yùn)行 print('代碼運(yùn)行完成: %s' %sql_name) def read_run_write2(sql_name): global result2 print('正在運(yùn)行代碼: %s' %sql_name) with open(sql_name,encoding='utf-8-sig',mode='r') as f: sql_list = f.read() sql_list = re.sub(r'--.*', '', sql_list) # 去除注釋 connection = cx_Oracle.connect('賬號(hào)/密碼@IP地址/數(shù)據(jù)庫(kù)名稱') code = sql_list.replace('\n', ' ').replace(';','') # 將換行符轉(zhuǎn)為空格,去除分號(hào) for i in range(5): try: result2 = sql.read_sql(code, connection) break except: print('代碼%s運(yùn)行出錯(cuò),正在重新運(yùn)行第%d次' %(sql_name,(i+1))) time.sleep(10) print('代碼運(yùn)行完成: %s' % sql_name) def read_run_write3(sql_name): global result3 print('正在運(yùn)行代碼: %s' %sql_name) with open(sql_name,encoding='utf-8-sig',mode='r') as f: sql_list = f.read() sql_list = re.sub(r'--.*', '', sql_list) # 去除注釋 connection = cx_Oracle.connect('賬號(hào)/密碼@IP地址/數(shù)據(jù)庫(kù)名稱') code = sql_list.replace('\n', ' ').replace(';','') # 將換行符轉(zhuǎn)為空格,去除分號(hào) for i in range(5): try: result3 = sql.read_sql(code, connection) break except: print('代碼%s運(yùn)行出錯(cuò),正在重新運(yùn)行第%d次' %(sql_name,(i+1))) time.sleep(10) print('代碼運(yùn)行完成: %s' % sql_name) # 多線程運(yùn)行sql代碼 if __name__ == '__main__': t1 = threading.Thread(target=read_run_write1, args=(sql1,)) # 調(diào)用函數(shù),并傳遞參數(shù)sql1,注意當(dāng)只有一個(gè)參數(shù)時(shí),參數(shù)后面需要有逗號(hào) t2 = threading.Thread(target=read_run_write2, args=(sql2,)) t3 = threading.Thread(target=read_run_write3, args=(sql3,)) t1.start() # 開始運(yùn)行 t2.start() t3.start() t1.join() # 加入線程,若無(wú)join()則運(yùn)行完一個(gè)主線程后則會(huì)自動(dòng)跳出,運(yùn)行下面的代碼,而不會(huì)等待其他線程運(yùn)行完成 t2.join() t3.join() # 寫入數(shù)據(jù) print('正在寫入數(shù)據(jù)') app = xw.App(visible=False,add_book=False) # visible=False后臺(tái)打開Excel程序 wb = app.books.open(sqlpath+name+'.xlsx') # 打開給定只保留標(biāo)題和公式的空模版 wb.sheets['單日'].range('A4').options(expand='table').value=result1[:].values # result[:].values寫法可以去掉索引和標(biāo)題,將result1寫入到表格'單日',從A4單元格開始 wb.sheets['滾動(dòng)一周'].range('A4').options(expand='table').value=result2[:].values wb.sheets['月累計(jì)'].range('A4').options(expand='table').value=result3[:].values filename = sqlpath+name+date+'.xlsx' # 命名新生成的excel wb.save(filename) # 另存為新Excel,不改變模版 wb.close() # 關(guān)閉工作簿 print(filename+'已自動(dòng)生成') time_end=time.time() print("程序運(yùn)行時(shí)間:%.2f s" % (time_end-time_start)) logging.info("程序運(yùn)行時(shí)間:%.2f s" % (time_end-time_start)) # 記錄程序運(yùn)行時(shí)間到運(yùn)行日志log.txt中
python自動(dòng)化中的一些難點(diǎn)
- 多線程無(wú)法同時(shí)對(duì)excel進(jìn)行寫入操作,如果直接在函數(shù)中運(yùn)行完成后直接寫入,并利用多線程運(yùn)行,會(huì)報(bào)錯(cuò)com模塊沖突
- 為了解決函數(shù)不能直接生成結(jié)果變量的問(wèn)題, 應(yīng)先定義空DataFrame,并在函數(shù)中g(shù)lobal聲明為調(diào)用全局變量才能達(dá)到運(yùn)行完函數(shù)生成變量的效果(可能還有其他更好方法)
運(yùn)行結(jié)果
總結(jié)
以上所述是小編給大家介紹的python實(shí)現(xiàn)自動(dòng)化報(bào)表(Oracle/plsql/Excel/多線程),希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
如果你覺(jué)得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!
相關(guān)文章
python Django實(shí)戰(zhàn)之歌曲搜索功能實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了如何利用python Django實(shí)現(xiàn)歌曲搜索功能,文中的示例代碼講解詳細(xì),具有一定的參考價(jià)值,有需要的小伙伴開業(yè)了解下2023-10-10python實(shí)現(xiàn)簡(jiǎn)單聊天應(yīng)用 python群聊和點(diǎn)對(duì)點(diǎn)均實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)簡(jiǎn)單聊天應(yīng)用,python群聊和點(diǎn)對(duì)點(diǎn)均實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09python語(yǔ)言是免費(fèi)還是收費(fèi)的?
在本篇文章里小編給大家分享的是關(guān)于python語(yǔ)言是否免費(fèi)的相關(guān)知識(shí)點(diǎn),需要的朋友們可以學(xué)習(xí)下。2020-06-06Keras中 ImageDataGenerator函數(shù)的參數(shù)用法
這篇文章主要介紹了Keras中 ImageDataGenerator函數(shù)的參數(shù)用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-07-07Tensorflow實(shí)現(xiàn)神經(jīng)網(wǎng)絡(luò)擬合線性回歸
這篇文章主要為大家詳細(xì)介紹了Tensorflow實(shí)現(xiàn)神經(jīng)網(wǎng)絡(luò)擬合線性回歸,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-07-07基于Python詞云分析政府工作報(bào)告關(guān)鍵詞
這篇文章主要介紹了基于Python詞云分析政府工作報(bào)告關(guān)鍵詞,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06