Pandas完美读取html格式的Excel所有隐藏数据

举报
小小明-代码实体 发表于 2021/10/11 23:54:05 2021/10/11
【摘要】 大家好,我是小小明。 你是否有遇到这样的情况在一些网站导出Excel文件后,用pandas却无法直接以Excel方式读取。 本文就将遇到的这种情况,带你去完整的解析读取。 问题分析 有一个文件用E...

大家好,我是小小明。

你是否有遇到这样的情况在一些网站导出Excel文件后,用pandas却无法直接以Excel方式读取。

本文就将遇到的这种情况,带你去完整的解析读取。

问题分析

有一个文件用Excel软件打开可以看到如下数据:

image-20210714224150972

但尝试用pandas直接读取:

import pandas as pd

df = pd.read_excel("明细费用表1.xlsx")
df

  
 
  • 1
  • 2
  • 3
  • 4

结果报出:

ValueError: File is not a recognized excel file

  
 
  • 1

这时我们可以考虑一下,这个问题有没有可能时间是csv等文本格式,于是用文本解析器打开看看:

image-20210714223359637

原来这是一个html文档,那么我们就可以以纯html的方式读取它了:

image-20210714224302164

但是可以很明显的看到pandas的网页读取,有大量数据并没有读取到。

这时候我们可以考虑使用pywin32转换格式,也可以通过网页解析直接提取需求的数据。

网页结构分析

首先分析一下主要的结构。

首先是表头:

image-20210714224934210

很明显Excel表中的隐藏列就是受display:none的CSS样式控制。

再看看数据行:

image-20210714225352622

可以看到整数类型的数据都存在于属性x:num中,而不是内部的文本节点中。

下面我们使用xpath来解析数据:

解析数据

经时间测试发现,带有x:的命名空间下的数据,几乎无法通过正常的方法解析获取,或者说非常麻烦。所以我们一次性去掉所有的x:前缀后,再读取数据并加载:

import pandas as pd
from lxml import etree

with open("明细费用表1.xlsx", encoding="u8") as f:
    html = etree.HTML(f.read().replace("x:", ""))

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

最终我编写的解析代码如下:

header = None
data = []
for tr in html.xpath("//table/tr"):
    row = []
    for td in tr.xpath("./td"):
        num = td.xpath("./@num")
        if num and num[0]:
            row.append(float(num[0]))
        else:
            row.append("".join(td.xpath(".//text()")))
    if len(row) < 4:
        continue
    if header is None:
        header = row
    else:
        data.append(row)
df = pd.DataFrame(data, columns=header)
df

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

image-20210715000439499

可以看到这下子,数据就全部都读取出来了。

解析带有命名空间xml的标准方法

前面对于xmlns:x="urn:schemas-microsoft-com:office:excel"的命名空间,我没有找到好的方法解析,只能直接替换原始文本删除。当对于正常的带有命名空间的数据xpath还是有标准方法解析的。

比如对于如下xml:

from lxml import etree

xml = etree.parse("drawing1.xml")
print(etree.tostring(xml, pretty_print=True).decode("utf-8"))

  
 
  • 1
  • 2
  • 3
  • 4

image-20210715001703468

我们希望取出其中的a:blip节点下的r:embed属性:

namespaces = {"r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
              "a": "http://schemas.openxmlformats.org/drawingml/2006/main"}
for e in xml.xpath("//a:blip", namespaces=namespaces):
    print(etree.tostring(e).decode("utf-8"))
    print(e.xpath("./@r:embed", namespaces=namespaces)[0])

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
<a:blip xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing" cstate="print" r:embed="rId1"/>
rId1
<a:blip xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing" cstate="print" r:embed="rId2"/>
rId2
<a:blip xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing" cstate="print" r:embed="rId3"/>
rId3

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

可以看到对应的值都顺利获取到。

文章来源: xxmdmst.blog.csdn.net,作者:小小明-代码实体,版权归原作者所有,如需转载,请联系作者。

原文链接:xxmdmst.blog.csdn.net/article/details/118740991

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。