Pywin32操作Excel数据的类

练习Pywin32操作Excel数据。学习https://blog.csdn.net/qdx411324962/article/details/44270455这篇博客后编写的内容。编写完成后进行测试,发现其速度远低于VBA。

  1 # -*- coding: utf-8 -*-
  2 
  3 
  4 import os
  5 import time
  6 import win32com.client
  7 from requests_html import HTMLSession
  8 
  9 
 10 def get_path(file_name=''):
 11     '''获取当前程序运行目录'''
 12     if file_name:
 13         file_name = file_name.strip()
 14     if file_name:
 15         main_file_dir = __file__
 16         main_file_dir_split = main_file_dir.split('\\', -1)
 17         main_file_name = main_file_dir_split[-1]
 18         main_file_path = main_file_dir.rstrip(main_file_name)
 19         return main_file_path + file_name
 20 
 21 
 22 def get_web_page_elements(url='', xpath_expression=''):
 23     '''获取 网页中 xpath表达式匹配的内容'''
 24     web_page_session = HTMLSession()
 25     web_page_request = web_page_session.get(url)
 26     elements = web_page_request.html.xpath(xpath_expression)
 27     return elements
 28 
 29 
 30 class PyExcel(object):
 31     '''处理 Excel 的类'''
 32     __file_name = ''  # 定义 文件名
 33     __excel = None  # 定义 Excel
 34     __work_book = None  # 定义 工作表
 35     __exists = False    # 定义 是否存在
 36 
 37     def __init__(self):
 38         '''PyExcel 对象 初始化'''
 39         self.__work_book = None
 40         self.__file_name = ''
 41         self.__excel = win32com.client.DispatchEx('Excel.Application')  # 也可以用 Dispatch。DispatchEx 开启新进程,Dispatch 会复用进程中的 Excel 进程
 42         self.__excel.Visible = 1    # 后台运行,不显示
 43         # self.__excel.DispalyAlerts = 0  # 不发出警告
 44 
 45     def open(self, file_name=''):
 46         '''
 47         打开 Excel文件\n\r
 48         file_name 为绝对路径,否则出错。
 49         '''
 50         if getattr(self, '__work_book', False):
 51             self.__work_book.Close()
 52         self.__file_name = get_path(file_name) or ''
 53         self.__exists = os.path.isfile(self.__file_name)
 54         if not self.__file_name or not self.__exists:
 55             self.__work_book = self.__excel.Workbooks.Add()
 56         else:
 57             self.__work_book = self.__excel.Workbooks.Open(self.__file_name)
 58 
 59     def reset(self):
 60         '''复位'''
 61         self.__work_book = None
 62         self.__file_name = ''
 63         self.__excel = None
 64         self.__exists = False
 65 
 66     def save(self, newfile=''):
 67         '''save the excel content'''
 68         assert type(newfile) is str, 'filename must be type string'
 69         newfile = get_path(newfile) or self.__file_name
 70         if not newfile or (self.__exists and newfile == self.__file_name):
 71             self.__work_book.Save()
 72             return
 73         pathname = os.path.dirname(newfile)
 74         if not os.path.isdir(pathname):
 75             os.makedirs(pathname)
 76         self.__file_name = newfile
 77         self.__work_book.SaveAs(newfile)
 78 
 79     def close(self, save_changes):
 80         '''关闭应用'''
 81         self.__work_book.Close(SaveChanges=save_changes)
 82         self.__excel.Quit()
 83         time.sleep(2)
 84         self.reset()
 85 
 86     def add_sheet(self, sheet_name=None):
 87         '''添加新页,页名可以自定义'''
 88         sheet = self.__work_book.WorkSheets.Add()
 89         sheet.Name = sheet_name if sheet_name else sheet.Name
 90         return sheet
 91 
 92     def get_sheet_by_index(self, sheet_index=1):
 93         '''通过页索引获取页对象'''
 94         assert sheet_index > 0, '页索引必须大于0'
 95         return self.__work_book.Sheets(sheet_index)
 96 
 97     def get_sheet_by_name(self, sheet_name=''):
 98         '''通过页名称获取页对象'''
 99         for each_worksheet in self.__work_book.WorkSheets:
100             if each_worksheet.Name == sheet_name:
101                 return each_worksheet
102         return None
103 
104     def get_cell(self, sheet_index=1, row=1, column=1):
105         '''获取 Cell 对象'''
106         assert row > 0 and column > 0, '行索引 和 列索引 必须大于0'
107         return self.get_sheet_by_index(sheet_index).Cells(row, column)
108 
109     def get_row(self, sheet_index=1, row=1):
110         '''获取 Row 对象'''
111         assert row > 0, '行索引 必须大于0'
112         return self.get_sheet_by_index(sheet_index).Rows(row)
113 
114     def get_column(self, sheet_index=1, column=1):
115         '''获取 Column 对象'''
116         assert column > 0, '列索引必须大于0'
117         return self.get_sheet_by_index(sheet_index).Columns(column)
118 
119     def get_range(self, sheet_index=1, row1=1, column1=1, row2=1, column2=1):
120         '''获取 Range 对象'''
121         sheet = self.get_sheet_by_index(sheet_index)
122         return sheet.Range(self.get_cell(sheet, row1, column1), self.get_cell(sheet, row2, column2))
123 
124     def get_cell_value(self, sheet_index, row, column):
125         '''获取一个 cell 的值'''
126         return self.get_cell(sheet_index, row, column).Value
127 
128     def set_cell_value(self, sheet_index, row, column, value):
129         '''设置一个 cell 的值'''
130         self.get_cell(sheet_index=sheet_index, row=row, column=column).Value = value
131 
132     def get_cell_text(self, sheet_index, row, column):
133         '''获取一个 cell 的文本'''
134         return self.get_cell(sheet_index, row, column).Text
135 
136     def set_cell_text(self, sheet_index, row, column, text):
137         '''设置一个 cell 的文本'''
138         self.get_cell(sheet_index=sheet_index, row=row, column=column).Test = text
139 
140     def get_cell_interior_color_index(self, sheet_index, row, column):
141         '''获取一个 cell 的颜色值'''
142         return self.get_cell(sheet_index=sheet_index, row=row, column=column).Interior.ColorIndex
143 
144     def set_cell_interior_color_index(self, sheet_index, row, column, color_index):
145         '''设置一个 cell 的颜色值'''
146         self.get_cell(sheet_index=sheet_index, row=row, column=column).Interior.ColorIndex = color_index
147 
148     def get_cell_horizongtal_alignment(self, sheet_index, row, column):
149         '''获取一个 cell 的水平对齐方式'''
150         return self.get_cell(sheet_index=sheet_index, row=row, column=column).HorizontalAlignment
151 
152     def set_cell_horizongtal_alignment(self, sheet_index, row, column, horizontal_alignment):
153         '''设置一个 cell 的水平对齐方式'''
154         self.get_cell(sheet_index=sheet_index, row=row, column=column).HorizontalAlignment = horizontal_alignment
155 
156     def get_cell_vertical_alignment(self, sheet_index, row, column):
157         '''获取一个 cell 的竖直对齐方式'''
158         return self.get_cell(sheet_index=sheet_index, row=row, column=column).VerticalAlignment
159 
160     def set_cell_vertical_alignment(self, sheet_index, row, column, vertical_alignment):
161         '''设置一个 cell 的竖直对齐方式'''
162         self.get_cell(sheet_index=sheet_index, row=row, column=column).VerticalAlignment = vertical_alignment
163 
164     def set_cell_number_format_local(self, sheet_index, row, column, number_format_local):
165         '''设置一个 cell 的 数字格式'''
166         self.get_cell(sheet_index=sheet_index, row=row, column=column).NumberFormatLocal = number_format_local
167 
168     def get_row_values(self, sheet_index, row):
169         '''获取 row 对象的值'''
170         return self.get_row(sheet_index=sheet_index, row=row).Value
171 
172     def set_row_values(self, sheet_index, row, values):
173         '''设置 row 对象的值'''
174         self.get_row(sheet_index=sheet_index, row=row).Value = values
175 
176     def get_row_interior_color_index(self, sheet_index, row):
177         '''获取 row 对象的颜色值'''
178         return self.get_row(sheet_index=sheet_index, row=row).Interior.ColorIndex
179 
180     def set_row_interior_color_index(self, sheet_index, row, color_index):
181         '''设置 row 对象的颜色值'''
182         self.get_row(sheet_index=sheet_index, row=row).Interior.ColorIndex = color_index
183 
184     def get_row_horizongtal_alignment(self, sheet_index, row):
185         '''获取一个 row 的水平对齐方式'''
186         return self.get_row(sheet_index=sheet_index, row=row).HorizontalAlignment
187 
188     def set_row_horizongtal_alignment(self, sheet_index, row, horizontal_alignment):
189         '''设置一个 row 的水平对齐方式'''
190         self.get_row(sheet_index=sheet_index, row=row).HorizontalAlignment = horizontal_alignment
191 
192     def get_row_vertical_alignment(self, sheet_index, row):
193         '''获取一个 row 的竖直对齐方式'''
194         return self.get_row(sheet_index=sheet_index, row=row).VerticalAlignment
195 
196     def set_row_vertical_alignment(self, sheet_index, row, vertical_alignment):
197         '''设置一个 row 的竖直对齐方式'''
198         self.get_row(sheet_index=sheet_index, row=row).VerticalAlignment = vertical_alignment
199 
200     def get_column_values(self, sheet_index, column):
201         '''获取 column 对象的值'''
202         return self.get_column(sheet_index=sheet_index, column=column).values
203 
204     def set_column_values(self, sheet_index, column, values):
205         '''设置 column 对象的值'''
206         self.get_column(sheet_index=sheet_index, column=column).Value = values
207 
208     def set_column_width(self, sheet_index, column, width):
209         '''设置 column 对象的 宽度'''
210         self.get_column(sheet_index=sheet_index, column=column).ColumnWidth = width
211 
212     def get_column_interior_color_index(self, sheet_index, column):
213         '''获取 column 对象的颜色值'''
214         return self.get_column(sheet_index=sheet_index, column=column).Interior.ColorIndex
215 
216     def set_column_interior_color_index(self, sheet_index, column, color_index):
217         '''设置 column 对象的颜色值'''
218         self.get_column(sheet_index=sheet_index, column=column).Interior.ColorIndex = color_index
219 
220     def get_column_horizongtal_alignment(self, sheet_index, column):
221         '''获取一个 column 的水平对齐方式'''
222         return self.get_column(sheet_index=sheet_index, column=column).HorizontalAlignment
223 
224     def set_column_horizongtal_alignment(self, sheet_index, column, horizontal_alignment):
225         '''设置一个 column 的水平对齐方式'''
226         self.get_column(sheet_index=sheet_index, column=column).HorizontalAlignment = horizontal_alignment
227 
228     def get_column_vertical_alignment(self, sheet_index, column):
229         '''获取一个 column 的竖直对齐方式'''
230         return self.get_column(sheet_index=sheet_index, column=column).VerticalAlignment
231 
232     def set_column_vertical_alignment(self, sheet_index, column, vertical_alignment):
233         '''设置一个 column 的竖直对齐方式'''
234         self.get_column(sheet_index=sheet_index, column=column).VerticalAlignment = vertical_alignment
235 
236     def get_range_values(self, sheet_index, row1, column1, row2, column2):
237         '''获取 range 对象的值'''
238         return self.get_range(sheet_index=sheet_index, row1=row1, column1=column1, row2=row2, column2=column2)
239 
240     def set_range_values(self, sheet_index, row1, column1, data):
241         '''设置 range 对象的值'''
242         row2 = row1 + len(data) - 1
243         column2 = column1 + len(data[0] - 1)
244         range = self.get_range(sheet_index, row1, column1, row2, column2)
245         range.clear()
246         range.Value = data
247 
248     def get_sheet_count(self):
249         '''获取 页 数量'''
250         return self.__work_book.Worksheets.Count
251 
252     def set_sheet_row_height(self, sheet_index, row_height):
253         '''设置 sheet 对象的所有 行高'''
254         self.get_sheet_by_index(sheet_index=sheet_index).Rows.RowHeight = row_height
255 
256     def set_sheet_column_width(self, sheet_index, column_width):
257         '''设置 sheet 对象的所有 列宽'''
258         self.get_sheet_by_index(sheet_index=sheet_index).Columns.ColumnWidth = column_width
259 
260     def set_sheet_horizontal_alignment(self, sheet_index, horizontal_alignment):
261         '''设置 sheet 对象的水平对齐方式'''
262         self.get_sheet_by_index(sheet_index=sheet_index).Columns.HorizontalAlignment = horizontal_alignment
263 
264     def get_max_row(self, sheet_index):
265         '''获取最大行数量,非最大已使用行数量'''
266         return self.get_sheet_by_index(sheet_index=sheet_index).Rows.Count
267 
268     def get_max_column(self, sheet_index):
269         '''获取最大列数量,非最大已使用列数量'''
270         return self.get_sheet_by_index(sheet_index=sheet_index).Columns.Count
271 
272     def clear_cell(self, sheet_index, row, column):
273         '''清除 cell 对象的内容'''
274         self.get_cell(sheet_index=sheet_index, row=row, column=column).Clear()
275 
276     def delete_cell(self, sheet_index, row, column):
277         '''删除 cell'''
278         self.get_cell(sheet_index=sheet_index, row=row, column=column).Delete()
279 
280     def clear_row(self, sheet_index, row):
281         '''清除 row 的内容'''
282         self.get_row(sheet_index=sheet_index, row=row).Clear()
283 
284     def delete_row(self, sheet_index, row):
285         '''删除 row'''
286         self.get_row(sheet_index=sheet_index, row=row).Delete()
287 
288     def clear_column(self, sheet_index, column):
289         '''清除 column 的内容'''
290         self.get_column(sheet_index=sheet_index, column=column).Clear()
291 
292     def delete_column(self, sheet_index, column):
293         '''删除 column'''
294         self.get_column(sheet_index=sheet_index, column=column).Delete()
295 
296     def clear_sheet(self, sheet_index):
297         '''清除 sheet 的内容'''
298         self.get_sheet_by_index(sheet_index=sheet_index).Clear()
299 
300     def delete_sheet(self, sheet_index):
301         '''删除 sheet'''
302         self.get_sheet_by_index(sheet_index=sheet_index).Delete()
303 
304     def delete_rows(self, sheet_index, start_row, count):
305         ''' 删除指定数量的 行'''
306         max_row = self.get_max_row(sheet_index)
307         max_column = self.get_max_column(sheet_index)
308         end_row = start_row + count - 1
309         if start_row > max_row or end_row < 1:
310             return
311         self.get_range(sheet_index=sheet_index, row1=start_row, column1=1, row2=end_row, column2=max_column).Delete()
312 
313     def delete_columns(self, sheet_index, start_column, count):
314         '''删除指定数量的 列'''
315         max_row = self.get_max_row(sheet_index)
316         max_column = self.get_max_column(sheet_index)
317         end_column = start_column + count - 1
318         if start_column > max_column or end_column < 1:
319             return
320         self.get_range(sheet_index=sheet_index, row1=1, column1=start_column, row2=max_row, column2=end_column).Delete()
321 
322     def write_share_name_code(self, sheet_index):
323         '''写入 股票名称、股票代码'''
324         # 表格对齐方式设置
325         self.set_sheet_horizontal_alignment(sheet_index, win32com.client.constants.xlCenter)
326         # 表格行高设置
327         self.set_sheet_row_height(sheet_index, 15)
328         # 表格列宽设置
329         self.set_column_width(sheet_index, 1, 45)
330         self.set_column_width(sheet_index, 2, 45)
331         self.set_column_width(sheet_index, 3, 15)
332         self.set_column_width(sheet_index, 4, 15)
333         self.set_column_width(sheet_index, 5, 30)
334         # 列名称 设置
335         self.set_cell_value(sheet_index, 1, 1, '图标列')
336         self.set_cell_value(sheet_index, 1, 2, '图标列')
337         self.set_cell_value(sheet_index, 1, 3, '股票名称')
338         self.set_cell_value(sheet_index, 1, 4, '股票代码')
339         self.set_cell_value(sheet_index, 1, 5, '备注')
340         self.set_cell_value(sheet_index, 2, 5, '股东数量(户)')
341         self.set_cell_value(sheet_index, 3, 5, '股东数量环比比增长率(%)')
342         self.set_cell_value(sheet_index, 4, 5, '人均流通股(股)')
343         self.set_cell_value(sheet_index, 5, 5, '人均流通股环比增长率(%)')
344         self.set_cell_value(sheet_index, 6, 5, '股价(元/股)')
345         # 获取 股票名称、股票代码
346         share_name_code_url = 'http://quote.eastmoney.com/stocklist.html'
347         share_name_code_xpath_expression = "//div[@id='quotesearch']//a[@target='_blank']"
348         share_name_code_data = get_web_page_elements(url=share_name_code_url, xpath_expression=share_name_code_xpath_expression)
349         share_name_code_array = []
350         for each_share_name_code_datum in share_name_code_data:
351             each_share_name_code_datum_split = each_share_name_code_datum.text.split('(', -1)
352             each_share_name = each_share_name_code_datum_split[-2]
353             each_share_code = each_share_name_code_datum_split[-1].split(')', -1)[-2]
354             share_name_code_array.append([each_share_name, each_share_code])
355         print('股票名称、股票代码 获取完毕。')
356         # 对 股票代码排序
357         share_name_code_array_length = len(share_name_code_array)
358         for i in range(0, share_name_code_array_length):
359             for j in range(i, share_name_code_array_length):
360                 if share_name_code_array[i][1] > share_name_code_array[j][1]:
361                     share_name_code_array[i][1], share_name_code_array[j][1] = share_name_code_array[j][1], share_name_code_array[i][1]
362             if i % 100 == 0:
363                 print('正在排序:i = ' + str(i) + ' j = ' + str(j))
364         # 将 股票名称、股票代码 写入 Excel 表格 第3列、第4列
365         for i in range(0, share_name_code_array_length):
366             row = 5 * i + 2
367             self.set_cell_value(sheet_index, row, 3, share_name_code_array[i][0])
368             self.set_cell_number_format_local(sheet_index, row, 4, '@')
369             self.set_cell_value(sheet_index, row, 4, share_name_code_array[i][1])
370             self.set_row_interior_color_index(sheet_index, row, 15)     # 设置本行颜色为 灰色
371             if i % 100 == 0:
372                 print('正在写入股票代码:i = ' + str(i) + ' j = ' + str(j))
373 
374     def write_report_date(self, sheet_index):
375         '''写入 股东报告日期'''
376         share_report_date_url = 'http://data.eastmoney.com/soft/cmjzd/'
377         share_report_date_xpath_expression = "//select[@class='slt']/option"
378         share_report_date_data = get_web_page_elements(url=share_report_date_url, xpath_expression=share_report_date_xpath_expression)
379         share_report_date_index = 5
380         for each_report_share_date_datum in share_report_date_data:
381             share_report_date = each_report_share_date_datum.text
382             share_report_date_index += 1
383             self.set_cell_value(sheet_index, 1, share_report_date_index, share_report_date)
384             self.set_cell_number_format_local(sheet_index, 1, share_report_date_index, 'yyyy-m-d')  # 设置 日期格式
385             self.set_column_width(sheet_index, share_report_date_index, 15)     # 设置 列宽
386 
387     def write_share_holders(self, sheet_index):
388         '''写入 股东数据'''
389         # 获取 日期数组长度
390         share_report_date_url = 'http://data.eastmoney.com/soft/cmjzd/'
391         share_report_date_xpath_expression = "//select[@class='slt']/option"
392         share_report_date_data = get_web_page_elements(url=share_report_date_url, xpath_expression=share_report_date_xpath_expression)
393         share_report_date_data_len = len(share_report_date_data)
394         # 获取股东数据
395         for share_report_date_index in range(share_report_date_data_len + 5, 5, -1):
396             share_report_date = self.get_cell_text(sheet_index, 1, share_report_date_index)
397             share_holders_url = r"http://datainterface.eastmoney.com/EM_DataCenter/JS.aspx?type=GG&sty=GDRS&st=1&sr=1&p=1&ps=5000&js=var%20tdokOZwB={pages:(pc),data:[(x)]}&mkt=1&fd=" + share_report_date
398             share_holders_session = HTMLSession()
399             headers = {
400                 'Coolie': 'st_pvi=03451569348115; st_si=93770045203763',
401                 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
402             }
403             share_holders_request = share_holders_session.get(share_holders_url, headers=headers)
404             share_holders_data = share_holders_request.text.split('[')[1].split(']')[0].split('"', -1)
405             n = 0
406             for each_share_holders_datum in share_holders_data:
407                 if each_share_holders_datum == '' or each_share_holders_datum == ',':
408                     continue
409                 else:
410                     each_share_holders_datum_split = each_share_holders_datum.split(',', -1)
411                     # 股票代码
412                     share_code = each_share_holders_datum_split[0]
413                     for i in range(2, 25000):
414                         if self.get_cell_text(sheet_index, i, 4) == share_code:  # 如果 第三列 等于 股票代码
415                             # 股东数量(户)
416                             share_holders_number = int(each_share_holders_datum_split[2])
417                             self.set_cell_value(sheet_index, i, share_report_date_index, share_holders_number)
418                             # 股东数量环比比增长率(%)
419                             share_holder_number_comparative_ratio = float(each_share_holders_datum_split[3]) * 100
420                             self.set_cell_value(sheet_index, i + 1, share_report_date_index, share_holder_number_comparative_ratio)
421                             self.set_cell_number_format_local(sheet_index, i+1, share_report_date_index, '0.00')
422                             # 人均流通股(股)
423                             stock_holding_quantity_per_person = float(each_share_holders_datum_split[4])
424                             self.set_cell_value(sheet_index, i + 2, share_report_date_index, stock_holding_quantity_per_person)
425                             self.set_cell_number_format_local(sheet_index, i+2, share_report_date_index, '0.00')
426                             # 人均流通股环比增长率(%)
427                             former_stock_holding_quantity_per_person = self.get_cell_value(sheet_index, i+2, share_report_date_index+1)
428                             if former_stock_holding_quantity_per_person != None and  float(former_stock_holding_quantity_per_person) != 0:
429                                 qoq_ratio = stock_holding_quantity_per_person / former_stock_holding_quantity_per_person - 1
430                                 self.set_cell_value(sheet_index, i + 3, share_report_date_index, qoq_ratio)
431                                 self.set_cell_number_format_local(sheet_index, i + 3, share_report_date_index, '0.00')
432                             break
433                     if n % 100 == 0:
434                         print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) + '正在处理 ' + share_report_date + ' 的股票:' + share_code + ' 的数据。')
435                     n += 1
436 
437 
438 def main():
439     '''main fuction'''
440     file_name = 'a.xlsx'
441     my_excel = PyExcel()
442     my_excel.open(file_name=file_name)
443     # my_excel.write_share_name_code(1)
444     my_excel.write_report_date(1)
445     my_excel.write_share_holders(1)
446 
447     my_excel.save(newfile=file_name)
448     my_excel.close(1)
449 
450 
451 if __name__ == '__main__':
452     main()

猜你喜欢

转载自www.cnblogs.com/mcgill0217/p/10340013.html
今日推荐