用Python一键分析你的上网行为,看是在认真工作还是摸鱼

640?wx_fmt=jpeg

2019 AI ProCon“598元学生票”限量抢购中!3日通票团购倒计时6天,扫码查看▲

作者 | 云外孤岛

出自 | Python那些事(ID:pPythonSomething)

简介

想看看你最近一年都在干嘛?看看你平时上网是在摸鱼还是认真工作?想写年度汇报总结,但是苦于没有数据?现在,它来了。

这是一个能让你了解自己的浏览历史的Chrome浏览历史记录分析程序,当然了,他仅适用于Chrome浏览器或者以Chrome为内核的浏览器。

在该页面中你将可以查看有关自己在过去的时间里所访问浏览的域名、URL以及忙碌天数的前十排名以及相关的数据图表。

640?wx_fmt=png

640?wx_fmt=png

640?wx_fmt=png

640?wx_fmt=png

640?wx_fmt=png

640?wx_fmt=png

640?wx_fmt=png


代码思路

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

  • app_configuration.py

  • app_layout..py

  • app_plot.py

  • app.py

  • assets

  • history_data.py

  • 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

该函数的代码流程为:

连接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()函数,获取解析后的历史记录文件数据。并对返回后的历史记录数据文件按照不同元素规则进行排序。至此,经过排序的解析后的历史记录数据文件获取成功。

3. web服务器基本配置

与web服务器基本配置有关的文件为app_configuration.py和app.py文件。包括设置web服务器的端口号,访问权限,静态资源目录等。

4. 前端页面部署

与前端部署有关的文件为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

该函数的代码流程为:

  1. 首先,对解析完数据库文件后返回的history_data进行遍历,获得url数据,并调用url_simplification(url)对齐进行简化。接着,依次将简化后的url存入字典中。

  2. 调用get_top_k_from_dict(dict_data, k),从字典dict_data中获取前k个最大值的数据。

  3. 接着,开始绘制柱状图了。使用go.Bar()绘制柱状图,其中,x和y代表的是属性和属性对应的数值,为list格式。xaxis和yaxis`分别设置相应坐标轴的标题

  4. 返回一个figure对象,以便于传输给前端。

而assets目录下包含的数据为image和css,都是用于前端布局。

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')表示当id为input_website_count_rank的组件的value发生改变时,会触发这个回调。而该回调经过update(value, store_memory_history_data)的结果会输出到id为graph_website_count_rank的value,通俗来讲,就是改变它的值。

  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数据库,所以我们需要使用数据库语法提取出我们想要的内容。

# 获取排序后的历史数据	
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的ID,URL的地址,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. 返回一个排序好的数据

这里我们列出每个字段代表的意思:

640?wx_fmt=png

6. 如何获取Chrome历史记录文件

Windows Vista, Windows 7, Windows 8, Windows 10
  • 历史记录文件位置: 

    C:Users%USERNAME%AppDataLocalGoogleChromeUser DataDefaultHistory

  • 拷贝历史记录文件到桌面:

  • 注意说明: %USERNAME%为你的用户名, 如果执行命令出现错误, 请手动找到该历史记录文件。

Windows XP
  • 历史记录文件位置:

    C:Documents and Settings%USERNAME%Local SettingsApplication DataGoogleChromeUser DataDefaultHistory

  • 拷贝历史记录文件到桌面:

  • 注意说明: %USERNAME%为你的用户名, 如果执行命令出现错误, 请手动找到该历史记录文件。

Mac OS X
  • 历史记录文件位置: 

    ~/Library/Application Support/Google/Chrome/Default/History

  • 拷贝历史记录文件到桌面:

  • 注意说明: Application Support中的空格需要转义,所以改为Application Support

Linux/ Unix
  • 历史记录文件位置: ~/.config/google-chrome/Default/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上,有需要的可以下载

https://github.com/shengqiangzhang/examples-of-web-crawlers/tree/master/11.一键分析你的上网行为(web页面可视化)

项目持续更新,欢迎您star本项目。

(*本文为Python大本营转载,转载请联系原作者)

精彩推荐

2019 AI开发者大会」 除了邀请国内外一线公司重磅嘉宾外,还邀请到了亚马逊首席科学家@李沐,他将于9月5日亲授「深度学习实训营」,通过动手实操,帮助开发者全面了解深度学习的基础知识和开发技巧。原价1099元,目前福利价199元!且现场赠送价值85元《动手学深度学习》一本。

640?wx_fmt=jpeg

社群福利

扫码添加小助手,回复:大会,加入2019 AI开发者大会福利群,每周更新技术福利,还有不定期的抽奖活动~

640?wx_fmt=jpeg

推荐阅读

640?wx_fmt=png

你点的每个“在看”,我都认真当成了喜欢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值