调用python脚本实现Excel截图,导出图片

关键字: 多线程(threading),python,excel,截图,图片导出,COMObject,ImageGrab,WIN32

前提:

因公司接到一个需求,需要把客户提供的excel文档里面的图表导出来以图片形式保存以及展示

实现思路:

python 导出excel原生图表 (柱形图,折线图,饼图)
根据公司优化要求,导致在研究开发的时候有两个版本,都把它列举出来的,方便一次性参考,
以及本人在解决问题遇到一些问题以及需要参考到网址,也一并列举出来,因为本人发现不能
仅仅做一个cv程序员,虽然一般开发上,70%问题都有大量的人解决过并愿意分享出来,但剩下30%
未被开发的呢?

  • 思路一:使用ImageGrab截图(多线程)
# Windows 10
  # Python 3.6

  # python -m pip install pywin32
  # python -m pip install pillow

  from PIL import ImageGrab
  import win32com.client as win32
  import os
  import sys
  import threading
  import win32process
  import pythoncom
  import win32api
  import win32con

  # 关闭excel方法,防止自动关闭不完成
  def shutdown(excel):
      hwnd  =  excel.hwnd
      t,p = win32process.GetWindowThreadProcessId(hwnd)
      try:
          handle = win32api.OpenProcess(win32process.PROCESS_THRMINATE,0,p)
          if handle:
              win32api.TerminateProcess(handle,0)
              win32api.CloseHandle(handle)
      except Exception as e:
          print("close_excel_probelm:%s" % e)

  # 导出图片方法
  def exprotChart(fileName,ImageFileName,lock,excel_id):# fileName 文件名字 ImageFileName 图片名字
      print('-----python start------')
      try:
          pythoncom.CoInitialize()#win32多线程必须初始化这个,进程之间才能通信
          excel = win32.Dispatch(pythoncom.CoGetInterfaceAndReleaseStream(excel_id,pythoncom.IID_IDispatch))
          WorkbookDirectory=r'C:\Users\mi\Desktop\excelChart\ExcelChart'#本人使用目录
          WorkbookFilename=fileName
          filePath=os.path.join(WorkbookDirectory,ImageFileName)
          #加载excel
          lock.auquire()
          wb = excel.Workbooks.Open(os.path.join(WorkbookDirectory,WorkbookFilename))
          ws = wb.WorkSheets('Sheet1')#可以直接输入数字表示第几个sheet,或者输入名字
          ws.Shape(1),Copy() #复制对应的图表到剪贴板
          img = ImageGrab.grabclipboard() #从剪贴板中获取图片数据
          img.save(filePath)#把图片保存在指定路径
          wb.Close(True)
          excel.Quit()
          print("python_thread : %s ---end---")
      except Exception as e:
          print("python_thread : %s  encounter probelms!!!")
          print(e)

      finally:
          lock.release()
          pythoncom.CoUninitialize()

      return filePath

  if  __name__ =='__main__':
      #初始化
        lock  =  threading.Lock()
        pythoncom.CoInitialize()
        start = time.time()
        list =['P2.xlsx','P3.xlsx','P4.xlsx','P1.xlsx']
        threads =[]
        Excel = win32.DispatchEx('Excel.Application')

  for index in range(len(list)):
        pngName = 'test'+str(index)+'.png'
        excel_id  = pythoncom.CoMarshalInterThreadInterfaceInStream(pythoncom.IID_IDispatch,Excel)
        t = threading.Thread(target=exprotChart,args=(list[index],pngName,lock,excel_id))
        # print("method=="+t.getName())
        threads.append(t)

  for th in threads:
      th.setDaemon(True)
      th.start()
  #     time.sleep(1)
  #     print(threading.currentThread().getName())

  for th in threads:
      th.join(12)

  end =  time.time()
  print(end-start)
  shutdown(Excel)
  • 思路二:使用COMObject 原生方法导出图片(多线程)
# 导出图片方法
  # Windows 10
  # Python 3.6

  # python -m pip install pywin32
  # python -m pip install pillow

  from PIL import ImageGrab
  import win32com.client as win32
  import os
  import sys
  import threading
  import win32process
  import pythoncom
  import win32api
  import win32con

  # 关闭excel方法,防止自动关闭不完成
  def shutdown(excel):
      hwnd  =  excel.hwnd
      t,p = win32process.GetWindowThreadProcessId(hwnd)
      try:
          handle = win32api.OpenProcess(win32process.PROCESS_THRMINATE,0,p)
          if handle:
              win32api.TerminateProcess(handle,0)
              win32api.CloseHandle(handle)
      except Exception as e:
          print("close_excel_probelm:%s" % e)

  # 导出图片方法
  def exprotChart(fileName,ImageFileName,lock,excel_id):# fileName 文件名字 ImageFileName 图片名字
      print('-----python start------')
      try:
          pythoncom.CoInitialize()#win32多线程必须初始化这个,进程之间才能通信
          excel = win32.Dispatch(pythoncom.CoGetInterfaceAndReleaseStream(excel_id,pythoncom.IID_IDispatch))
          WorkbookDirectory=r'C:\Users\mi\Desktop\excelChart\ExcelChart'#本人使用目录
          WorkbookFilename=fileName
          filePath=os.path.join(WorkbookDirectory,ImageFileName)
          #加载excel
          lock.auquire()
          wb = excel.Workbooks.Open(os.path.join(WorkbookDirectory,WorkbookFilename))
          ws = wb.WorkSheets('Sheet1')#可以直接输入数字表示第几个sheet,或者输入名字
          chartObject =ws.ChartObjects(1)#获取对应的图表对象
          chartObject.Chart.Export(filePath)
          wb.Close(True)
          excel.Quit()
          print("python_thread : %s ---end---")
      except Exception as e:
          print("python_thread : %s  encounter probelms!!!")
          print(e)

      finally:
          lock.release()
          pythoncom.CoUninitialize()

      return filePath

  if  __name__ =='__main__':
      #初始化
        lock  =  threading.Lock()
        pythoncom.CoInitialize()
        start = time.time()
        list =['P2.xlsx','P3.xlsx','P4.xlsx','P1.xlsx']
        threads =[]
        Excel = win32.DispatchEx('Excel.Application')

  for index in range(len(list)):
        pngName = 'test'+str(index)+'.png'
        excel_id  = pythoncom.CoMarshalInterThreadInterfaceInStream(pythoncom.IID_IDispatch,Excel)
        t = threading.Thread(target=exprotChart,args=(list[index],pngName,lock,excel_id))
        # print("method=="+t.getName())
        threads.append(t)

  for th in threads:
      th.setDaemon(True)
      th.start()
  #     time.sleep(1)
  #     print(threading.currentThread().getName())

  for th in threads:
      th.join(12)

  end =  time.time()
  print(end-start)
  shutdown(Excel)

优缺点总结:

使用剪贴板的时候,不使用多线程是ok,如果使用多线程的话,剪贴板是属于一个全局变量,另外再起一个进程的时候,存在几率把剪贴板里面的东西弄不见,导致我最终截的图跟我要想要的图不一致
一般建议使用win32.