基于python分析你的上网行为 看看你平时上网都在干嘛


Posted in Python onAugust 13, 2019

简介

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

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

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

部分截图

基于python分析你的上网行为 看看你平时上网都在干嘛

代码思路

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

该函数的代码流程为:

连接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对象,以便于传输给前端。
  5. 而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")

该函数的代码流程为:

首先确定好输入是什么(触发回调的数据),输出是什么(回调输出的数据),需要带上什么数据。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对象,并将这个对象返回到前端。至此,前端页面的布局就会显示出页面访问频率排名的图表了。
还有一个需要说的就是关于上次文件的过程,这里我们先贴出代码:

# 上传文件回调
@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

该函数的代码流程为:

首先判断用户上传的数据contents是否不为空,接着将客户端上传的文件进行base64解码。并且,为客户端上传的文件添加后缀,防止文件重复覆盖,最终将客户端上传的文件写入本地磁盘文件。
写入完毕后,使用sqlite读取本地磁盘文件,若读取正确,则返回解析后的数据,否则返回None

如何运行

在线演示程序: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上,有需要的可以下载

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
c++生成dll使用python调用dll的方法
Jan 20 Python
跟老齐学Python之集合(set)
Sep 24 Python
举例讲解Linux系统下Python调用系统Shell的方法
Nov 07 Python
wxpython中自定义事件的实现与使用方法分析
Jul 21 Python
在pandas中一次性删除dataframe的多个列方法
Apr 10 Python
解决PyCharm import torch包失败的问题
Oct 13 Python
Python3 修改默认环境的方法
Feb 16 Python
Python + OpenCV 实现LBP特征提取的示例代码
Jul 11 Python
Python新手学习raise用法
Jun 03 Python
Python类super()及私有属性原理解析
Jun 15 Python
Python plt 利用subplot 实现在一张画布同时画多张图
Feb 26 Python
Python中的datetime包与time包包和模块详情
Feb 28 Python
Python实现微信翻译机器人的方法
Aug 13 #Python
python读写csv文件的方法
Aug 13 #Python
python根据多个文件名批量查找文件
Aug 13 #Python
详解django实现自定义manage命令的扩展
Aug 13 #Python
Python一键安装全部依赖包的方法
Aug 12 #Python
Python之time模块的时间戳,时间字符串格式化与转换方法(13位时间戳)
Aug 12 #Python
浅谈Python2之汉字编码为unicode的问题(即类似\xc3\xa4)
Aug 12 #Python
You might like
基于CakePHP实现的简单博客系统实例
2015/06/28 PHP
百度地图API使用方法详解
2015/08/25 PHP
PHP常用函数之格式化时间操作示例
2019/10/21 PHP
js验证表单大全
2006/11/25 Javascript
$()JS小技巧
2007/07/21 Javascript
图片Slider 带左右按钮的js示例
2013/08/30 Javascript
JavaScript fontsize方法入门实例(按照指定的尺寸来显示字符串)
2014/10/17 Javascript
JS和JQ的event对象区别分析
2014/11/24 Javascript
windows8.1+iis8.5下安装node.js开发环境
2014/12/12 Javascript
JQuery复制DOM节点的方法
2015/06/11 Javascript
浅谈jquery中的each方法$.each、this.each、$.fn.each
2016/06/23 Javascript
通过javascript进行UTF-8编码的实现方法
2016/06/27 Javascript
浅谈JS的基础类型与引用类型
2016/09/13 Javascript
Javascript中常见的逻辑题和解决方法
2016/09/17 Javascript
js鼠标按键事件和键盘按键事件用法实例汇总
2016/10/03 Javascript
angular实现form验证实例代码
2017/01/17 Javascript
微信小程序swiper组件用法实例分析【附源码下载】
2017/12/07 Javascript
微信小程序使用form表单获取输入框数据的实例代码
2018/05/17 Javascript
浅谈VueJS SSR 后端绘制内存泄漏的相关解决经验
2018/12/20 Javascript
vue或react项目生产环境去掉console.log的操作
2020/09/02 Javascript
vue中实现点击空白区域关闭弹窗的两种方法
2020/12/30 Vue.js
python 文件操作api(文件操作函数)
2016/08/28 Python
python使用PIL给图片添加文字生成海报示例
2018/08/17 Python
python在CMD界面读取excel所有数据的示例
2020/09/28 Python
python 下载文件的多种方法汇总
2020/11/17 Python
关于pycharm 切换 python3.9 报错 ‘HTMLParser‘ object has no attribute ‘unescape‘ 的问题
2020/11/24 Python
使用HTML5 Canvas绘制圆角矩形及相关的一些应用举例
2016/03/22 HTML / CSS
HTML5响应式(自适应)网页设计的实现
2017/11/17 HTML / CSS
域名注册、建站工具、网页主机、SSL证书:Dynadot
2017/01/06 全球购物
Belstaff英国官方在线商店:Belstaff.co.uk
2021/02/09 全球购物
巴西最大的玩具连锁店:Ri Happy
2020/06/17 全球购物
《我爱祖国》演讲稿1000字
2014/09/26 职场文书
搞笑结婚保证书
2015/05/08 职场文书
详解Django中 render() 函数的使用方法
2021/04/22 Python
SpringCloud Alibaba 基本开发框架搭建过程
2021/06/13 Java/Android
教你如何让spark sql写mysql的时候支持update操作
2022/02/15 MySQL