Python处理表格数据的一些常见(坑)问题的心得

前不久领导安排让我对一些业务数据按照指定口径进行整理为Excel给他。由于我们对该系统只有使用权,不可能通过后台数据库直接查询,只能通过前台进行查询。而且该系统开发时间比较早,不支持导出CSV格式的数据。虽然提供了导出XLS文件的功能,但其实质是html表格,每超过5000条数据,就会分文件存储,最终返回一个zip压缩文档。

大约要获取30多个查询页面的数据,每个页面大约要获取3-8万条不等的数据,粗略估计要处理200多个html表格。虽然简单的机械劳动(Ctrl+C,Ctrl+V)可以处理这个问题,但那简直就是个噩梦。所以,我决定用Python来处理这个噩梦。

由于刚刚开始学习Python,我只是一个萌新,所以我遇到的问题,也都是很多新手遇到的问题。所以和大家分享一下我的心得。

通常我都是采用openpyxl来生成Excel文件,毕竟这都0202年了,谁还用xls文档啊。但是,我才发现,实际业务总比网上的例子复杂的多。

1.尽量不要用list存储要向worksheet写入的数据。不少介绍openpyxl使用的文章里,都有类似这样的代码

wb = Workbook()
ws = wb['Sheet1']
data = list()
data.append('data1')
data.append('data2')

ws.append(data)
ws.save(filename)

这样,确实可行,但实际上如果认真学过Python基础的话,就知道list(列表)不能存储重复数据,如果你获取的一行数据中,有多个空值或相同数值,这个完全不可用。所以,还是老老实实用dict(字典)吧。

2.尽量不要用Cell来处理数据

由于我的数据来源是html网页(虽然文件扩展名是xls),需要保存为Excel(xlsx),所以第一时间想到用Beautifusoup来分析页面,通过遍历tr和td标签,最后通过cell写入到excel中去,这样的代码有很多,我就不具体写了,大意如下。

#获取网页中的table
soup = BeautifulSoup(open(filename, encoding='utf-8', errors="replace").read(),'lxml')
tables = soup.find('table',attrs={'border':1})
row = 0
col = 0
for tr in tables.find_all('tr'):
    row += 1
    for td in tr.find_all('td'):
        col += 1
        ws.cell(row=row,column=col).value = td.getText()
    col = 0
#wb是openpyxl的workbook
wb.save(filename.replace(".xls"," - fixed.xlsx"))

处理一个文件时,大概用了30+s,但是当读取多个文件进行合并时,发现效率急转直下,尤其是openpyxl的save操作,特别耗时,连续处理5个文件后,第6个文件居然要处理30分钟。可见这种方式对于处理少量数据还是可行的,同时也要减少Python对磁盘的读写操作。

3.大量数据尽量使用pandas

pandas对于初学者还是有一点点难度的,不过——真香。我最终选择的技术方式为lxml的etree读取html文件内容,用xpath获取表格,用pandas的read_html导入数据到df,最后用to_excel导出为excel文件,转换一个文件才用时12s左右。文件合并采用pandas的concat,将多个df合并为一个df,再导出为excel文件,转换15个文件并保存,只用时3分钟。共用时0.2m*15+3m=6分钟,30多个查询也就不到4个小时就全搞定了(我给领导说需要3天时间才能弄完~~┓(;´_`)┏)。

4.dataframe导出excel的格式问题

由于业务数据中什么数据都有,既有20位的数字,也有电话号码,时间,日期这类数据,导出到Excel后,会有各种意想不到的格式问题,考虑到其中没有公式,而且excel也不用于计算,最后索性将所有字段转换为了字符格式。尤其是数据中的超长数字,设置numpy后,df中确实可以正确显示所有数字,但写入excel后,就会变为科学计数法。网上的方法对于特定列(即针对指定列名称进行修改)是有效的,但对于不确定列,由于excel.py中进行了强制转换,网上目前所有办法均不可行,除非修改底层库文件。所以这个办法虽然暴力,但确实有效。

#这个只是获取df标题的其中一种方式
header_list = df.columns.tolist()
for header in header_list:
    df[header] = df[header].astype(str)
#处理Nan,一定要处理
df.fillna('',inplace=True)

最后处理Nan,同时使用inplace=True,确保数据被替换掉。

最后再和各位萌新分享几点心得。

(1)基础知识一定要牢固,python的语法虽然很灵活,但也是把双刃剑。
(2)python不太适合初学编程的人员,感觉很多地方还是需要有一些基础技术知识的。
(3)多阅读一下库文件的源码,里面的docs有很多不错的例子和说明
(4)如果你不是大神,别没事造轮子,如果发现有一段代码过于复杂,不如求助或搜索一下,看有没有其他合适的库来帮你处理数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值