1. 程式人生 > 其它 >20204311 《Python程式設計》實驗四:Python綜合實踐——瀏覽記錄分析

20204311 《Python程式設計》實驗四:Python綜合實踐——瀏覽記錄分析

簡介

  • 實驗名稱:Python綜合實踐——瀏覽記錄分析
  • 課程:《Python程式設計》
  • 班級: 2043
  • 姓名: 曲經民
  • 學號:20204311
  • 實驗教師:王志強
  • 實驗日期:2021年6月
  • 必修/選修: 選修課

實驗內容

之前我在翻找瀏覽器歷史記錄的時候發現,單獨查詢某一天的記錄很方便,但是綜合分析一段時間的瀏覽記錄就比較困難。通過查詢得知,Chrome瀏覽器的歷史記錄資料儲存在名為History的sqlite資料庫檔案中。
所以我打算通過python編寫一個能夠分析一段時間內瀏覽記錄的程式,並且通過圖表的形式將分析結果展示在網頁上,分析結果包括瀏覽時間、次數、搜尋引擎偏好等等。

實驗要求

(1)程式能執行,功能豐富。(需求提交原始碼,並建議錄製程式執行的視訊)
(2)綜合實踐報告,要體現實驗分析、設計、實現過程、結果等資訊,格式規範,邏輯清晰,結構合理。
(3)在實踐報告中,需要對全課進行總結,並寫課程感想體會、意見和建議等。

實驗過程及結果

一. 實現應用的關鍵步驟設計

二. 程式碼編寫及除錯執行

1. 解析歷史記錄檔案資料

與解析歷史記錄檔案資料有關的檔案為history_data.py檔案。

# 連線sqlite資料庫,執行查詢語句,返回查詢結構,最終關閉資料庫連線。
def query_sqlite_db(history_db, query):

    # 查詢sqlite資料庫
    conn = sqlite3.connect(history_db)
    cursor = conn.cursor()
    select_statement = query
    cursor.execute(select_statement)

    # 獲取資料,資料格式為元組(tuple)
    results = cursor.fetchall()
    cursor.close()
    conn.close()

    return results

# 設定資料庫查詢語句select_statement,呼叫query_sqlite_db()函式,獲取解析後的歷史記錄檔案資料。並對返回後的歷史記錄資料檔案按照不同元素規則進行排序。
def get_history_data(history_file_path):

    try:
        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個元素進行排序
        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'

至此,成功獲取經過排序的解析後的瀏覽記錄資料檔案。

2. web伺服器基本配置

與web伺服器基本配置有關的檔案為app_configuration.pyapp.py檔案。
本專案使用dash框架。

dash是一款基於python的web輕量級框架,無需js即可輕鬆執行。
適合用於比較簡單的web頁面的快速部署,如資料視覺化,圖表展示等。

import dash

# 配置一個dash伺服器
app = dash.Dash(__name__)

#設定web伺服器的埠號,訪問許可權,靜態資源目錄等

# 設定網頁標題
app.title = 'Browser History Analysis'

# 開啟載入本地css和js檔案模式
app.css.config.serve_locally = True
app.scripts.config.serve_locally = True
app.layout = app_layout

# 回撥,用於更新web頁面資料
app_callback_function()

# 開始執行web伺服器
if __name__ == '__main__':


    # 是否是在本地執行(測試)
    app_local = False
    if(app_local):
        app.run_server(host='127.0.0.1', debug=True, port='8090')
    else:
        app.run_server(host='0.0.0.0', debug=False, port='8090')

3. 前端頁面部署

與前端部署有關的檔案為app_layout.pyapp_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%)'}
                ),
            ],
        )
    ]
)

app_plot.py中,使用plotly庫繪製圖表。plotly庫是一個用於具有web互動功能的畫圖元件庫。

# 繪製 頁面訪問頻率排名 柱狀圖
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

該函式的程式碼流程為:

  1. 首先,對解析完資料庫檔案後返回的history_data進行遍歷,獲得url資料,並呼叫url_simplification(url)對齊進行簡化。接著,依次將簡化後的url存入字典中。
  2. 呼叫get_top_k_from_dict(dict_data, k),從字典dict_data中獲取前k個最大值的資料。
  3. 接著,開始繪製柱狀圖。使用go.Bar()繪製柱狀圖,其中,xy代表的是屬性和屬性對應的數值,為list格式xaxisyaxis`分別設定相應座標軸的標題。
  4. 返回一個figure物件,以便於傳輸給前端。

assets目錄下包含的資料為css,用於前端佈局。

4. 後臺部署

與後臺部署有關的檔案為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")

該函式的程式碼流程為:

  1. 首先確定好輸入是什麼(觸發回撥的資料),輸出是什麼(回撥輸出的資料),需要帶上什麼資料。dash.dependencies.Input指的是觸發回撥的資料,而dash.dependencies.Input('input_website_count_rank', 'value')表示當idinput_website_count_rank的元件的value發生改變時,會觸發這個回撥。而該回調經過update(value, store_memory_history_data)的結果會輸出到idgraph_website_count_rankvalue
  2. 對於def update(value, store_memory_history_data)的解析。首先是判斷輸入資料store_memory_history_data是否不為空物件,接著讀取歷史記錄檔案history_data,接著呼叫剛才所說的app_plot.py檔案中的plot_bar_website_count_rank(),返回一個figure物件,並將這個物件返回到前端。至此,前端頁面的佈局就會顯示出頁面訪問頻率排名的圖表了。

接下來,就是從Chrome歷史記錄檔案中提取出想要的資料。由於Chrome歷史記錄檔案是一個sqlite資料庫,所以需要使用資料庫語法提取出相關內容。

# 獲取排序後的歷史資料
def get_history_data(history_file_path):

    try:
        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個元素進行排序
        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'

每個欄位代表的意思:

欄位名 含義
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的停留時間

5.程式碼調式及執行


執行成功後,通過瀏覽器開啟http://localhost:8090:

上傳瀏覽器History檔案後,即可看到分析結果:


三. 將程式碼上傳碼雲

實驗中遇到的問題

本次實驗中我遇到了很多問題。例如由於Chrome瀏覽器在sqlite中儲存的時間是以1601-01-01 00:00:00 為起始時間點的微妙計數,與Unix時間戳存在時間間隔,所以需要轉換,這給我造成了很大困擾。
但通過查詢相關資料,我最終解決了這些問題,這也是對我綜合實踐能力的一次提升。

思想感悟