Python的excel操作——PasteSpecial實現選擇性粘貼自動化


 

前提要景:

  最近收到這么一個需求,excel表格里面我們只想要結果,不要把底表發出來,也就是把excel里面做好的數據粘貼在新的excel,並選擇性粘貼為數值,並且保留格式。完成后發郵件給相應的經理老板們。在經過一系列跌跌撞撞,磕磕碰碰的錯誤下,寫了個excel自動把特定的區域復制粘貼到新的excel的sheet中,並保留了數值和格式。Python操作excel的模塊有千千萬,本文只挑選了win32com.client來進行操作,如有其它模塊的操作,記得艾特我學習一下!

啟動excel

Python啟動excel的常規操作有兩種:

第一種:

os.system('taskkill /IM EXCEL.exe /F')

xlapp = Dispatch('Excel.Application')

第二種:

os.system('taskkill /IM EXCEL.exe /F')

xlapp = win32com.client.gencache.EnsureDispatch('Excel.Application')

有什么區別呢?我也清楚得不仔細,EnsureDispatch的啟動方式要求格式比較嚴格,方法必須首字母大寫,最主要的是這種啟動方式可以使用win32com.client里面的excelVBA常量constants,而普通Dispatch不可以完成,選擇性粘貼PasteSpecial必須要用到constants的常量,故本文使用EnsureDispatch的方式啟動excel。

然后使用Visible為true,表示工作簿可見,

xlapp.Visible = True

DisplayAlerts為False表示為關閉警告,比如在保存時候,提示我們已經有相同文件了,是否保存並覆蓋,為false表示為不提示警告並覆蓋此文件。

xlapp.DisplayAlerts = False

Win32com之工作簿工作表的操作

打開指定路徑wkb_path的excel文件,這里的wkb_path為全路徑

wkb = xlapp.Workbooks.Open(wkb_path)

 

新建一個工作簿:

wkb_new = xlapp.Workbooks.Add()

 

保存工作簿:

wkb.Save()  #保存已有的工作簿

wkb_new.SaveAs(new_path)  #保存新的工作簿到指定的new_path下

 

新建一個工作表:

wkb_new.Worksheets.Add().Name = sheet_name

 

關閉工作簿:

wkb.Close()

 

xlapp.Quit()

退出excel應用程序

 

Win32com之單元格的操作

這里first_range指定區域的第一個單元格

first_row = old_wkb_sheet.Range(first_range).Row   #取得old_wkb_sheet表中單元格first_range的行

first_row = old_wkb_sheet.Range(first_range).Column   #取得old_wkb_sheet表中單元格first_range的列

last_row = old_wkb_sheet.Range(first_range).End(-4121).Row  #取得old_wkb_sheet表中單元格first_range的向下有數據區域的最大行

last_col = old_wkb_sheet.Range(first_range).End(-4161).Column    #取得old_wkb_sheet表中單元格first_range的向右有數據區域的最大列

 

old_wkb_sheet.Range(current_range).Copy()  # 復制old_wkb_sheet表中current_range區域的值

new_wkb_sheet.Range(current_range).Paste()  # 粘貼到new_wkb_sheet表中current_range區域中,Paste為全粘貼,包括格式數值等等

****額外小延伸****

vba中的Paste有sheet的Paste和range的Paste,在進行跨表復制粘貼的時候,只能用sheet的Paste,而跨表粘貼,則需要先激活需要粘貼的工作表

old_wkb_sheet.Range(current_range).Copy()

new_wkb_sheet.Range('A1').Select()

new_wkb_sheet.Range(new_current_range).Paste

 

當然,在用Paste的時候,會把包含格式公式的數據一起復制過去,但是這並不是想要的結果,事實上,我只想要數值和格式,這時候就需要用到PasteSpecial選擇性粘貼了,

我們先了解下PasteSpecial有那些常量:

Paste xlPasteType常量,指定復制的具體內容。默認為全部復制。

  1. 全部 xlPasteAll
  2. 公式 xlPasteFormulas
  3. 數值 xlPasteValues
  4. 格式 xlPasteFormats
  5. 批注 xlPasteComments
  6. 驗證 xlPasteValidation
  7. 所有使用源主題的單元 xlPasteAllUsingSourceTheme
  8. 邊框除外 xlPasteAllExceptBorders
  9. 列寬 xlPasteColumnWidths
  10. 公式和數字格式 xlPasteFormulasAndNumberFormats
  11. 值和數字格式 xlPasteValuesAndNumberFormats
  12. 所有合並條件格式 xlPasteAllMergingConditionalFormats

Operation xlPasteSpecialOperation常量,指明粘貼時要進行的運算操作,即將復制的單元格中的數據與指定單元格區域中的值進行加減乘除運算。

  1. 無 xlPasteSpecialOperationNone
  2. 加 xlPasteSpecialOperationAdd
  3. 減 xlPasteSpecialOperationSubtract
  4. 乘 xlPasteSpecialOperationMultiply
  5. 除 xlPasteSpecialOperationDivide

 

而在python中要使用vba常量,則必須使用EnsureDispatch的啟動方式,使用常量則要導入

from win32com.client import constants

那么來了,使用PasteSpecial來進行選擇性粘貼,可以這樣操作:

old_wkb_sheet.Range(current_range).Copy()

new_wkb_sheet.Range('A1').Select()

new_wkb_sheet.Range(new_current_range).PasteSpecial(Paste = constants.xlPasteValues,Operation = constants.xlNone)

new_wkb_sheet.Range(new_current_range).PasteSpecial(Paste = constants.xlPasteFormats,Operation = constants.xlNone)

new_wkb_sheet.Range(new_current_range).PasteSpecial(Paste = constants.xlPasteColumnWidths,Operation = constants.xlNone)

這里我進行了三次粘貼,一次數值,一次格式,一次列寬,就可以完成只保留數值格式的操作,列寬只是為了讓它完美好看。

****小延申****

那么怎么通過復制的方式,復制一張工作表呢?

首先選擇要復制的工作表的全部數據進行復制:

wkb.Worksheets(sheetname).Cells.Copy()

激活新的工作表

wkb_new.Worksheets(sheetname).Select()

粘貼

wkb_new.Worksheets(sheetname).Paste()

 

*****************************************以下是完全的代碼***********************************

  1 import os
  2 import win32com
  3 from win32com.client import Dispatch,constants
  4 
  5 path = r"\\10.250.50.23\共享\qsl\數值"
  6 path_a = r"\\10.250.50.23\共享\qsl\數值\大表_EM_V3.xlsx"
  7 
  8 #橫坐標轉換為數字
  9 def colname_to_num(colname):
 10     if type(colname) is not str:
 11         return colname
 12     col = 0
 13     power = 1
 14     for i in range(len(colname)-1,-1,-1):
 15         ch = colname[i]
 16         col += (ord(ch)-ord('A')+1)*power
 17         power *= 26
 18     return col
 19 
 20 #數字轉換為橫坐標
 21 def column_to_name(colnum):
 22     if type(colnum) is not int:
 23         return colnum
 24     str = ''
 25     while(not(colnum//26 == 0 and colnum % 26 == 0)):
 26         temp = 25
 27         if(colnum % 26 == 0):
 28             str += chr(temp+65)
 29         else:
 30             str += chr(colnum % 26 - 1 + 65)
 31         colnum //= 26
 32     return str[::-1]
 33 
 34 def wkb_client(path,wkb_path,class_Collection,newwkb_name):
 35         os.system('taskkill /IM EXCEL.exe /F')
 36         xlapp = win32com.client.gencache.EnsureDispatch('Excel.Application')
 37         #xlapp = Dispatch('Excel.Application')
 38         xlapp.Visible = True
 39         xlapp.DisplayAlerts = False # 關閉警告
 40         wkb = xlapp.Workbooks.Open(wkb_path)
 41         print('文件【{}】已打開!'.format(wkb_path))
 42         wkb_new = xlapp.Workbooks.Add()
 43         new_path = path + '\\{}'.format(newwkb_name)
 44         print(newwkb_name)
 45         wkb_new.SaveAs(new_path)
 46         wkb_new.Close(1)
 47         wkb_new = xlapp.Workbooks.Open(new_path)
 48 
 49         for key,vlaue in class_Collection.items():
 50             
 51             sheet_name = class_Collection[key]['sheetname']
 52             first_range = class_Collection[key]['數據區域首行首列']
 53 
 54             old_wkb_sheet = wkb.Worksheets(sheet_name)
 55             wkb_new.Worksheets.Add().Name = sheet_name
 56             new_wkb_sheet = wkb_new.Worksheets(sheet_name)
 57             first_row = old_wkb_sheet.Range(first_range).Row
 58             first_col = old_wkb_sheet.Range(first_range).Column
 59             last_row = old_wkb_sheet.Range(first_range).End(-4121).Row
 60             last_col = old_wkb_sheet.Range(first_range).End(-4161).Column
 61             last_rane = column_to_name(last_col)+str(last_row)
 62             current_range = first_range + ':'+last_rane
 63             print ('當前復制單元格區域為:{}'.format(current_range))
 64             new_current_range = 'A1'+':'+column_to_name(last_col-first_col+1)+str((last_row-first_row+1))
 65             print(new_current_range)
 66             old_wkb_sheet.Range(current_range).Copy()
 67             new_wkb_sheet.Range('A1').Select()
 68             new_wkb_sheet.Range(new_current_range).PasteSpecial(Paste = constants.xlPasteValues,Operation = constants.xlNone)
 69             new_wkb_sheet.Range(new_current_range).PasteSpecial(Paste = constants.xlPasteFormats,Operation = constants.xlNone)
 70             new_wkb_sheet.Range(new_current_range).PasteSpecial(Paste = constants.xlPasteColumnWidths,Operation = constants.xlNone)
 71         wkb.Worksheets(class_Collection['sheet0']['sheetname']).Cells.Copy()
 72         wkb_new.Worksheets(class_Collection['sheet0']['sheetname']).Select()
 73         wkb_new.Worksheets(class_Collection['sheet0']['sheetname']).Paste()
 74         wkb.Save()
 75         wkb_new.Save()
 76         wkb.Close(1)
 77         wkb_new.Close(1)
 78         xlapp.Quit()
 79         print('#更新 成功:%s' % wkb_path)
 80         pass
 81 
 82 
 83 class_Collection = {'sheet1':{'sheetname':'業務經營大表_姓名 (日)',
 84                              '數據區域首行首列':'A17',},
 85                     
 86                     'sheet2':{'sheetname':'組織管理大表_姓名 (日)',
 87                              '數據區域首行首列':'A17',},
 88                     
 89                     'sheet3':{'sheetname':'用戶運營大表_姓名 (日)',
 90                              '數據區域首行首列':'A17',},
 91                     
 92                     'sheet4':{'sheetname':'業務經營大表_姓名',
 93                              '數據區域首行首列':'A17',},
 94                     
 95                     'sheet5':{'sheetname':'用戶運營大表_姓名',
 96                              '數據區域首行首列':'A17',},
 97                     
 98                     'sheet6':{'sheetname':'組織管理大表_姓名',
 99                              '數據區域首行首列':'A17',},
100                     
101                     'sheet0':{'sheetname':'定義說明',
102                              '數據區域首行首列':'A1',}
103                     }
104 
105 wkb_client(path,path_a,class_Collection,'大表_EM_數值.xlsx')

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM