我有一个从 Excel 文件获取数据的程序。我正在使用 Python 3.11.4 和 xlWings。 数据由一些标准数据和一些用户输入定义的数据组成。该 Excel 包含的列的技术数据属于列顶部的产品 ID。数据保存在提取开始之前创建的数据库中。有关需要提取的数据的信息存储在字典中,数据库的标头充当键。对于标准数据,字典的值是一个数组,其中包含从 Excel 中找到的值,以及用作在数据库中创建列的数据类型的字符串。对于用户定义的数据,该数组有两个附加元素:搜索字符串(在 Excel 中查找的内容)和查找该字符串的地址。将针对循环遍历的每一列更新将保存在数据库中的字典中的值。该代码循环遍历用户提供的文档。
问题:当一次从多个文件中提取数据时,代码在特定的 Excel 文件中返回错误:
pywintypes.com_error:(-2146827864,'OLE错误0x800a01a8',无,无) 在第 1395 行(下一个块的最后一行):
#Retrieve properties
for header in headers:
if header_basis[header][3] is None:
header_basis[header][0] = "not found!"
else:
header_basis[header][0] = header_basis[header][3].offset(0,i).value
headers 是一个数组,其中包含定义用户定义数据名称的字符串。这些字符串是数据库的列标题和字典的键。
代码本身相当长,有很多内容与这个问题关系不大(我假设)但是重要的部分在这里(用(...)分隔):
def search_productcard_excel(path, families, headers, search_strings, master):
(...)
#Create dictionary with value and database data type.
header_basis = {
"product_ID": [None, "BIGINT(20)"],
"doc_name": [None, "VARCHAR(50)"],
"family": [None, "VARCHAR(50)"],
"num_of_conductors": [None, "VARCHAR(50)"],
"type": [None, "VARCHAR(50)"],
"CSA": [None, "VARCHAR(50)"],
#"current": [None, "FLOAT(5)"],
"note_1": [None, "VARCHAR(50)"],
"note_2": [None, "VARCHAR(50)"],
}
for i, header in enumerate(headers):
#Add the search string and address for manual data too
header_basis[header] = [None, "VARCHAR(50)", search_strings[i], None]
(...)
#Create new table
sql_string = f"CREATE TABLE {temp_table} ("
for i, key in enumerate(header_basis.keys()):
if i > 0:
sql_string += ", "
sql_string += f"{key} {header_basis[key][1]}"
sql_string = sql_string + ")"
cursor.execute(sql_string)
connection.commit()
(...)
#Do for all document names
create_log_text("Start searching documents...\n")
for doc_name in doc_name_arr:
xml_files = []
for extension in ALLOWED_FILES:
xml_files.extend(glob.glob(os.path.join(path, f"{doc_name}.{extension}")))
#do for all found documents
for xml_file in xml_files:
(...)
#Find the start position of the given properties
for i, header in enumerate(headers):
search_string = header_basis[header][2]
#Search for both columns if "&&" is found
if search_string.find("&&") != -1:
char_pos = search_string.find("&&")
search_string_1 = search_string[0:char_pos-1]
search_string_2 = search_string[char_pos+3:]
temp_range = fun_search_string(search_string_1,
worksheet[PROPERTY_RANGE_BACKUP],
0)
if temp_range is not None:
for search_cell in temp_range:
if search_cell is None:
header_basis[header][3] = None
else:
temp_result = fun_search_string(
search_string_2,
worksheet[search_cell.offset(0,2).address],
0
)[0]
if temp_result is not None:
header_basis[header][3] = search_cell.offset(0,2)
break
else:
header_basis[header][3] = (
fun_search_string(
search_string,
worksheet[PROPERTY_RANGE],0
)[0]
)
#Get family name
header_basis["family"][0] = worksheet["B2"].value
#for every column (CSA)
create_log_text("Search given values...\n")
for i in range(1, MAX_SIZES):
(...)
#Retrieve properties
for header in headers:
if header_basis[header][3] is None:
header_basis[header][0] = "not found!"
else:
header_basis[header][0] = header_basis[header][3].offset(0,i).value
(...)
#Do for every product
for cell in id_cells:
(...)
#Add row table
#Create sql command
sql_string = f"INSERT INTO {temp_table} ("
for j, key in enumerate(header_basis.keys()):
if j > 0:
sql_string += ", "
sql_string += key
sql_string = sql_string + ") VALUES ("
for j, key in enumerate(header_basis.keys()):
val = header_basis[key][0]
if j > 0:
sql_string += ", "
try:
float(val)
sql_string = sql_string + str(val)
except ValueError:
sql_string = sql_string + f"'{str(val)}'"
except TypeError:
sql_string = sql_string + "''"
sql_string = sql_string + ")"
#print(sql_string)
cursor.execute(sql_string)
(...)
#close workbook
create_log_text("Closing file...\n")
workbook.close()
(...)
#close excel app
app.quit()
当仅从返回错误的一个特定文件中提取数据时,而不是一次提取多个文档,它不会返回错误。 另外,在稍微简化代码之前,我将这些值存储在与其他数据(地址、数据类型和搜索字符串)分开的数组中:
val_arr[i] = fun_search_string(search_string, worksheet[PROPERTY_RANGE],0)[0]
代替
header_basis[header][3] = (fun_search_string(search_string, worksheet[PROPERTY_RANGE],0)[0])
这没有返回任何错误。
我不知道 pywintypes.com_error 到底是什么,也不知道其中的“OLE 错误 0x800a01a8”意味着什么,因此我很难弄清楚从哪里开始。我在网上也没有找到答案。
编辑:我自己找到了解决方案。我怀疑这与记忆有关。所以我只是在每次循环更新
header_basis[header][3] is None
之前设置 header_basis[header][3]
。这似乎有效。我
我怀疑该错误与内存问题有关。也许字典在不知不觉中填充了数据,因为值没有被删除而是更新了。在循环中更新之前,我将字典值重置为 None 。这似乎有效。我不确定到底为什么,因为我认为更新字典值(例如 header_basis[header][3] = blabla)会删除以前的值并且不会留下任何剩余数据。也许这也与存储范围有关。
以下代码:
#Find the start position of the given properties for i, header in enumerate(headers): search_string = header_basis[header][2] #Search for both columns if "&&" is found
成为:
#Find the start position of the given properties for i, header in enumerate(headers): search_string = header_basis[header][2] header_basis[header][3] = None #Empty the dictionary value #Search for both columns if "&&" is found