溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

python實現(xiàn)自動化報表:用于Excel或多線程等

發(fā)布時間:2020-07-19 11:48:23 來源:網(wǎng)絡(luò) 閱讀:700 作者:ckllf 欄目:編程語言

  日常會有很多固定報表需要手動更新,本文將利用python實現(xiàn)多線程運行oracle代碼,并利用xlwings包和numpy包將結(jié)果寫入到指定excel模版(不改變模版內(nèi)容),并自動生成帶日期命名的新excel。此外還添加了logging模塊記錄運行日志,以及利用try…except實現(xiàn)遇到錯誤自動重新運行。下面將介紹整個自動化的實現(xiàn)過程。

  # -*- coding: utf-8 -*-

  # Create time: 2019-10-16

  # Update time: 2019-11-28

  # Version: 1.0

  # Version: 2.0 增加多線程/出錯自動重新運行模塊

  # 導(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è)置運行日志

  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)營日報' # 模版名稱

  print('開始運行: %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()

  # 定義可以讀取運行sql的函數(shù)

  def read_run_write1(sql_name):

  global result1 # 調(diào)用全局變量result1,使用global才能對全局變量進(jìn)行修改

  print('正在運行代碼: %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('賬號/密碼@IP地址/數(shù)據(jù)庫名稱')

  code = sql_list.replace('\n', ' ').replace(';','') # 將換行符轉(zhuǎn)為空格,去除分號

  for i in range(5): # 運行oracle代碼,若運行失敗則10秒自動重新運行

  try:

  result1 = sql.read_sql(code, connection) # 利用pd包的read_sql函數(shù)運行代碼,返回DataFrame類型的結(jié)果

  break # 代碼運行成功則跳出循環(huán)

  except:

  print('代碼%s運行出錯,正在重新運行第%d次' %(sql_name,(i+1)))

  time.sleep(10) # 代碼運行失敗則10秒后再重新運行

  print('代碼運行完成: %s' %sql_name)

  def read_run_write2(sql_name):

  global result2

  print('正在運行代碼: %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('賬號/密碼@IP地址/數(shù)據(jù)庫名稱')

  code = sql_list.replace('\n', ' ').replace(';','') # 將換行符轉(zhuǎn)為空格,去除分號

  for i in range(5):

  try:

  result2 = sql.read_sql(code, connection)

  break

  except:鄭州婦科醫(yī)院 http://www.120zzkd.com/

  print('代碼%s運行出錯,正在重新運行第%d次' %(sql_name,(i+1)))

  time.sleep(10)

  print('代碼運行完成: %s' % sql_name)

  def read_run_write3(sql_name):

  global result3

  print('正在運行代碼: %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('賬號/密碼@IP地址/數(shù)據(jù)庫名稱')

  code = sql_list.replace('\n', ' ').replace(';','') # 將換行符轉(zhuǎn)為空格,去除分號

  for i in range(5):

  try:

  result3 = sql.read_sql(code, connection)

  break

  except:

  print('代碼%s運行出錯,正在重新運行第%d次' %(sql_name,(i+1)))

  time.sleep(10)

  print('代碼運行完成: %s' % sql_name)

  # 多線程運行sql代碼

  if __name__ == '__main__':

  t1 = threading.Thread(target=read_run_write1, args=(sql1,)) # 調(diào)用函數(shù),并傳遞參數(shù)sql1,注意當(dāng)只有一個參數(shù)時,參數(shù)后面需要有逗號

  t2 = threading.Thread(target=read_run_write2, args=(sql2,))

  t3 = threading.Thread(target=read_run_write3, args=(sql3,))

  t1.start() # 開始運行

  t2.start()

  t3.start()

  t1.join() # 加入線程,若無join()則運行完一個主線程后則會自動跳出,運行下面的代碼,而不會等待其他線程運行完成

  t2.join()

  t3.join()

  # 寫入數(shù)據(jù)

  print('正在寫入數(shù)據(jù)')

  app = xw.App(visible=False,add_book=False) # visible=False后臺打開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['滾動一周'].range('A4').options(expand='table').value=result2[:].values

  wb.sheets['月累計'].range('A4').options(expand='table').value=result3[:].values

  filename = sqlpath+name+date+'.xlsx' # 命名新生成的excel

  wb.save(filename) # 另存為新Excel,不改變模版

  wb.close() # 關(guān)閉工作簿

  print(filename+'已自動生成')

  time_end=time.time()

  print("程序運行時間:%.2f s" % (time_end-time_start))

  logging.info("程序運行時間:%.2f s" % (time_end-time_start)) # 記錄程序運行時間到運行日志log.txt中

  python自動化中的一些難點

  多線程無法同時對excel進(jìn)行寫入操作,如果直接在函數(shù)中運行完成后直接寫入,并利用多線程運行,會報錯com模塊沖突

  為了解決函數(shù)不能直接生成結(jié)果變量的問題, 應(yīng)先定義空DataFrame,并在函數(shù)中g(shù)lobal聲明為調(diào)用全局變量才能達(dá)到運行完函數(shù)生成變量的效果(可能還有其他更好方法)

  得出運行結(jié)果

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI