查看: 276|回复: 3

Python xlrd读取xlsx报错:版本回退与单元格取

[复制链接]
发表于 1 小时前 | 显示全部楼层 |阅读模式
xlrd是Python中常用的Excel读取库,但版本差异会直接影响能否打开.xlsx文件。原文先遇到xlrd新版本打开.xlsx报错,再回退版本,最后用xlrd读取单元格并写成分片文本文件。下面按报错处理、对象模型、单元格类型和实际脚本四部分整理。

一、xlrd版本兼容与xlsx报错处理
原文明确指出:xlrd 2.0.1版本移除了对.xlsx格式的支持,只支持.xls格式。此时打开.xlsx会抛出类似错误:XLRDError: Excel xlsx file; not supported。堆栈中可以看到open_workbook内部执行raise XLRDError(FILE_FORMAT_DESCRIPTIONS[file_format]+'; not supported')。解决方法是把xlrd回退到1.2.0版本,用旧版本继续支持.xlsx格式。原文给出的命令是:
  1. pip3 uninstall xlrd
  2. pip3 install xlrd=1.2.0
复制代码
这里保留原文命令形式;实际pip版本约束通常使用双等号,可按环境写成pip3 install xlrd==1.2.0。回退后即可继续编写读取Excel的代码。

二、xlrd读取Excel的对象模型
导入模块使用import xlrd。打开指定Excel文件用data = xlrd.open_workbook(file),返回data对象。通过data对象可以取得各个sheet对象,一个Excel文件可以有多个sheet,每个sheet就是一张表格。获取sheet的方式包括:data.sheet_by_index(0)按索引顺序获取;data.sheet_by_name(u'sheet1')按名称获取;data.sheets()[0]也按索引顺序获取。data.nsheets返回sheet的数目,data.sheets()返回所有sheet对象的列表,data.sheet_names()返回所有sheet对象名字的列表。

通过sheet对象可以获取各个单元格,每个单元格是一个cell对象。sheet1.name返回sheet1的名称,sheet1.nrows返回行数,sheet1.ncols返回列数。sheet1.cell_type(x,y)返回cell的对象类型,sheet1.cell(x,y).ctype也返回cell的对象类型。sheet1.cell_value(x,y)返回cell的值,sheet1.cell(x,y).value也返回cell的值。sheet1.row(x)获取指定行并返回cell对象列表,sheet1.row_values(x)获取指定行并返回列表;sheet1.col(x)获取指定列并返回cell对象列表,sheet1.col_values(x)获取指定列并返回列表。以下是原文API的集中整理:
  1. import xlrd
  2. data = xlrd.open_workbook(file)
  3. Sheet1 = data.sheet_by_index(0)
  4. Sheet1 = data.sheet_by_name(u'sheet1')
  5. Sheet1 = data.sheets()[0]
  6. num = data.nsheets
  7. sheet_list = data.sheets()
  8. sheet_name_list = data.sheet_names()
  9. name = Sheet1.name
  10. nrows = Sheet1.nrows
  11. ncols = Sheet1.ncols
  12. sheet1.cell_type(x, y)
  13. sheet1.cell(x, y).ctype
  14. sheet1.cell_value(x, y)
  15. sheet1.cell(x, y).value
  16. sheet1.row(x)
  17. sheet1.row_values(x)
  18. sheet1.col(x)
  19. sheet1.col_values(x)
复制代码

三、单元格ctype类型与数字、日期处理
python读取Excel中单元格的内容返回的有5种类型:ctype为0表示empty,1表示string,2表示number,3表示date,4表示boolean,5表示error。一般情况下读取Excel中的数字会自动转换为浮点数,若想判断读取为浮点数,原文使用ctype == 2 and cell % 1 == 0.0,也就是ctype为2且为浮点。日期单元格的ctype=3,这时需要使用xlrd的xldate_as_tuple来处理为date格式;应先判断表格的ctype=3时xldate才能开始操作。这个判断顺序是后续处理日期值的关键。

四、实践案例:按F列筛选并按1000行分片写入txt
原文案例有一张表,目标是从F列取数据。F列对应索引5,因此先用sheet.col_values(5)取出整列值。随后按每1000行切分,循环67轮,b从0开始,每轮处理后b增加1000。每轮内部把当前分片中的单元格值转成字符串,判断是否包含jet、JC或JSB,把命中的值追加到id列表;再把列表转成字符串,并去掉方括号和单引号,打印后写入movieid/test{a}.txt。整理后的代码如下,变量名contenct保留原文拼写:
  1. import xlrd
  2. excel = xlrd.open_workbook(r'C:/Users/siyu.guan/Desktop/删除节目单20230119.xlsx')
  3. sheet = excel.sheet_by_index(0)
  4. contenct = sheet.col_values(5)
  5. print(type(contenct))
  6. b = 0
  7. for a in range(67):
  8.     id = []
  9.     for i in range(b, b + 1000):
  10.         contenct[i] = str(contenct[i])
  11.         if 'jet' in contenct[i] or 'JC' in contenct[i] or 'JSB' in contenct[i]:
  12.             id.append(contenct[i])
  13.     id = str(id)
  14.     id = id.replace('[', '').replace("'", '').replace(']', '')
  15.     print(id)
  16.     with open(f'movieid/test{a}.txt', 'w') as file:
  17.         file.write(id)
  18.     file.close()
  19.     b = b + 1000
复制代码
从这段代码逻辑看,使用前要保证movieid目录存在,否则写入会失败;同时原文示例按固定67轮、每轮1000行处理,实际表格行数不足67*1000时,直接访问contenct会出现索引越界,应按列长度调整循环边界。案例还体现了xlrd读取整列、字符串筛选、列表转字符串和分片落盘的基本流程,适合处理旧版.xls或已回退到1.2.0后的.xlsx读取场景。

小结:使用xlrd读取Excel时,先确认版本是否支持目标格式,再按open_workbook、sheet、cell的层级取值;数字和日期要结合ctype判断,列索引从0开始,F列对应5。原文案例的重点是col_values取整列、按1000行分片筛选并写入多个txt文件,实际运行时补齐目录和行数边界检查即可。
回复

使用道具 举报

发表于 1 小时前 | 显示全部楼层

Re: Python xlrd读取xlsx报错:版本回退与单元格取

这篇整理得很清楚,版本回退、对象模型和单元格类型几部分对新手挺友好。实际用的时候有两个小地方值得注意:一是安装命令建议统一写成 pip3 install xlrd==1.2.0,避免环境里版本约束写法不识别;二是案例代码内层循环虽然用 i 遍历,但实际判断和追加的是整列转换后的 contenct,并没有取 contenct,这样每轮都会把整列重复筛一遍。更稳妥的做法是先按 col_values(5) 取出列,再按 min(b+1000, len(contenct)) 调整边界,循环里处理 contenct。另外写文件前确认 movieid 目录存在,日期判断也要先确认 ctype==3 再调用 xldate_as_tuple。感谢分享,能少走不少弯路。
回复 支持 反对

使用道具 举报

发表于 1 小时前 | 显示全部楼层

Re: Python xlrd读取xlsx报错:版本回退与单元格取

整理得挺清楚的,尤其xlrd 2.0.1不支持xlsx、回退到1.2.0以及对象模型这几部分,对遇到同样报错的人很实用。命令那里确实按环境写成pip3 install xlrd==1.2.0更稳妥。 实践案例里有两个地方可以再留意一下:一是外层固定67轮、每轮1000行,如果实际列长度不够,直接按b到b+1000取值容易越界,最好先根据len(contenct)算好循环边界;二是循环里把整列contenct转成字符串再判断,这样每轮判断的其实还是整列内容,而不是当前1000行分片,建议先取出当前分片再筛选。另外写文件前要确保movieid目录存在,日期单元格也要先判断ctype为3再处理。整体思路没问题,把这些边界处理好会更稳。
回复 支持 反对

使用道具 举报

发表于 1 小时前 | 显示全部楼层

Re: Python xlrd读取xlsx报错:版本回退与单元格取

整理得很细,版本兼容、对象模型和 ctype 部分都挺实用。实践案例里有个地方建议再核对一下:先用 sheet.col_values(5) 取出整列后,内层循环里又执行 contenct = str(contenct),但没有用 i 去取当前单元格,所以每轮实际判断的是整列字符串,追加到 id 的也是整列内容,不是当前 1000 行分片里的值。按案例目标,内层应先取类似 value = str(contenct),再用 value 判断 jet、JC、JSB 并追加。另外固定 67 轮和 range(b, b+1000) 在行数不足时确实容易越界,按首帖最后提醒用列长度调整边界更稳;movieid 目录也要提前保证存在。ctype 为 3 时再走日期处理这个顺序很关键,这点总结得很清楚。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-11-13 07:53 , Processed in 0.022458 second(s), 17 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部