想看看你最近一年都在幹嗎?看看你平時上網是在摸魚仍是認真工做?想寫年度彙報總結,可是苦於沒有數據?如今,它來了。html
這是一個能讓你瞭解本身的瀏覽歷史的Chrome瀏覽歷史記錄分析程序,固然了,他僅適用於Chrome瀏覽器或者以Chrome爲內核的瀏覽器。前端
在該頁面中你將能夠查看有關本身在過去的時間裏所訪問瀏覽的域名、URL以及忙碌天數的前十排名以及相關的數據圖表。python
首先,咱們先看一下總體目錄結構git
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
主要用於回調,能夠理解爲實現後臺功能。github
app_configuration.py
顧名思義,對web服務器的一些配置操做。web
app_layout..py
web前端頁面配置,包含html, css元素。sql
app_plot.py
這個主要是爲實現一些web前端的圖表數據。chrome
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
該函數的代碼流程爲:
# 獲取排序後的歷史數據 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
目錄。
前端佈局主要包括如下幾個元素:
在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的停留時間 |
首先,打開瀏覽器,輸入chrome://version/
,其中,我的資料路徑
即爲存放歷史文件所在的目錄。
跳轉到我的資料路徑
,好比/Users/xxx/Library/Application Support/Google/Chrome/Default
,找到一個叫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上,有須要的能夠下載
項目持續更新,歡迎您star本項目