最真實(shí)的辦公自動化案例!
在數(shù)據(jù)分析的日常工作中,除了Excel數(shù)據(jù)的清洗,最常見的就是pdf、word、ppt等場景下的數(shù)據(jù)清洗,這種其實(shí)還有一個更高大上的名字,叫:辦公自動化。
很多時候由于辦公自動化場景下的數(shù)據(jù)是不規(guī)整的,所以在進(jìn)行數(shù)據(jù)分析之前首要的就是進(jìn)行數(shù)據(jù)提取。
例如,小一的朋友『長河』在實(shí)際工作中遇到的真實(shí)問題:

雖然我自己對word的操作不是很熟悉,但是我也在思考過后提供了自己的解決方法:

由于我自己對于PDF的數(shù)據(jù)提取比較擅長,也曾經(jīng)寫過相關(guān)的操作文檔:Python辦公自動化之PDF的詳細(xì)操作(全),所以如果原始數(shù)據(jù)是pdf,那我就會按照上面我說的方法進(jìn)行操作
但是長河他自己已經(jīng)搞定了pdf的轉(zhuǎn)換,那問題就變成了多個word的數(shù)據(jù)提取。
下面的文章就是他自己在實(shí)現(xiàn)過程中的真實(shí)思路,部分?jǐn)?shù)據(jù)比較敏感,文中已經(jīng)打碼,但是不影響實(shí)際的閱讀和練手
這個也是在實(shí)際工作中比較常遇到的問題,希望大家下次遇到的時候都能游刃有余
以下是『長河』投稿的正文:
1. 問題來源
最近面臨的一個問題是從word中讀取表格數(shù)據(jù),然后整理成excel格式。
如下所示:

如果表格不是很多,只有幾張表,完全手動處理就好,但是如果有140張表,9年的數(shù)據(jù),該怎么處理呢?
這個時候需要程序來幫我們自動化解決了。
2.?解決問題
明確問題之后,我們接下來需要解決問題。
如果要從word中提取表格,常用的包有docx , 對提取中的數(shù)據(jù)進(jìn)行規(guī)范處理,需要使用pandas
2.1 明確數(shù)據(jù)的行和列
如果要提取word表格中的行和列,則需要明白這個表格到底有多少行和列,然后再根據(jù)具體行和列進(jìn)行數(shù)據(jù)的提取。
該部分內(nèi)容可以參看B站的上的一些視頻,用Python操作Word
代碼如下:
from?docx?import?Document
doc?=?Document('one.docx')
tables?=?doc.tables
table?=?tables[0]??#?表示讀取的第一張表
#?查看一下多少行,多少列
print(len(table.rows),len(table.columns))
輸出結(jié)果為:
5?14
說明我們提取的表格信息是一個5行14列的數(shù)據(jù)。接下來需要思考,每一行每一列是什么樣子。
我們這里以第5行第2列為例進(jìn)行說明:
繼續(xù)寫入代碼為:
print(table.cell(4,1).text)
輸出結(jié)果為:
13905
270
5583
1528
1791
2315
2439
...
經(jīng)過不斷地嘗試,我們終于知道自己需要的數(shù)據(jù)在什么地方了。
考慮到表頭的太過于復(fù)雜,不好定位,需要自己重新寫表頭信息即可,我們需要的是整個學(xué)校的數(shù)據(jù),也就是下圖中的部分

2.2 數(shù)據(jù)提取
接下來進(jìn)行數(shù)據(jù)提取:
list1?=?[]??#?定義一個空的列表存儲數(shù)據(jù)
for?row?in?range(4,len(table.rows)):
????for?column?in?range(len(table.columns)):
????????list1.append(table.cell(row,column).text)
print(len(list1))
print(list1)
提取出來的數(shù)據(jù)是一串很長的列表,輸出結(jié)果為:
14
['--大學(xué)\--大學(xué)\--大學(xué)\---大學(xué)\n????----\n2186588\n203224\n146649\n329602\n214014\n299323\n47413\n71033']
接下來進(jìn)行迭代,轉(zhuǎn)化成 [[],[],[]] 的形式
values?=?[]
for?i?in?list1:
????i?=?i.split('\n')
????values.append(i)
print(values)
結(jié)果處理完成,結(jié)果如下:
[['xx大學(xué)',?'xxxx大學(xué)',?'xx大學(xué)',?---'xxxx大學(xué)'],---?['2186588',?'203224',?'146649',?'329602',?'214014',?'299323',?'47413',?'71033']]
2.3 轉(zhuǎn)成 DataFrame格式
前面已經(jīng)把values整理好了,接下來重新整理表頭信息即可:
colums?=?['xx','xx','xx']
data_part1?=?pd.DataFrame(values,columns).T
print(data_part1.head())
輸出結(jié)果為:
?????學(xué)校名稱???????xxxxxx-??...????????xxxx??????xxxxxxx
0????XX大學(xué)??????????13905??...????????46526?????2222470
1????XX大學(xué)???????????270??...????????????0???????67822
2????XX大學(xué)???????????5583??...???????331010?????3557540
3????XX大學(xué)???????????1528??...????????12826??????544980
4????XX大學(xué)???????????1791??...?????????1270??????844921
[5?rows?x?14?columns]
考慮到一個word文件有兩張表,第二張表的數(shù)據(jù)結(jié)構(gòu)如下:

第二張表的表頭與第一張表有所不同,處理方式一樣,直接上代碼即可:
table?=?tables[1]
for?row?in?range(3,?len(table.rows)):
????for?column?in?range(len(table.columns)):
????????table2.append(table.cell(row,?column).text)
for?h?in?table2:
????h?=?h.split('\n')
????values2.append(h)
data2?=?pd.DataFrame(values2,column2).T
data?=?pd.concat([data1,data2],axis?=1)
2.4 完整地處理一張表
一張完整的word有兩張表,所以需要使用一個判斷條件進(jìn)行處理,將其分為奇數(shù)位表和偶數(shù)位表,其判斷依據(jù)是某數(shù)除以2余數(shù)是否為 0,
具體的代碼如下:
import?pandas?as?pd
from?docx?import?Document
column1?=?['xx','xx','xx','xx','xx']
column2?=?['xx','xx','xx','xx','xx']
for?t?in?range(len(tables)):
????if?t?%?2?==?0:
????????table1?=?[]
????????value1?=?[]
????????table?=?docx.tables[t]
????????for?row?in?range(4,?len(table.rows)):
????????????for?column?in?range(len(table.columns)):
?????????????????table1.append(table.cell(row,?column).text)
????????for?j?in?table1:
?????????????j?=?j.split('\n')
?????????????value1.append(j)
????????data1?=?pd.DataFrame(value1,?column1).T
????if?t?%?2?==?1:
????????table2?=?[]
????????value2?=?[]
????????table?=?docx.tables[t]
????????for?row?in?range(3,?len(table.rows)):
?????????????for?column?in?range(len(table.columns)):
?????????????????table2.append(table.cell(row,?column).text)
????????for?h?in?table2:
????????????????h?=?h.split('\n')
????????????????value2.append(h)
????????data2?=?pd.DataFrame(value2,column2).T
data?=?pd.concat([data1,data2],axis?=1)
2.5 完整地處理多張表
如果是處理多張表,則需要設(shè)置路徑,然后在具體的路徑中進(jìn)行處理
具體的代碼如下:
import?pandas?as?pd
from?docx?import?Document
import?os
column1?=?['xx','xx','xx','xx','xx']
column2?=?['xx','xx','xx','xx','xx']
#?設(shè)置路徑
path?=?os.listdir('E:\one-two')
#?print(path)
for?i?in?range(len(path)):
????docx?=?Document('E:\one-two\{}'.format(path[i]))
????#?print('第{}表'.format(i+1),docx)
????tables?=?docx.tables
????for?t?in?range(len(tables)):
????????if?t?%?2?==?0:
????????????table1?=?[]
????????????value1?=?[]
????????????table?=?docx.tables[t]
????????????for?row?in?range(4,?len(table.rows)):
????????????????for?column?in?range(len(table.columns)):
????????????????????table1.append(table.cell(row,?column).text)
????????????for?j?in?table1:
????????????????j?=?j.split('\n')
????????????????value1.append(j)
????????????data1?=?pd.DataFrame(value1,?column1).T
????????if?t?%?2?==?1:
????????????table2?=?[]
????????????value2?=?[]
????????????table?=?docx.tables[t]
????????????for?row?in?range(3,?len(table.rows)):
????????????????for?column?in?range(len(table.columns)):
????????????????????table2.append(table.cell(row,?column).text)
????????????for?h?in?table2:
????????????????h?=?h.split('\n')
????????????????value2.append(h)
????????????data2?=?pd.DataFrame(value2,column2).T
????data?=?pd.concat([data1,data2],axis?=1)
????print('正在保存{}'.format(i+1))
????data.to_excel('E:\one-two\{}.xlsx'.format(i),index=False)
最后的輸出結(jié)果為:
3. 總結(jié)
學(xué)習(xí)編程會遇到很多問題和困惑。但是這個也是提高自己編程技術(shù)的關(guān)鍵所在。不斷地探索,看B站視頻,請教大佬,然后不停地print看輸出結(jié)果,就會得到自己想要的東西!
感謝小一前輩提供的思路,筆芯筆芯!
一個word一個word的處理,這樣反而能提高效率!
推薦閱讀
牛逼!Python常用數(shù)據(jù)類型的基本操作(長文系列第①篇)
牛逼!Python的判斷、循環(huán)和各種表達(dá)式(長文系列第②篇)
推薦閱讀
牛逼!Python常用數(shù)據(jù)類型的基本操作(長文系列第①篇)
牛逼!Python的判斷、循環(huán)和各種表達(dá)式(長文系列第②篇)
