使用 Python 将数据覆盖到现有工作簿

Overwriting data to an existing workbook using Python

我是 Python 的新手,正在从事一个我需要一些帮助的项目。因此,我试图修改现有的 excel 工作簿以比较库存数据。幸运的是,有一个在线程序可以检索我需要的所有数据,我已经成功地提取数据并将数据写入新的 excel 文件。但是,目标是提取数据并将其放入现有的 excel 文件中。此外,我需要覆盖现有文件中的单元格值。我相信 xlwings 能够做到这一点,我认为我的代码是在正确的轨道上,但我 运行 遇到了意外错误。我得到的错误是:

TypeError: Objects of type 'Period' can not be converted to a COM VARIANT (but obtaining the buffer() of this object could)

我想知道是否有人知道为什么会出现此错误?另外,有人知道怎么修吗?它可以修复吗?我的代码错了吗?任何帮助或指导表示赞赏。谢谢。

import good_morning as gm
import pandas as pd
import xlwings as xw

#import income statement, balance sheet, and cash flow of AAPL
fd = gm.FinancialsDownloader()
fd_frames = fd.download('AAPL')

#Creates a DataFrame for only the balance sheet
df1 = pd.DataFrame(list(fd_frames.values())[0])

#connects to workbook I want to modify 
wb = xw.Book(r'C:\Users\vince\Project\Spreadsheet.xlsm')

#sheet I would like to modify
sht = wb.sheets[1]

#modifies & overwrites values in my spreadsheet(this is where I get the type_error)
sht.range('M6').value = df1

数据类型

type(fd_frames)
>>> <class 'dict'>
fd_frames.values())[0].info()
>>> <class 'pandas.core.frame.DataFrame'> 
RangeIndex: 22 entries, 0 to 21 
Data columns (total 8 columns): 
parent_index 22 non-null int64 
title 22 non-null object 
2012 19 non-null float64 
2013 20 non-null float64 
2014 20 non-null float64 
2015 20 non-null float64 
2016 20 non-null float64 
2017 20 non-null float64 
dtypes: float64(6), int64(1), object(1) 
memory usage: 1.5+ KB

Comments: You have a Dict of pandas.DataFrame.

使用 list(fd_frames.values())[0] 从字典中选择会导致 不可预测的 结果。显示字典的键并使用这些键选择您感兴趣的键,例如:

 print(fd_frames.keys())
 >>> dict_keys(['key_1', 'key_2', 'key_n']
 df_2 = fd_frames['key_2']

除此之外,pandas.DataFrame 中的维度都不匹配 M6:M30 = 25。只有 8 列 20 个值。因此,您必须将工作表范围对齐 20 行 。将 Column 2017 写入工作表,例如:

wb['M6:M25'] = df_2['2017'].values

Note: I have updated the code below to accept numpy.ndarray also.


Question: ... the goal is to pull the data and put it into an existing excel file

使用列表值更新工作簿工作表范围。
使用:OpenPyXLA Python library to read/write Excel 2010 xlsx/xlsm files

Note: Observe how the List Values have to be arranged!
param values: List: *[row 1(col1, ... ,coln), ..., row n(col1, ... ,coln)]`

from openpyxl import Workbook, load_workbook

class UpdateWorkbook(object):
    def __init__(self, fname, worksheet=0):
        self.fname = fname
        self.wb = load_workbook(fname)
        self.ws = self.wb.worksheets[worksheet]

    def save(self):
        self.wb.save(self.fname)

    def __setitem__(self, _range, values):
        """
         Assign Values to a Worksheet Range
        :param _range:  String e.g ['M6:M30']
        :param values: List: [row 1(col1, ... ,coln), ..., row n(col1, ... ,coln)]
        :return: None
        """

        def _gen_value():
            for value in values:
                yield value

            if not isinstance(values, (list, numpy.ndarray)):
                raise ValueError('Values Type Error: Values have to be "list": values={}'.
                                  format(type(values)))
            if isinstance(values, numpy.ndarray) and values.ndim > 1:
                raise ValueError('Values Type Error: Values of Type numpy.ndarray must have ndim=1; values.ndim={}'.
                                  format(values.ndim))

        from openpyxl.utils import range_boundaries
        min_col, min_row, max_col, max_row = range_boundaries(_range)
        cols = ((max_col - min_col)+1)
        rows = ((max_row - min_row)+1)
        if cols * rows != len(values):
            raise ValueError('Number of List Values:{} does not match Range({}):{}'.
                             format(len(values), _range, cols * rows))

        value = _gen_value()
        for row_cells in self.ws.iter_rows(min_col=min_col, min_row=min_row,
                                           max_col=max_col, max_row=max_row):
            for cell in row_cells:
                cell.value = value.__next__()

Usage

wb = UpdateWorkbook(r'C:\Users\vince\Project\Spreadsheet.xlsx', worksheet=1)
df_2 = fd_frames['key_2']
wb['M6:M25'] = df_2['2017'].values
wb.save()

测试 Python:3.4.2 - openpyxl:2.4.1 - LibreOffice:4.3.3.2

以下是我为其他 Stack 浏览器执行类似过程的方法:

import pandas as pd
from openpyxl import load_workbook
from openpyxl.utils.dataframe import dataframe_to_rows

... create your pandas dataframe df...

# Writing from pandas back to an existing EXCEL workbook
# Load workbook
wb = load_workbook(filename=target, read_only=False, keep_vba=True)
ws = wb['Sheet1']

# Overwrite Existing data in sheet with a dataframe.
rows = dataframe_to_rows(df, index=False, header=True)

for r_idx, row in enumerate(rows, 1):
    for c_idx, value in enumerate(row, 1):
         ws.cell(row=r_idx, column=c_idx, value=value)

# Save file
wb.save('outfile.xlsm')