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

作者 | 云外孤岛

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

简介

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

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

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

代码思路

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. 返回一个排序好的数据

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

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元《动手学深度学习》一本。

社群福利

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

推荐阅读

  • 冠军奖3万元!CSDN×易观算法大赛开赛啦

  • 谁偷偷删了你的微信?别慌!Python帮你都揪出来了

  • 吐血整理!140种Python标准库、第三方库和外部工具都有了

  • 如何用爬虫技术帮助孩子秒到心仪的幼儿园(基础篇)

  • Python传奇:30年崛起之路

  • 干货 | Python后台开发的高并发场景优化解决方案

  • 2019年最新华为、BAT、美团、头条、滴滴面试题目及答案汇总

  • 阿里巴巴杨群:高并发场景下Python的性能挑战

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

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

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

    简介 想看看你最近一年都在干嘛?看看你平时上网是在摸鱼还是认真工作?想写年度汇报总结,但是苦于没有数据?现在,它来了. 这是一个能让你了解自己的浏览历史的Chrome浏览历史记录分析程序,当然了,他仅 ...

  2. python上网行为分析_转:用 Python 一键分析你的上网行为, 看是在认真工作还是摸鱼...

    简介 想看看你最近一年都在干嘛?看看你平时上网是在摸鱼还是认真工作?想写年度汇报总结,但是苦于没有数据?现在,它来了. 这是一个能让你了解自己的浏览历史的Chrome浏览历史记录分析程序,当然了,他仅 ...

  3. 一键将手机投屏到电脑上玩,这下摸鱼更方便了

    苏生不惑第291篇原创文章,将本公众号设为星标,第一时间看最新文章. 之前分享过很多Windows软件,今天分享几个能在电脑上操作手机的神器,这下上班摸鱼更方便了上班摸鱼又有了新姿势 新买了台笔记本电 ...

  4. 摸鱼气象Python教案代码分享

    摸鱼气象Python是大气科学领域内的一套有视频讲解,项目实战类的长期更新的教程. 其中涵盖了大量气象领域Python初学者需要用到的编程案例,如: 数据读取.数据处理.数值计算.数据可视化.数据分析 ...

  5. 用python一键去除图片、PDF水印

    嗨嗨,我是小圆,现在网络上的图片大多都有水印,我们每次找无水印的图片都有点难找. 但今天给大家分享一下 : 如何用python一键去除图片.PDF水印 看完学会后就不用担心 水印会影响阅读了 安装模块 ...

  6. 国美通报员工上班摸鱼,企业监控员工上网情况违法吗?

    来源:新财富/作者:杨亦静 去年,大厂为防员工"摸鱼"设置一系列如厕障碍的情况曾引发关注.前几天,国美通报员工看视频.刷抖音.听音乐等"摸鱼"行为,并给予相关处 ...

  7. 微商成功神器,python程序员教你,一键分析微信好友近期所有信息

    其他精彩内容:https://blog.csdn.net/weixin_45400881/article/details/95754294 几千个好友,怎么统计 相信做微商的微信好友都会很多,多到很多 ...

  8. python开发程序知道微信好友是否已读信息吗_微商成功神器,python程序员教你,一键分析微信好友近期所有信息...

    好友太多怎么保活 相信做微商的微信好友都会很多,多到很多都成了"僵尸"好友,但是想要成为一个成功的微商,要有两点: 1.好友多,基数决定高度 2."活的"好友多 ...

  9. python批量分析表格_python批量设置多个Excel文件页眉页脚的脚本

    python批量设置多个Excel文件页眉页脚的脚本 本文实例为大家分享了python批量设置多个Excel文件页眉页脚的具体代码,供大家参考,具体内容如下 import os import open ...

最新文章

  1. 给定二叉树先序、中序遍历序列,求后序遍历
  2. 关于我的Android 博客
  3. 判断仅有指针域的单链表是否有环且怎么找到环
  4. weblogic:local class incompatible: stream classdesc serialVersionUID
  5. Attempt to do update or delete on table db1.table1 that is not transactional解决
  6. 【软件工程】计算资源
  7. SpringMVC Hello(IDEA)
  8. 根据自己平时的经验写的针对SQLSERVER操作的通用类库
  9. hue 用oozie调度shell(sqoop)脚本问题
  10. c语言 由函数组成的数组,学生的记录由学号和成绩组成,N名学生的数据已在主函数中放入结构体数组s中,请编写函数fun(),它的_考题宝...
  11. 日期无忧,Python计算日期清单
  12. Java缓存技术-google guava cache
  13. 高等数学(第七版)同济大学 习题1-7 个人解答
  14. rs485接口上下拉_RS485上拉下拉电阻计算详解
  15. Android9.0 PM机制系列(一)PackageInstaller初始化解析
  16. python编写一个程序、判断用户输入的数是正数还是负数_编写一个程序,判断用户输入的数是正数还是负数。_学小易找答案...
  17. 我看过有一种莫名的动力,你呢?
  18. 手把手教你编译Flutter engine
  19. 银河麒麟4.0.2安装
  20. Qt系列文章之 QAbstractItemModel(中)

热门文章

  1. 在控制台上跳极乐净土 音频版
  2. EVE 一键齐发 (EVE 按键辅助工具V1.0发布)//注册请用留言,不要用评论//
  3. 物联网(IOT)基本概念探讨——门户帖2
  4. 离散元仿真-PFC,3DEC
  5. Electron - 用前端的技术开发桌面应用(二)
  6. html5女生,HTML5告诉你:女生应该怎么独立自强?
  7. Vj程序设计作业H6
  8. 基于FPGA的HDMI显示(一)
  9. 生活感悟——我对三句话的理解
  10. 《钢铁是怎样炼成的》中的名言警句