Java+Redis+ES+Kibana对百万用户数据分析( 二 )


免费代理池的架构及其实现思路图:
Java+Redis+ES+Kibana对百万用户数据分析文章插图
简述一下思路:

  • 启动项目时 , 会自动去爬取西刺代理网站前10页的代理(共1000个代理) , 并将其保存到RabbitMQ中 。 RabbitMQ设置有10个消费者 , 每个消费者会检测代理是否可用 , 检测完毕后会将该代理的信息及其检测结果保存到DB中 。
  • 系统设置了一个定时任务 , 会定时将DB中当前的所有代理再次放到RabbitMQ中 , 会由10个消费者检测代理是否可用 , 并将检测结果同时更新到DB中 。 如果连续3次测试代理不可用 , 则将该代理从DB中删除 。
  • 系统设置了一个定时任务 , 会定时爬取西刺代理网首页的所有代理 , 会检测代理的可用性 , 并将其信息及检测结果再次保存到DB中 。 这样保证DB中会定时获取更多的代理(实际原因是西刺代理可用代理太少 , 如果不定时获取更多代理 , DB中很快就没有可用的代理了) 。
  • 系统设置了一个定时任务 , 会自动删除redis中所有的代理 。 然后再将DB中的代理按检测成功次数进行排序 , 将连续成功次数最多的前10个代理保存进redis中 。 这样redis中的代理就是高可用的 。
3.4 调用接口爬取数据项目一定程度地屏蔽了代理池以及知乎用户数据解析的实现复习性 , 以暴露接口的方式提供爬取知乎用户信息的功能 。
在配置好Redis/RabbitMQ环境后 , 成功启动项目 , 等项目稳定后(需要等到redis中有高可用的代理 , 否则就是用本机IP直接进行数据爬取 , 这样的话本机IP很容易会被封)后 , 即可通过调用如下接口的方式爬取知乎用户信息 。
  1. 调用接口localhost:8980/users爬取指定知乎用户的信息 , 修改url_token的值即可爬取不同知乎用户的信息 。

Java+Redis+ES+Kibana对百万用户数据分析文章插图
  1. 调用接口localhost:8980/users/followees爬取关注指定知乎用户的用户信息 , 修改url_token的值即可爬取关注不同知乎用户的用户信息 。

Java+Redis+ES+Kibana对百万用户数据分析文章插图
  1. 调用接口localhost:8980/users/followers爬取指定知乎用户关注的用户信息 , 修改url_token的值即可爬取不同知乎用户关注的用户信息 。

Java+Redis+ES+Kibana对百万用户数据分析文章插图
在实际测试爬取知乎网站用户信息的过程中 , 如果系统只用一个固定IP进行爬取数据 , 基本爬取不到10万数据该IP就会被封 。 使用了代理池这种方式后 , 由于西刺代理网址上可用的免费代理太少了 , 最终爬取到167万左右数据后 , 代理池中基本就没有可用的IP了 。 不过爬取到这么多的数据已经够用了 。
4. 分析知乎用户数据4.1 数据去重爬取了167万+知乎用户数据后 , 需要对原始数据进行简单的清理 , 这里就是去重 。 每个知乎用户有唯一的url_token , 由于这里爬取的是用户的关注者与被关注者 , 很容易就会有重复的数据 。
数据量有167万+ , 使用Java自带的去重容器Set/Map明显不合适(内存不够 , 就算内存足够 , 去重的效率也有待考量) 。
Java+Redis+ES+Kibana对百万用户数据分析文章插图
项目中实现了一个简单的布隆算法 , 能够保证过滤后的知乎用户数据绝对没有重复 。
布隆算法的实现思路图如下:
Java+Redis+ES+Kibana对百万用户数据分析文章插图
简述布隆算法的实现思路如下:
  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容器进行去重 , 但其实这里还没有考虑容器中还需要存的其他信息) 。