在家工作的第二周,用Python檢測你是在認真工作還是摸魚
簡介
想看看你最近都在干嘛?看看你在家辦公的時候是在摸魚還是認真工作?想寫匯報總結,但是苦于沒有數據?現在,它來了。
這是一個能讓你了解自己的瀏覽歷史的Chrome瀏覽歷史記錄分析程序,當然了,他僅適用于Chrome瀏覽器或者以Chrome為內核的瀏覽器。
在該頁面中你將可以查看有關自己在過去的時間里所訪問瀏覽的域名、URL以及忙碌天數的前十排名以及相關的數據圖表。
代碼思路
首先,我們先看一下整體目錄結構
Code├─ app_callback.py 回調函數,實現后臺功能├─ app_configuration.py web服務器配置├─ app_layout.py web前端頁面配置├─ app_plot.py web圖表繪制├─ app.py web服務器的啟動├─ assets web所需的一些靜態資源文件│ ├─ css web前端元素布局文件│ │ ├─ custum-styles_phyloapp.css│ │ └─ stylesheet.css│ ├─ image web前端logo圖標│ │ ├─ GitHub-Mark-Light.png│ └─ static web前端幫助頁面│ │ ├─ help.html│ │ └─ help.md├─ history_data.py 解析chrome歷史記錄文件└─ requirement.txt 程序所需依賴庫
app_callback.py
該程序基于python,使用dash web輕量級框架進行部署。app_callback.py主要用于回調,可以理解為實現后臺功能。
app_configuration.py
顧名思義,對web服務器的一些配置操作。
app_layout..py
web前端頁面配置,包含html, css元素。
app_plot.py
這個主要是為實現一些web前端的圖表數據。
app.py
web服務器的啟動。
assets
靜態資源目錄,用于存儲一些我們所需要的靜態資源數據。
history_data.py
通過連接sqlite數據庫,并解析Chrome歷史記錄文件。
requirement.txt
運行本程序所需要的依賴庫。
與解析歷史記錄文件數據有關的文件為history_data.py文件。我們一一分析。
# 查詢數據庫內容def query_sqlite_db(history_db, query):
# 查詢sqlite數據庫 # 注意,History是一個文件,沒有后綴名。它不是一個目錄。 conn = sqlite3.connect(history_db) cursor = conn.cursor()
# 使用sqlite查看軟件,可清晰看到表visits的字段url=表urls的字段id # 連接表urls和visits,并獲取指定數據 select_statement = query
# 執行數據庫查詢語句 cursor.execute(select_statement)
# 獲取數據,數據格式為元組(tuple) results = cursor.fetchall()
# 關閉 cursor.close() conn.close()
return results
該函數的代碼流程為:
連接sqlite數據庫,執行查詢語句,返回查詢結構,最終關閉數據庫連接。
# 獲取排序后的歷史數據def get_history_data(history_file_path):
try:
# 獲取數據庫內容 # 數據格式為元組(tuple) select_statement = "SELECT urls.id, urls.url, urls.title, urls.last_visit_time, urls.visit_count, visits.visit_time, visits.from_visit, visits.transition, visits.visit_duration FROM urls, visits WHERE urls.id = visits.url;" result = query_sqlite_db(history_file_path, select_statement)
# 將結果按第1個元素進行排序 # sort和sorted內建函數會優先排序第1個元素,然后再排序第2個元素,依此類推 result_sort = sorted(result, key=lambda x: (x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8]))
# 返回排序后的數據 return result_sort except: # print('讀取出錯!') return 'error'
該函數的代碼流程為:
設置數據庫查詢語句select_statement,調用query_sqlite_db()函數,獲取解析后的歷史記錄文件數據。并對返回后的歷史記錄數據文件按照不同元素規則進行排序。至此,經過排序的解析后的歷史記錄數據文件獲取成功。
與web服務器基本配置有關的文件為app_configuration.py和app.py文件。包括設置web服務器的端口號,訪問權限,靜態資源目錄等。
與前端部署有關的文件為app_layout.py和app_plot.py以及assets目錄。
前端布局主要包括以下幾個元素:
上傳歷史記錄文件組件
繪制頁面訪問次數組件
繪制頁面訪問停留總時間排名組件
每日頁面訪問次數散點圖組件
某日不同時刻訪問次數散點圖組件
訪問次數最多的10個URL組件
搜索關鍵詞排名組件
搜索引擎使用情況組件
在app_layout.py中,這些組件的配置大多一樣,和平常的html, css配置一樣,所以我們僅僅以配置頁面訪問次數排名組件為例子。
# 頁面訪問次數排名html.Div( style={'margin-bottom':'150px'}, children=[ html.Div( style={'border-top-style':'solid','border-bottom-style':'solid'}, className='row', children=[ html.Span( children='頁面訪問次數排名, ', style={'font-weight': 'bold', 'color':'red'} ),
html.Span( children='顯示個數:', ), dcc.Input( id='input_website_count_rank', type='text', value=10, style={'margin-top':'10px', 'margin-bottom':'10px'} ), ] ),
html.Div( style={'position': 'relative', 'margin': '0 auto', 'width': '100%', 'padding-bottom': '50%', }, children=[ dcc.Loading( children=[ dcc.Graph( id='graph_website_count_rank', style={'position': 'absolute', 'width': '100%', 'height': '100%', 'top': '0', 'left': '0', 'bottom': '0', 'right': '0'}, config={'displayModeBar': False}, ), ], type='dot', style={'position': 'absolute', 'top': '50%', 'left': '50%', 'transform': 'translate(-50%,-50%)'} ), ], ) ])
可以看到,雖然是python編寫的,但是只要具備前端經驗的人,都可以輕而易舉地在此基礎上新增或者刪除一些元素,所以我們就不詳細講如何使用html和css了。
在app_plot.py中,主要是以繪制圖表相關的。使用的是plotly庫,這是一個用于具有web交互的畫圖組件庫。
這里以繪制頁面訪問頻率排名 柱狀圖為例子,講講如何使用plotly庫進行繪制。
# 繪制 頁面訪問頻率排名 柱狀圖def plot_bar_website_count_rank(value, history_data):
# 頻率字典 dict_data = {}
# 對歷史記錄文件進行遍歷 for data in history_data: url = data[1] # 簡化url key = url_simplification(url)
if (key in dict_data.keys()): dict_data[key] += 1 else: dict_data[key] = 0
# 篩選出前k個頻率最高的數據 k = convert_to_number(value) top_10_dict = get_top_k_from_dict(dict_data, k)
figure = go.Figure( data=[ go.Bar( x=[i for i in top_10_dict.keys()], y=[i for i in top_10_dict.values()], name='bar', marker=go.bar.Marker( color='rgb(55, 83, 109)' ) ) ], layout=go.Layout( showlegend=False, margin=go.layout.Margin(l=40, r=0, t=40, b=30), paper_bgcolor='rgba(0,0,0,0)', plot_bgcolor='rgba(0,0,0,0)', xaxis=dict(title='網站'), yaxis=dict(title='次數') ) )
return figure
該函數的代碼流程為:
首先,對解析完數據庫文件后返回的history_data進行遍歷,獲得url數據,并調用url_simplification(url)對齊進行簡化。接著,依次將簡化后的url存入字典中。
調用get_top_k_from_dict(dict_data, k),從字典dict_data中獲取前k個最大值的數據。
接著,開始繪制柱狀圖了。使用go.Bar()繪制柱狀圖,其中,x和y代表的是屬性和屬性對應的數值,為list格式。xaxis和yaxis`分別設置相應坐標軸的標題
返回一個figure對象,以便于傳輸給前端。
而assets目錄下包含的數據為image和css,都是用于前端布局。
與后臺部署有關的文件為app_callback.py文件。這個文件使用回調的方式對前端頁面布局進行更新。
首先,我們看看關于頁面訪問頻率排名的回調函數:
# 頁面訪問頻率排名@app.callback( dash.dependencies.Output('graph_website_count_rank', 'figure'), [ dash.dependencies.Input('input_website_count_rank', 'value'), dash.dependencies.Input('store_memory_history_data', 'data') ])def update(value, store_memory_history_data):
# 正確獲取到歷史記錄文件 if store_memory_history_data: history_data = store_memory_history_data['history_data'] figure = plot_bar_website_count_rank(value, history_data) return figure else: # 取消更新頁面數據 raise dash.exceptions.PreventUpdate("cancel the callback")
該函數的代碼流程為:
首先確定好輸入是什么(觸發回調的數據),輸出是什么(回調輸出的數據),需要帶上什么數據。dash.dependencies.Input指的是觸發回調的數據,而dash.dependencies.Input('input_website_count_rank', 'value')表示當id為input_website_count_rank的組件的value發生改變時,會觸發這個回調。而該回調經過update(value, store_memory_history_data)的結果會輸出到id為graph_website_count_rank的value,通俗來講,就是改變它的值。
對于def update(value, store_memory_history_data)的解析。首先是判斷輸入數據store_memory_history_data是否不為空對象,接著讀取歷史記錄文件history_data,接著調用剛才所說的app_plot.py文件中的plot_bar_website_count_rank(),返回一個figure對象,并將這個對象返回到前端。至此,前端頁面的布局就會顯示出頁面訪問頻率排名的圖表了。
還有一個需要說的就是關于上次文件的過程,這里我們先貼出代碼:
# 上傳文件回調@app.callback(
dash.dependencies.Output('store_memory_history_data', 'data'), [ dash.dependencies.Input('dcc_upload_file', 'contents') ])def update(contents):
if contents is not None:
# 接收base64編碼的數據 content_type, content_string = contents.split(',')
# 將客戶端上傳的文件進行base64解碼 decoded = base64.b64decode(content_string)
# 為客戶端上傳的文件添加后綴,防止文件重復覆蓋 # 以下方式確保文件名不重復 suffix = [str(random.randint(0,100)) for i in range(10)] suffix = "".join(suffix) suffix = suffix + str(int(time.time()))
# 最終的文件名 file_name = 'History_' + suffix # print(file_name)
# 創建存放文件的目錄 if (not (exists('data'))): makedirs('data')
# 欲寫入的文件路徑 path = 'data' + '/' + file_name
# 寫入本地磁盤文件 with open(file=path, mode='wb+') as f: f.write(decoded)
# 使用sqlite讀取本地磁盤文件 # 獲取歷史記錄數據 history_data = get_history_data(path)
# 獲取搜索關鍵詞數據 search_word = get_search_word(path)
# 判斷讀取到的數據是否正確 if (history_data != 'error'): # 找到 date_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) print('新接收到一條客戶端的數據, 數據正確, 時間:{}'.format(date_time)) store_data = {'history_data': history_data, 'search_word': search_word} return store_data else: # 沒找到 date_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) print('新接收到一條客戶端的數據, 數據錯誤, 時間:{}'.format(date_time)) return None
return None
該函數的代碼流程為:
首先判斷用戶上傳的數據contents是否不為空,接著將客戶端上傳的文件進行base64解碼。并且,為客戶端上傳的文件添加后綴,防止文件重復覆蓋,最終將客戶端上傳的文件寫入本地磁盤文件。
寫入完畢后,使用sqlite讀取本地磁盤文件,若讀取正確,則返回解析后的數據,否則返回None
接下來,就是我們數據提取最核心的部分了,即從Chrome歷史記錄文件中提取出我們想要的數據。由于Chrome歷史記錄文件是一個sqlite數據庫,所以我們需要使用數據庫語法提取出我們想要的內容。
# 獲取排序后的歷史數據def get_history_data(history_file_path):
try:
# 獲取數據庫內容 # 數據格式為元組(tuple) select_statement = "SELECT urls.id, urls.url, urls.title, urls.last_visit_time, urls.visit_count, visits.visit_time, visits.from_visit, visits.transition, visits.visit_duration FROM urls, visits WHERE urls.id = visits.url;" result = query_sqlite_db(history_file_path, select_statement)
# 將結果按第1個元素進行排序 # sort和sorted內建函數會優先排序第1個元素,然后再排序第2個元素,依此類推 result_sort = sorted(result, key=lambda x: (x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8]))
# 返回排序后的數據 return result_sort except: # print('讀取出錯!') return 'error'
上面select_statement指的是查詢數據庫的規則,規則如下:
從(FROM)表urls中選擇(SELECT)出以下字段urls.id, urls.url, urls.title, urls.last_visit_time, urls.visit_count,依次代表URL的ID,URL的地址,URL的標題,URL最后的訪問時間,URL的訪問次數。
接著,從(FROM)表visits中選擇(SELECT)出以下字段visits.visit_time, visits.from_visit, visits.transition, visits.visit_duration,分別代表的是訪問時間,從哪個鏈接跳轉過來的,訪問跳轉,訪問停留的時間。
對步驟1和步驟2的結果進行連接,形成一個表格。然后從中(WHERE)篩選出符合urls.id = visits.url的行。在urls中,id代表的是URL的id,在visits中,url代表的也是URL的id,所以只有當兩者相等,才能連接一起,才能保留,否則就要去除這一行。
使用排序函數sorted,這個函數依次是以x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7],x[8]進行排序,也就是指的是urls.id, urls.url, urls.title, urls.last_visit_time, urls.visit_count, visits.visit_time, visits.from_visit, visits.transition, visits.visit_duration。
返回一個排序好的數據
這里我們列出每個字段代表的意思:
字段名?含義
urls.id
url的編號
urls.url
url的地址
urls.title
url的標題
urls.last_visit_time
url的最后訪問時間
urls.visit_count
url的訪問次數
urls.visit_time
url的訪問時間
urls.from_visit
從哪里訪問到這個url
urls.transition
url的跳轉
urls.visit_duration
url的停留時間
歷史記錄文件位置:
C:Users%USERNAME%AppDataLocalGoogleChromeUser DataDefaultHistory
拷貝歷史記錄文件到桌面:
bash # 打開命令行cmd,輸入以下命令, 自動將History文件復制到桌面, 文件名為History, 沒有后綴名 copy "C:Users%USERNAME%AppDataLocalGoogleChromeUser DataDefaultHistory" "C:Users%USERNAME%DesktopHistory"
注意說明:?%USERNAME%為你的用戶名, 如果執行命令出現錯誤, 請手動找到該歷史記錄文件。
歷史記錄文件位置:
C:Documents and Settings%USERNAME%Local SettingsApplication DataGoogleChromeUser DataDefaultHistory
拷貝歷史記錄文件到桌面:
# 打開命令行cmd,輸入以下命令, 自動將History文件復制到桌面, 文件名為History, 沒有后綴名
copy "C:Documents and Settings%USERNAME%Local SettingsApplication DataGoogleChromeUser DataDefaultHistory" "C:Documents and Settings%USERNAME%DesktopHistory"
注意說明:?%USERNAME%為你的用戶名, 如果執行命令出現錯誤, 請手動找到該歷史記錄文件。
歷史記錄文件位置:
~/Library/Application Support/Google/Chrome/Default/History
拷貝歷史記錄文件到桌面:
bash # 打開terminal,輸入以下命令, 自動將History文件復制到桌面, 文件名為History, 沒有后綴名 cp ~/Library/Application Support/Google/Chrome/Default/History ~/Desktop/History
注意說明:?Application Support中的空格需要轉義,所以改為Application Support
歷史記錄文件位置:?~/.config/google-chrome/Default/History
拷貝歷史記錄文件到桌面:
bash # 打開terminal,輸入以下命令, 自動將History文件復制到桌面, 文件名為History, 沒有后綴名 cp ~/.config/google-chrome/Default/History ~/Desktop/History
注意說明:?如果提示路徑不存在, 請自行獲取History文件
如何運行
在線演示程序:http://39.106.118.77:8090(普通服務器,勿測壓)
運行本程序十分簡單,只需要按照以下命令即可運行:
# 跳轉到當前目錄cd 目錄名# 先卸載依賴庫pip uninstall -y -r requirement.txt# 再重新安裝依賴庫pip install -r requirement.txt# 開始運行python app.py
# 運行成功后,通過瀏覽器打開http://localhost:8090
完整版源代碼已存放到github
掃碼回復關鍵詞【摸魚】即可下載
A
螞蟻森林背后的灰色產業鏈!
B
我在支付寶1分鐘查到了對象的開房記錄!
C
你見過哪些要命的奇葩代碼!
D
AI斗圖,你OUT了!
“掃一掃,關注我的公眾號”
Python web前端 數據庫
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。