轉:用 Python 一鍵分析你的上網行為, 看是在認真工作還是摸魚

来源:https://www.cnblogs.com/xxpythonxx/archive/2019/08/23/11402618.html
-Advertisement-
Play Games

簡介 想看看你最近一年都在幹嘛?看看你平時上網是在摸魚還是認真工作?想寫年度彙報總結,但是苦於沒有數據?現在,它來了。 這是一個能讓你瞭解自己的瀏覽歷史的Chrome瀏覽歷史記錄分析程式,當然了,他僅適用於Chrome瀏覽器或者以Chrome為內核的瀏覽器。 在該頁面中你將可以查看有關自己在過去的時 ...


簡介

想看看你最近一年都在幹嘛?看看你平時上網是在摸魚還是認真工作?想寫年度彙報總結,但是苦於沒有數據?現在,它來了。

這是一個能讓你瞭解自己的瀏覽歷史的Chrome瀏覽歷史記錄分析程式,當然了,他僅適用於Chrome瀏覽器或者以Chrome為內核的瀏覽器。

在該頁面中你將可以查看有關自己在過去的時間里所訪問瀏覽的功能變數名稱、URL以及忙碌天數的前十排名以及相關的數據圖表。

部分截圖

img

代碼思路

1. 目錄結構

首先,我們先看一下整體目錄結構

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
    運行本程式所需要的依賴庫。

2. 解析歷史記錄文件數據

與解析歷史記錄文件數據有關的文件為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

該函數的代碼流程為:

  1. 連接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'

該函數的代碼流程為:

  1. 設置資料庫查詢語句select_statement,調用query_sqlite_db()函數,獲取解析後的歷史記錄文件數據。並對返回後的歷史記錄數據文件按照不同元素規則進行排序。至此,經過排序的解析後的歷史記錄數據文件獲取成功。

3. web伺服器基本配置

與web伺服器基本配置有關的文件為app_configuration.pyapp.py文件。包括設置web伺服器的埠號,訪問許可權,靜態資源目錄等。

4. 前端頁面部署

與前端部署有關的文件為app_layout.pyapp_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

該函數的代碼流程為:

  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目錄下包含的數據為imagecss,都是用於前端佈局。

5. 後臺部署

與後臺部署有關的文件為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對象,並將這個對象返回到前端。至此,前端頁面的佈局就會顯示出頁面訪問頻率排名的圖表了。

還有一個需要說的就是關於上次文件的過程,這裡我們先貼出代碼:

# 上傳文件回調
@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

該函數的代碼流程為:

  1. 首先判斷用戶上傳的數據contents是否不為空,接著將客戶端上傳的文件進行base64解碼。並且,為客戶端上傳的文件添加尾碼,防止文件重覆覆蓋,最終將客戶端上傳的文件寫入本地磁碟文件。

  2. 寫入完畢後,使用sqlite讀取本地磁碟文件,若讀取正確,則返回解析後的數據,否則返回None

接下來,就是我們數據提取最核心的部分了,即從Chrome歷史記錄文件中提取出我們想要的數據。由於Chrome歷史記錄文件是一個sqlite資料庫,所以我們需要使用資料庫語法提取出我們想要的內容。

'''
遇到問題沒人解答?小編創建了一個Python學習交流QQ群:857662006 
尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書!
'''
# 獲取排序後的歷史數據
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指的是查詢資料庫的規則,規則如下:

  1. 從(FROM)表urls中選擇(SELECT)出以下欄位urls.id, urls.url, urls.title, urls.last_visit_time, urls.visit_count,依次代表URL的IDURL的地址URL的標題URL最後的訪問時間URL的訪問次數
  2. 接著,從(FROM)表visits中選擇(SELECT)出以下欄位visits.visit_time, visits.from_visit, visits.transition, visits.visit_duration,分別代表的是訪問時間從哪個鏈接跳轉過來的訪問跳轉訪問停留的時間
  3. 步驟1步驟2的結果進行連接,形成一個表格。然後從中(WHERE)篩選出符合urls.id = visits.url的行。在urls中,id代表的是URL的id,在visits中,url代表的也是URL的id,所以只有當兩者相等,才能連接一起,才能保留,否則就要去除這一行。
  4. 使用排序函數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
  5. 返回一個排序好的數據

這裡我們列出每個欄位代表的意思:

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

6. 如何獲取Chrome歷史記錄文件

  1. 首先,打開瀏覽器,輸入chrome://version/,其中,個人資料路徑即為存放歷史文件所在的目錄。
    img
  2. 跳轉到個人資料路徑,比如/Users/xxx/Library/Application Support/Google/Chrome/Default,找到一個叫History的文件,這個文件即為歷史記錄文件。
    img

如何運行

線上演示程式:http://39.106.118.77:8090(普通伺服器,勿測壓)

運行本程式十分簡單,只需要按照以下命令即可運行:

# 跳轉到當前目錄
cd 目錄名
# 先卸載依賴庫
pip uninstall -y -r requirement.txt
# 再重新安裝依賴庫
pip install -r requirement.txt
# 開始運行
python app.py

# 運行成功後,通過瀏覽器打開http://localhost:8090

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1、文件上傳簡單流程分析圖: 2、Fastdfs介紹: Fastdfs由兩個角色組成: Tracker(集群):調度(幫你找到有空閑的Storage) Storage(集群):文件存儲(幫你保存文件或獲取需要的文件) 流程: 1.Storage和tracker 發送心跳連接。 2.客戶端請求trac ...
  • 在有些業務場景下,我們需要兩個完全相同卻彼此無關的java對象。比如使用原型模式、多線程編程等。對此,java提供了深拷貝的概念。通過深度拷貝可以從源對象完美複製出一個相同卻與源對象彼此獨立的目標對象。這裡的相同是指兩個對象的狀態和動作相同,彼此獨立是指改變其中一個對象的狀態不會影響到另外一個對象。 ...
  • 創建群自定義機器人 在指定釘釘群(或者隨便拉兩個人建個群,然後把別人T出去)的群設置里選擇 群機器人 自定義,如圖: 然後,添加機器人,設置名字,添加成功時如下圖: 其中webhook非常重要,下文詳述。點擊設置說明可以看相關使用文檔,文檔鏈接見本文末尾。 使用HTTP POST請求發送消息 直接向 ...
  • 題目描述 又是一年秋季時,陶陶家的蘋果樹結了n個果子。陶陶又跑去摘蘋果,這次她有一個a公分的椅子。當他手夠不著時,他會站到椅子上再試試。 這次與NOIP 2005普及組第一題不同的是:陶陶之前搬凳子,力氣只剩下s了。當然,每次摘蘋果時都要用一定的力氣。陶陶想知道在s<! more 輸入格式 第1行: ...
  • INTRODUCTION: 在一個無向圖中,如果有一個頂點集合,刪除這個頂點集合以及這個集合中所有頂點相關聯的邊以後,圖的連通分量增多,就稱這個點集為割點集合。 如果某個割點集合只含有一個頂點X(也即{X}是一個割點集合),那麼X稱為一個割點。--百度百科 首先,什麼是割點? 在一個有N個節點,M條 ...
  • 一、起源 1960年Lisp語言: 第一門真正使用記憶體動態分配和垃圾回收的語言。 二、概要 線程相關:程式計數器、虛擬機棧、本地方法棧,不需要考慮垃圾回收 Java堆、方法區:需要考慮垃圾回收 三、垃圾回收演算法 1 引用計數演算法 2 可達性分析演算法 垃圾收集演算法 1 標記-清除演算法 Mark-Swe ...
  • 個人博客搭建線上實施方案 實施方案 方案一:GithubPages 1. 創建 "Github" 賬號 2. 創建倉庫, 倉庫名為:.github.io 3. 將本地Hexo博客推送到GithubPages 3.1. 安裝 插件。在命令行(即Git Bash)運行以下命令即可: 3.2. 添加SSH ...
  • 功能要求: ​ 相關源碼:碼雲:傳送門,GitHub:傳送門 相關圖片: 拆分版 make編譯 ​ ./hotel運行 ​ 輸入2,進入開房模塊 ​ 相關源碼: class.cpp 1 #include <fstream> 2 #include "tools.h" 3 #include "class ...
一周排行
    -Advertisement-
    Play Games
  • Timer是什麼 Timer 是一種用於創建定期粒度行為的機制。 與標準的 .NET System.Threading.Timer 類相似,Orleans 的 Timer 允許在一段時間後執行特定的操作,或者在特定的時間間隔內重覆執行操作。 它在分散式系統中具有重要作用,特別是在處理需要周期性執行的 ...
  • 前言 相信很多做WPF開發的小伙伴都遇到過表格類的需求,雖然現有的Grid控制項也能實現,但是使用起來的體驗感並不好,比如要實現一個Excel中的表格效果,估計你能想到的第一個方法就是套Border控制項,用這種方法你需要控制每個Border的邊框,並且在一堆Bordr中找到Grid.Row,Grid. ...
  • .NET C#程式啟動閃退,目錄導致的問題 這是第2次踩這個坑了,很小的編程細節,容易忽略,所以寫個博客,分享給大家。 1.第一次坑:是windows 系統把程式運行成服務,找不到配置文件,原因是以服務運行它的工作目錄是在C:\Windows\System32 2.本次坑:WPF桌面程式通過註冊表設 ...
  • 在分散式系統中,數據的持久化是至關重要的一環。 Orleans 7 引入了強大的持久化功能,使得在分散式環境下管理數據變得更加輕鬆和可靠。 本文將介紹什麼是 Orleans 7 的持久化,如何設置它以及相應的代碼示例。 什麼是 Orleans 7 的持久化? Orleans 7 的持久化是指將 Or ...
  • 前言 .NET Feature Management 是一個用於管理應用程式功能的庫,它可以幫助開發人員在應用程式中輕鬆地添加、移除和管理功能。使用 Feature Management,開發人員可以根據不同用戶、環境或其他條件來動態地控制應用程式中的功能。這使得開發人員可以更靈活地管理應用程式的功 ...
  • 在 WPF 應用程式中,拖放操作是實現用戶交互的重要組成部分。通過拖放操作,用戶可以輕鬆地將數據從一個位置移動到另一個位置,或者將控制項從一個容器移動到另一個容器。然而,WPF 中預設的拖放操作可能並不是那麼好用。為瞭解決這個問題,我們可以自定義一個 Panel 來實現更簡單的拖拽操作。 自定義 Pa ...
  • 在實際使用中,由於涉及到不同編程語言之間互相調用,導致C++ 中的OpenCV與C#中的OpenCvSharp 圖像數據在不同編程語言之間難以有效傳遞。在本文中我們將結合OpenCvSharp源碼實現原理,探究兩種數據之間的通信方式。 ...
  • 一、前言 這是一篇搭建許可權管理系統的系列文章。 隨著網路的發展,信息安全對應任何企業來說都越發的重要,而本系列文章將和大家一起一步一步搭建一個全新的許可權管理系統。 說明:由於搭建一個全新的項目過於繁瑣,所有作者將挑選核心代碼和核心思路進行分享。 二、技術選擇 三、開始設計 1、自主搭建vue前端和. ...
  • Csharper中的表達式樹 這節課來瞭解一下表示式樹是什麼? 在C#中,表達式樹是一種數據結構,它可以表示一些代碼塊,如Lambda表達式或查詢表達式。表達式樹使你能夠查看和操作數據,就像你可以查看和操作代碼一樣。它們通常用於創建動態查詢和解析表達式。 一、認識表達式樹 為什麼要這樣說?它和委托有 ...
  • 在使用Django等框架來操作MySQL時,實際上底層還是通過Python來操作的,首先需要安裝一個驅動程式,在Python3中,驅動程式有多種選擇,比如有pymysql以及mysqlclient等。使用pip命令安裝mysqlclient失敗應如何解決? 安裝的python版本說明 機器同時安裝了 ...