之前我在翻找浏览器历史记录的时候发现,单独查询某一天的记录很方便,但是综合分析一段时间的浏览记录就比较困难。通过查询得知,Chrome浏览器的历史记录数据存储在名为History的sqlite数据库文件中。
所以我打算通过python编写一个能够分析一段时间内浏览记录的程序,并且通过图表的形式将分析结果展示在网页上,分析结果包括浏览时间、次数、搜索引擎偏好等等。
(1)程序能运行,功能丰富。(需求提交源代码,并建议录制程序运行的视频)
(2)综合实践报告,要体现实验分析、设计、实现过程、结果等信息,格式规范,逻辑清晰,结构合理。
(3)在实践报告中,需要对全课进行总结,并写课程感想体会、意见和建议等。

与解析历史记录文件数据有关的文件为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‘
至此,成功获取经过排序的解析后的浏览记录数据文件。
与web服务器基本配置有关的文件为app_configuration.py和app.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‘)
与前端部署有关的文件为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%)‘}
                ),
            ],
        )
    ]
)
在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
该函数的代码流程为:
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目录下包含的数据为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对象,并将这个对象返回到前端。至此,前端页面的布局就会显示出页面访问频率排名的图表了。接下来,就是从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的停留时间 | 

运行成功后,通过浏览器打开http://localhost:8090:

上传浏览器History文件后,即可看到分析结果:



本次实验中我遇到了很多问题。例如由于Chrome浏览器在sqlite中存储的时间是以1601-01-01 00:00:00 为起始时间点的微妙计数,与Unix时间戳存在时间间隔,所以需要转换,这给我造成了很大困扰。
但通过查询相关资料,我最终解决了这些问题,这也是对我综合实践能力的一次提升。
    这学期很幸运地选到了志强老师的Python课。我一开始以为在Python理论课上,应该就是老师照着PPT念(古板印象),同学们在底下各干各的。但是出乎意料的是,志强老师的理论课十分有趣,理论课也需要我们带着电脑跟着一起敲代码,不仅如此,志强老师的课上也会联系其他知识,例如知识点在实际项目中的应用、与其他编程语言的对比。其中令我印象深刻的是,志强老师在讲到序列的时候,用了王者荣耀英雄的案例,一下子感觉很熟悉(亲切)。
    除此以外,课程的实验也设置得十分合理,有层次地由易到难、由浅到深,让我在每次实验过程中都能有全新的收获。正如志强老师在课程之初提到的“人生苦短,我用Python”,通过课程学习,我有了更深的体会。希望编程语言在我们日常生活中应该更多地被使用,这才是编程解决实际问题的魅力所在。
    最后,再次感谢志强老师的教导,希望Python课程能越办越好!!!
20204311《Python程序设计》实验四 Python综合实践实验报告
原文:https://www.cnblogs.com/jam12138/p/14956750.html