用Python將數據自動轉成Execl實現自動化辦公


背景

公司項目的廣告展示率太低,需要查找原因,之前做了統計埋點,運維給出過濾後的數據,一個 txt 文件 500M 以上,文件打開非常亂。

在這裡還是提醒下,很多人學Python過程中會遇到各種煩惱問題,沒有人解答容易放棄。為此我建了個python學習資源圈裡面有最新學習資料,如果你想學或者正在學python,可以關注我,後臺私信我 ‘p’ 免費獲取!還有老司機解答哦

用Python將數據自動轉成Execl實現自動化辦公

代碼

詢問運維是否有工具轉換,回覆說沒有,然後想到之前重學 Python3 的初衷,就是為了能寫一些腳本方便處理一些事情。

這個數據主要是 HTTP 的 GET 請求,需要轉碼,然後把參數拿到,目標是寫到 Execl 文件中。

因為一直沒用,語法也記不清楚,只能不停回看筆記,關於 Execl 這塊也沒用過,臨時網上查找。

讀文件

由於原文件太大,所以先複製了一部分存入當前目錄的 test.txt 文件中。

<code>import os

file = open('./test.txt') # 打開文件
for line in file: # 按行遍歷文件
...

file.close() # 最後要關閉
/<code>

遍歷每一行數據後,轉碼,分割,轉成字典結構

<code>import urllib.parse

# 定義個方法將一行數據轉成字典
def getOneDict(line):
params = dict() # 創建字典保存數據


pre = 'timeAnalysis?'
index = line.find(pre) # 找到這個位置,後面的數據是需要的參數
if index > -1:
line = line[index+len(pre):].split()[0] # 先截子串然後選空格之前的
line = urllib.parse.unquote(line) # 網上搜到的用於將 HTTP 編碼後的文字解碼
paramList = line.split('&') # 得到類似 s=android 的內若

for item in paramList:
param = item.split('=')
if (len(param) > 1): # 如果等於號後面有值
params[param[0]] = param[1] # 字典加個數據
return params
/<code>

創建 Execl 文件

有了每一行對應的字典,就想把這內容寫到 Execl 文檔裡。要先切換到 pip3 目錄,執行 sudo pip3 install openpyxl 安裝 openpyxl 模塊,最新的語法參考 http://openpyxl.readthedocs.io/en/stable/

<code>import openpyxl

def createExcel():
if 'time.xlsx' in os.listdir('./'): # 如果有了這個文件,就不要再創建了
return

wb = openpyxl.Workbook() # 創建 Execl
wb.active.title = 'Splash' # 默認有一個活動的 Sheet,把名字改成 Splash
wb.create_sheet(title='Home') # 再創建一個 Sheet
wb.save('time.xlsx') # 最後一定不能忘了這句
/<code>

結果本地生成了文件 time.xlsx,打開後有兩個 Sheet。

用Python將數據自動轉成Execl實現自動化辦公

表格


向 Execl 中插入數據

看 Execl,橫向是 A、B、C... 這樣編號,縱向是 1、2、3... 這樣編號,看文檔可以通過兩個編號組合來定位。我這裡沒用這個函數。

我需要把字典裡的 key 作為第一行用作標題,然後每來一個字典裡的數據,先尋找是否有了這個 key,有了就往下一行添加對應的 value,沒有的話先添加一列,行數是第一行,值是字典裡的這個 key,然後再添加 value。

<code>def writeToExecl(params):
wb = openpyxl.load_workbook('time.xlsx') # 打開 Execl 文件
splashSheet = wb['Splash'] # 找到兩個 Sheet
homeSheet = wb['Home']
if params['pid'] == '04': # 如果字典裡有一個 pid=04 的,要放到 Splash 表裡
writeToSheet(splashSheet, wb, params)
elif params['pid'] == '00':
writeToSheet(homeSheet, wb, params)
/<code>
<code>def getValue(t):
return t.value

def writeToSheet(sheet, wb, params):
rows = tuple(sheet.rows) # 拿到所有行轉成元組
index = len(rows) + 1 # 在原有的行數的下一行插入數據
print('rows ' + str(index))
titles = list(map(getValue, rows[0])) # 用高階函數 map 轉換第一行,拿到裡面的 value,然後要轉成 list

if titles == [None]: # 測試發現列表不是空的,長度是 1,裡面是 None,所以判斷一下
titles = []

for k,v in params.items(): # 遍歷字典
if k in titles: # 如果第一行有這個標題,直接插值
sheet.cell(row = index, column = titles.index(k) + 1).value = v # 行數為 index,列為這個 key 在的行,cell 裡的索引從 1 開始
else:
sheet.cell(row = 1, column = len(titles) + 1).value = k # 先插標題,先插了一列
sheet.cell(row = index, column = len(titles) + 1).value = v # 再插字典的 value
titles.append(k) # 標題多了一個,要更新
wb.save('time.xlsx') # 保存以生效
/<code>

遍歷文件

將要分析的文件放入當前目錄的 web 文件夾下,然後遍歷,對每一個文件進行讀取。

<code>for file in os.listdir('./web'):
print('read file ' + os.path.basename(file))
readAFile('./web/' + file)

def readAFile(filename):
file = open(filename)
for line in file:
params = getOneDict(line)
if (len(params) == 0): # 如果字典為空,繼續下一行
continue
writeToExecl(params)
file.close()
/<code>

其它

運行時報出了一個錯誤

<code>...
self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x80 in position 3131: invalid start byte ...
/<code>

網上搜了下,是編碼的問題,沒去特地解決,一兩行數據不影響統計比例,找到一種方法,打開文件時忽略錯誤。

<code>file = open(filename, errors='ignore')
/<code>

還有生成的文件名,要分析文件的路徑等可以通過命令行參數傳入,這樣可用性高些,就不搞了。

整體做下來,其實功能很簡單,但是由於對語言的不熟悉,花了不少時間,map 這個高級函數還是因為 Kotlin,Rx 裡都有類似的,所以搜了下才知道,有些不知道的可能就寫繁瑣了。

文件太大,寫入時間太長,只運行了一會看了一些數據,分析出大概的原因,最終還是讓運營再去過濾分析比例的。

結果

源代碼

<code>import os
import urllib.parse
import openpyxl
import sys

# 將一行數據轉成字典
def getOneDict(line):

params = dict() # 創建字典保存數據

pre = 'timeAnalysis?'
index = line.find(pre)
if index > -1:
line = line[index+len(pre):].split()[0]
line = urllib.parse.unquote(line)
paramList = line.split('&')

for item in paramList:
param = item.split('=')
if (len(param) > 1):
params[param[0]] = param[1]
return params

def createExcel():
if 'time.xlsx' in os.listdir('./'):
return

wb = openpyxl.Workbook() # 創建Execl
wb.active.title = 'Splash'
wb.create_sheet(title='Home')
wb.save('time.xlsx')

def writeToExecl(params):
wb = openpyxl.load_workbook('time.xlsx')
splashSheet = wb['Splash']
homeSheet = wb['Home']
if params['pid'] == '04': # 開屏
writeToSheet(splashSheet, wb, params)
elif params['pid'] == '00': # 首頁
writeToSheet(homeSheet, wb, params)

def getValue(t):
return t.value

def writeToSheet(sheet, wb, params):
rows = tuple(sheet.rows)
index = len(rows) + 1 # 從這一行開始插入數據

titles = list(map(getValue, rows[0])) # 拿到第1行的內容,做標題用
if titles == [None]:
titles = []

for k,v in params.items():

if k in titles:

sheet.cell(row = index, column = titles.index(k) + 1).value = v
else:
sheet.cell(row = 1, column = len(titles) + 1).value = k # 先插標題
sheet.cell(row = index, column = len(titles) + 1).value = v
titles.append(k) # 更新標題
wb.save('time.xlsx')

def readAFile(filename):
file = open(filename, errors='ignore')
for line in file:
params = getOneDict(line)
if (len(params) == 0):
continue
writeToExecl(params)
file.close()

createExcel()

for file in os.listdir('./web'):
print('read file ' + os.path.basename(file))
readAFile('./web/' + file)
/<code>

生成 Execl 如下


用Python將數據自動轉成Execl實現自動化辦公

表格數據

最後在這裡還是提醒下,很多人學Python過程中會遇到各種煩惱問題,沒有人解答容易放棄。為此我建了個python學習資源圈裡面有最新學習資料,如果你想學或者正在學python,可以關注我,後臺私信我 ‘p’ 免費獲取!還有老司機解答哦!
本文的文字及圖片來源於網絡加上自己的想法,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯繫我們以作處理。


分享到:


相關文章: