我用Java+SeimiCrawler+Redis+ES+Kibana技术对数百万知乎用户进行了数据分析,得到了这些......
点击上方“方志朋”,选择“设为星标”
回复”666“获取新整理的面试资料
作者:_artoria_
来源:http://tinyurl.com/quscxyl
# 前言
我是一个真正的知乎小白。
上班的时候,自己手头的事情处理完了,我除了在掘金摸鱼,就是在知乎逛贴。在我的认知中,知乎是一个高质量论坛,基本上各种“疑难杂症”都能在上面找到相应的专业性回答。但平时逗留在知乎的时间过多,我不知道自己是被知乎上面的精彩故事所吸引,还是为知乎上面的高深技术而着迷。
咱是理科生,不太懂过于高深的哲学,自然不会深层次地剖析自己,只能用数据来说话。于是,就有了这篇博客。
# 结构图
结构图如上所示。这篇博客主要讲述两件事:爬取知乎用户数据和对用户数据进行分析。这个结构图基本能够概述分析知乎用户信息的思路,具体的思路详述和技术实现细节可看博客后面的内容。
# 爬取知乎用户数据
1 知乎用户页面解析
我的知乎主页信息预览如下:
从该页面的内容来看,我当前需要爬取的知乎信息就在两个红框中。然后每个知乎用户主页对应的URL路径应该不一样,这里URL中标识是我的主页就是mi-zhi-saber,这个URL标识就是知乎里面的url_token。也就是说拿到足够多的url_token,就可以自己组装URL来获取用户的信息。
通过分析知乎页面结构,我们可以按照如下思路来爬取用户信息:
1.基于用户的个人主页信息,爬取、解析并保存用户信息。
上面用户主页链接对应的页面内容如下:
对比这两个页面,可以推断出里面部分字段的意义(其实字段名称已经足够见名知意了)。综合考虑后,我要爬取的字段及其意义如下
2.基于用户关注的知乎用户信息,爬取、解析并保存用户信息。
我关注的知乎用户信息页面内容如下:
3. 基于关注用户的知乎用户信息,爬取、解析并保存用户信息。
理论上,选取一个知乎大V作为根节点,迭代爬取关注者和被关注者的信息,可以拿到绝大部分的知乎用户信息。
选取爬虫框架
要想对知乎用户进行画像,必须拿到足够多的知乎用户数据。简单来说,就是说要用java爬虫爬取足够多的知乎用户数据。
工欲善其事,必先利其器。常见的Java爬虫框架有很多如:
webmagic,crawler4j,SeimiCrawler,jsoup等等。这里选用的是SpringBoot + SeimiCrawler,这个方式可以几乎零配置地使用爬虫爬取知乎用户数据。具体如何使用可见于SeimiCrawler官方文档。
使用反反爬手段
论坛是靠内容存活的。如果有另外一个盗版论坛大量地爬取知乎内容,然后拷贝到自己的论坛上,知乎肯定会流失大量用户。不用想就知道,知乎肯定是采取了一些反爬手段的。
最常见的反爬手段就是User Agent识别和IP限流。简单解释一下,就是知乎会基于用户访问记录日志,分析哪个用户(IP)用哪个浏览器(UA)访问知乎网站的,如果某个用户极其频繁地访问知乎网站,知乎就会把该用户标记为“疑似爬虫的机器人”,然后让该用户进行登录验证或直接将该用户对应的IP地址进行封禁。
然后,所谓的“反反爬手段”,就是应对上面所说的反爬手段的。我采取的“反反爬手段”是:
1.收集一些常用的UA,然后每次调用接口访问知乎网站的时候会刷新所使用的UA。
2.自己在项目中维护一个可高用的免费代理池,每次调用接口访问知乎网站的时候会使用高可用代理池的随机一个代理。
实际实践过程中,提供了免费代理的网站有:西刺代理、89免费代理、云代理等等,但实际能够使用的还是只有西刺代理。
而且西刺代理的可用数也非常少,导致代理池中可用代理数很少,使用代理池的效果不是很好,这真的是一件很沮丧的事。
免费代理池的架构及其实现思路图:
简述一下思路:
1.启动项目时,会自动去爬取西刺代理网站前10页的代理(共1000个代理),并将其保存到RabbitMQ中。RabbitMQ设置有10个消费者,每个消费者会检测代理是否可用,检测完毕后会将该代理的信息及其检测结果保存到DB中。
2.系统设置了一个定时任务,会定时将DB中当前的所有代理再次放到RabbitMQ中,会由10个消费者检测代理是否可用,并将检测结果同时更新到DB中。如果连续3次测试代理不可用,则将该代理从DB中删除。
3.系统设置了一个定时任务,会定时爬取西刺代理网首页的所有代理,会检测代理的可用性,并将其信息及检测结果再次保存到DB中。这样保证DB中会定时获取更多的代理(实际原因是西刺代理可用代理太少,如果不定时获取更多代理,DB中很快就没有可用的代理了)。
4.系统设置了一个定时任务,会自动删除redis中所有的代理。然后再将DB中的代理按检测成功次数进行排序,将连续成功次数最多的前10个代理保存进redis中。这样redis中的代理就是高可用的。
调用接口爬取数据
项目一定程度地屏蔽了代理池以及知乎用户数据解析的实现复习性,以暴露接口的方式提供爬取知乎用户信息的功能。
在配置好Redis/RabbitMQ环境后,成功启动项目,等项目稳定后(需要等到redis中有高可用的代理,否则就是用本机IP直接进行数据爬取,这样的话本机IP很容易会被封)后,即可通过调用如下接口的方式爬取知乎用户信息。
1.调用接口localhost:8980/users爬取指定知乎用户的信息,修改url_token的值即可爬取不同知乎用户的信息。
2.调用接口localhost:8980/users/followees爬取关注指定知乎用户的用户信息,修改url_token的值即可爬取关注不同知乎用户的用户信息。
调用接口localhost:8980/users/followers爬取指定知乎用户关注的用户信息,修改url_token的值即可爬取不同知乎用户关注的用户信息。
在实际测试爬取知乎网站用户信息的过程中,如果系统只用一个固定IP进行爬取数据,基本爬取不到10万数据该IP就会被封。使用了代理池这种方式后,由于西刺代理网址上可用的免费代理太少了,最终爬取到167万左右数据后,代理池中基本就没有可用的IP了。不过爬取到这么多的数据已经够用了。
# 分析知乎用户数据
数据去重
爬取了167万+知乎用户数据后,需要对原始数据进行简单的清理,这里就是去重。每个知乎用户有唯一的url_token,由于这里爬取的是用户的关注者与被关注者,很容易就会有重复的数据。
数据量有167万+,使用Java自带的去重容器Set/Map明显不合适(内存不够,就算内存足够,去重的效率也有待考量)。
项目中实现了一个简单的布隆算法,能够保证过滤后的知乎用户数据绝对没有重复。
布隆算法的实现思路图如下:
简述布隆算法的实现思路如下:
1.首先初始化一个位容器(每个容器单位的值只能是0或1),并先规定好要使用映射数据用的n个hash方法,hash方法的结果对应于该位容器的一个下标。
2.每次存数据之前,需要先判断该容器中是否已经存过该数据。该数据对应所有hash方法的结果,对应在位容器中的下标只要有一个下标对应的单位的值为0,则表示该容器还没有存过该数据,否则就判定为该容器之前存过该数据。
3.每次存数据之后,需要将该数据所有hash方法结果对应于位容器中的下标的值,都置为1。
这里需要说明一下为什么要使用布隆算法以及布隆算法还有什么缺点。
使用布隆算法的理由:我们是依靠url_token来判断一个用户是否重复的,但url_token的长度是不确定的,这里存放一个url_token所需要的空间按上图DB中来看基本上有10字节以上。如果使用java容器进行去重,那么该容器至少需要的空间:10 * 1670000 byte 即大约15.93MB(这里貌似还是可以使用java容器进行去重,但其实这里还没有考虑容器中还需要存的其他信息)。而使用布隆算法,需要的空间:n * 1670000 bit ,使用的hash方法一般是3-10个左右,即一般至多只需要15.9KB左右的空间(我在项目中使用的是2 << 24 bit即16KB的容量)。如果数据量继续增大,布隆算法的优势会越来越大。
布隆算法的缺点:很明显地,这种hash映射存储的方式肯定会有误判的情况。即bitSet容器中明明没有存储该数据,却认为之前已经存储过该数据。但是只要hash方法的个数以及其实现设计得合理,那么这个误判率能够大大降低(笔者水平有限,具体怎么降低并计算误判率可自行谷歌或百度)。而且基于大数据分析来说,一定数据的缺失是可以允许的,只要保证过滤后有足够的不重复的数据进行分析就行。
项目中屏蔽了布隆算法实现的复杂性,直接调用接口localhost:8980/users/filter,即可将DB中的用户数据进行去重。
过滤之后,还有160万左右不重复的数据,说明布隆算法误判率导致的数据流失,对大量的数据来说影响是可以接受的。
数据导入ElasticSearch
mysql是一个用来持久化数据的工具,直接用来进行数据分析明显效果不太好(而且数据量较大时,查询效率极低),这里就需要使用更加合适的工具—ElasticSearch。简单学习一下ElasticSearch,可以参考elasticsearch官网或者我之前写的一篇博客—SpringBoot整合elasticsearch。
配置好ElasticSearch环境,然后修改配置文件中ElasticSearch相关的配置。调用接口localhost:8980/users/transfer,即可将DB中的用户数据迁移到ES中。
SpringBoot整合ElasticSearch非常简单,直接在项目中导入ElasticSearch的自动配置依赖包
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
然后让相应的DAO层继承ElasticsearchRepository即可在项目中使用ElasticSearch。具体如何在springboot项目中使用ElasticSearch,可以参考SpringBoot-ElasticSearch官方文档,也可参考我项目中源码。
数据导入ES后,可以在head插件或者kibana插件中查看ES中的数据(head插件或kibana插件可以看去重之后导入ES中的数据有1597696条)。
kibana分析知乎数据
我们已经拿到足够多的用户数据了,现在需要利用kibana插件来分析数据。我们在Management > Kibana > Index Patterns中将创建关联的索引user后,即可使用kibana插件辅助我们来分析数据。
下面举几个例子来表示如何使用Kibana来分析大数据。
1.查询关注数在100万及以上的用户
# 查询关注数在100万及以上的用户
GET user/userInfo/_search
{"query": {"range" : {"followerCount" : {"gte": 1000000}}}
}
查询结果图如下
简单地解释一下结果集中部分字段的意义。took是指本次查询的耗时,单位是毫秒。hits.total表示的是符合条件的结果条数。hits._score表示的是与查询条件的相关度得分情况,默认降序排序。
聚合查询知乎用户的性别比
# 查询知乎用户男女性别比
GET /user/userInfo/_search
{"size": 0,"aggs": {"messages": {"terms": {"field": "gender"}}}
}
查询结果图如下:
直接看数据可能不太直观,我们还可以直接通过kibana插件不画相应的结果图(-1:未填,1:男, 0:女):
从结果图来看,目前知乎的男女比还不算离谱,比例接近3:2(这里让我有点儿怀疑自己爬取的数据有问题)。
3.聚合查询人口最集中的前10个城市
# 查询现居地最多的前10个城市
GET /user/userInfo/_search
{"size": 0,"aggs": {"messages": {"terms": {"field": "home","size": 10}}}
}
查询结果图如下:
从这里的查询结果,很容易就可以看出,“深圳”和“深圳市”、“广州”和“广州市”其实各自指的都是同一地方。但是当前ES不能智能地识别并归类(ps: 可能有方法可以归类但笔者不会…)。因此这里需要后续手动地将类似信息进行处理归类。
4.模糊搜索
全字段匹配,“模糊”搜索含有“知乎”的数据,搜索结果图如下:
echarts作图
从上面的kibana画图效果来看,真的一般般。这里更推荐使用kibana收集数据,利用百度开源的数据可视化工具echarts来作图。
最终的数据汇总以及echarts绘图效果图如下:
1.关注数层级统计
很明显地,绝大部分知乎用户都是“知乎小白”或者“知乎路人”。这里的“知乎超大V(1000000+)”的用户只有3个:“丁香医生”、“知乎日报”、“张佳玮”。
2.行业信息统计
手动整理后的行业信息图如下:
很明显地能够看出,大部分知乎用户所处的行业都与计算机或者互联网相关。
3.公司信息统计
统计了出现频率最多的前15名所属公司统计图如下:
可以看到,“腾讯”、“阿里”的员工数量遥遥领先。虽然“百度”还是排名第三,但已经不在一个数量级。(“BAT”的时代真的一去不复返了吗?)
4.职位信息统计
基于职位信息统计图,利用中文在线词云生成器优词云,生成出现频率最多的前100名的职位词云图:
可以看出,除了学生以外,很多知乎用户都从事计算机或者软件编程相关的工作,也就是说,知乎用户中“程序猿/媛”所占的比重极其的大。
5.大学信息统计
统计了出现频率最多的前20名毕业院校统计图如下:
可以看到,填写了毕业院校的知乎用户(其实还有绝大部分人没有完善该信息),这些毕业院校的实力和名气那是杠杠的。
6.专业信息统计
统计了出现频率最多的前20名专业统计图如下:
可以看到,“计算机科学与技术”和“软件工程”这两个专业的人数遥遥领先。
7.居住城市信息统计
统计了出现频率最多的前20名居住城市统计图如下:
很明显地,“帝都”和“魔都”的人数遥遥领先。(这里可以做一个相关性不大、准确度不高的推论:杭州将是下一个“新一线城市”最有力的竞争者。)
# 总结
从最终的信息统计结果来看,大部分的知乎用户信息不算完善(信息比例)。但这些统计结果图,都是基于知乎用户已经完善的信息进行整理并分析的。很明显地可以看出,已完善信息的知乎用户,基本都在发达城市大公司任职,而且其中的很大一部分是“程序猿/媛”。
也就是说,如果我(码农一枚)在工作中遇到什么专业难题时,在知乎中寻求到的答案是专业可信的。
热门内容:
Spring Boot + MyBatis + Druid + PageHelper 实现多数据源并分页
是时候扔掉Postman了,又一个被低估的IDEA插件出来了...
Spring集成任务调度功能
看完知乎轮子哥的编程之路,我只想说,收下我的膝盖...
这是我读过写得最好的【秒杀系统架构】分析与实战!
Springboot总结,核心功能,优缺点
如何设计 API 接口,实现统一格式返回?
阿里巴巴为什么能抗住90秒100亿?看完这篇你就明白了!
最近面试BAT,整理一份面试资料《Java面试BAT通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。
获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。
明天见(。・ω・。)ノ♡
我用Java+SeimiCrawler+Redis+ES+Kibana技术对数百万知乎用户进行了数据分析,得到了这些......相关推荐
- 我用Java+Redis+ES+Kibana技术对数百万知乎用户进行了数据分析,得到了这些...
点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 作者:_artoria_ http://tinyurl.c ...
- Redis学习(5)-Jedis(Java操作redis数据库技术)
Java连接redis 一,导入jar包 Redis有什么命令,Jedis就有什么方法 设置防火墙 在Linux上面运行如下代码: 单实例:Jedis实例: package com.jedis.dem ...
- flume+es+kibana日志系统
上个公司做了个日志系统,其实之间断断续续搞了三套方案,一套就是前边说的hadoop方案,网上也有但是不全,自己搞了下发现太庞大不适合小型项目,这次搞了flume+ES+kibana方案,感觉非常不错哦 ...
- Logstash+Redis+Elasticsearch+Kibana+Nginx搭建日志分析系统
为什么80%的码农都做不了架构师?>>> 前言: 随着实时分析技术的发展及成本的降低,用户已经不仅仅满足于离线分析.目前我们服务的用户包括微博.微盘.云存储.弹性计算平台等十多 ...
- Spring Data:企业级Java的现代数据访问技术(影印版)
<Spring Data:企业级Java的现代数据访问技术(影印版)> 基本信息 原书名:Spring Data:Modern Data Access for Enterprise Jav ...
- ES+Kibana+IK安装
ES+Kibana+IK ElasticSearch(简称ES) Elasticsearch是用Java开发并且是当前最流行的开源的企业级搜索引擎. 能够达到实时搜索,稳定,可靠,快速,安装使用方便. ...
- 基于springboot项目中使用docker-compose+es+kibana+logstash+mysql 提高数据查询效率
基于springboot项目中使用docker-compose+es+kibana+logstash+mysql 提高数据查询效率 1.拉取logstash,kibana,es,mysql镜像 #命令 ...
- Java开发面试常见的技术问题整理
Java开发面试常见的技术问题整理 介绍 对jvm的了解? jvm类加载机制 jvm运行时数据区||Jvm体系结构五大块 jvm自带的加载器 jvm的双亲委派模式 什么是GC jvm的垃圾回收算法 怎 ...
- JAVA外卖项目第一天 技术选型和包结构
瑞吉外卖-Day01 课程内容 软件开发整体介绍 瑞吉外卖项目介绍 开发环境搭建 后台登录功能开发 后台退出功能开发 1. 软件开发整体介绍 作为一名软件开发工程师,我们需要了解在软件开发过程中的开发 ...
最新文章
- mysql 密码 特殊符号_MySQL数据库之mysql设置复杂密码中含$特殊符号导致无法命令行登录...
- flutter版本控制工具 `FVM`
- 读书笔记_CLR.via.c#第十六章_数组
- Python爬虫人工智能大数据全栈视频史上最全合辑教程分享!
- spark启动脚本报告No such file or directory
- windows10中远程访问凭据不工作
- Java基于Redis的分布式锁
- hadoop配置文件_Hadoop分布式集群
- powerdesigner安装之后会自动加载到word中怎么去除??
- ThinkPHP中使用聚合查询去重求和
- 可见光植被指数,RGB影像植被指数
- 高项_第一章信息化和信息系统
- opencv-python API中的findContours、drawContours与hierachy解析
- 怎么查看linux系统硬盘,Linux系统下如何查看所有存储设备(磁盘分区)
- opencv 实现的静态手势识别 进而玩剪刀石头布
- 测试体重的手机软件,手机能测重量的软件
- Maven的三种packaging方式(pom、jar、war)
- MySQL数据库(五)percona软件介绍,innobackupex备份与恢复
- 近几年计算机系论文参考文献,近几年计算机学校参考文献 哪里有计算机学校参考文献...
- win10 无法访问XP 共享目录原因
热门文章
- BZOJ 4025 二分图
- Android Java使用JavaMail API发送和接收邮件的代码示例
- 玩转Android之二维码生成与识别
- javascrip 常用属性
- 老调重弹:插件式框架开发的一个简单应用
- 中国电子学会青少年编程能力等级测试图形化四级编程题:太空大战
- 刻意练习:Python基础 -- Task09. else 与 with 语句
- 【怎样写代码】参数化类型 -- 泛型(四):泛型之类型参数约束
- 超 40W 奖金池等你来战!第二届“长沙银行杯”腾讯云启创新大赛火热来袭!...
- 性能超越最新序列推荐模型,华为诺亚方舟提出记忆增强的图神经网络