python: 知乎大规模(34k)用户爬虫

前些天学习python,完成了python练习册的大部分习题:https://github.com/Show-Me-the-Code/python(我的github上有习题代码,欢迎自取)。之后看到@salamer的一个python爬虫项目,觉得很不错。于是自己花了4天的时间完成了一个大规模爬取知乎用户信息的爬虫,由于个人网络原因,爬取12小时,获得了34k用户的信息(理论上可以爬全站的信息,可能时间要长一些,最好放在服务器上跑)并整理成直观的图表(文章末尾显示)。

好了,说一下主要的技术点:

(1)使用python的request模块获取html页面,注意要修改自己的cookie,使得我们更像是使用浏览器访问

(2)使用xpath模块从html中提取需要的关键信息(姓名,职业,居住地,关注人等)

(3)使用redis作为队列,很好的解决并发和大规模数据的问题(可以分布式)

(4)使用bfs宽度优先搜索,使得程序得以不断扩展持续搜索用户

(5)数据存储至no-sql数据库:mongodb(高效轻量级并且支持并发)

(6)使用python的进程池模块提高抓取速度

(7)使用csv,pandas,matplotlib模块进行数据处理(需要完善)

接下来我们进行仔细的分析:

(一)数据的获取

主要使用了python的request进行html的获取,另外,header中的cookie携带了我们的登陆信息,所以,按下你的F12将自己的cookie添加至程序中。

知乎上有很多水军,我们为了更加高质量的抓取用户信息,使用了这样一个策略:只抓取每个人的关注者,这样可以相对有效的减少水军和小号。

#cookie要自己从浏览器获取
        self.header["User-Agent"]="Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:35.0) Gecko/20100101 Firefox/35.0"
        self.cookies={"q_c1":"8074ec0c513747b090575cec4a547cbd|1459957053000|1459957053000",
                      "l_cap_id":'"Y2MzODMyYjgzNWNjNGY4YzhjMDg4MWMzMWM2NmJmZGQ=|1462068499|cd4a80252719f069cc467a686ee8c130c5a278ae"',
                      "cap_id":'"YzIwNjMwNjYyNjk0NDcyNTkwMTFiZTdiNmY1YzIwMjE=|1462068499|efc68105333307319525e1fc911ade8151d9e6a6"',
                      "d_c0":'"AGAAI9whuwmPTsZ7YsMeA9d_DTdC6ijrE4A=|1459957053"',
                      "_za":"9b9dde53-9e53-4ed1-a17f-363b875a8107",
                      "login":'"YWQyYzQ4ZDYyOTAwNDVjNTg2ZmY3MDFkY2QwODI5MGY=|1462068522|49dd99d3c8330436f211a130209b4c56215b8ec3"',
                      "__utma":"51854390.803819812.1462069647.1462069647.1462069647.1",
                      "__utmz":"51854390.1462069647.1.1.utmcsr=baidu|utmccn=(organic)|utmcmd=organic",
                      "_xsrf":"6b32002d2d529794005f7b70b4ad163e",
                      "_zap":"a769d54e-78bf-44af-8f24-f9786a00e322",
                      "__utmb":"51854390.4.10.1462069647",
                      "__utmc":"51854390",
                      "l_n_c":"1",
                      "z_c0":"Mi4wQUFBQWNJQW9BQUFBWUFBajNDRzdDUmNBQUFCaEFsVk5LdkpNVndCRlQzM1BYVEhqbWk0VngyVkswSVdpOXhreDJB|1462068522|eed70f89765a9dd2fdbd6ab1aabd40f7c23ea283",
                      "s-q":"%E4%BA%91%E8%88%92",
                      "s-i":"2",
                      "sid":"1jsjlbsg",
                      "s-t":"autocomplete",
                      "__utmv":"51854390.100--|2=registration_date=20140316=1^3=entry_date=20140316=1",
                      "__utmt":"1"}

使用xpath提取html中我们需要关注的信息,这里给个小例子,关于xpath的用法请自行百度:)

def get_xpath_source(self,source):
        if source:
            return source[0]
        else:
            return ''
 tree=html.fromstring(html_text)
        self.user_name=self.get_xpath_source(tree.xpath("//a[@class='name']/text()"))
        self.user_location=self.get_xpath_source(tree.xpath("//span[@class='location item']/@title"))
        self.user_gender=self.get_xpath_source(tree.xpath("//span[@class='item gender']/i/@class"))

(二)搜索和存储

准备搜索的url队列可能会很大,我们使用redis作为队列来存储,不仅程序退出后不会丢失数据(程序重新运行可以继续上次的搜索),而且支持分布式水平扩展和并发。

核心采用BFS宽度优先搜索来进行扩展,这里不清楚的,恐怕要自己去学习下算法了。存储提供两种方式,一种直接输出至控制台,另一种就是存储至mongodb费关系数据库。

# 核心模块,bfs宽度优先搜索
def BFS_Search(option):
    global red
    while True:
        temp=red.rpop('red_to_spider')
        if temp==0:
            print 'empty'
            break
        result=Spider(temp,option)
        result.get_user_data()

    return "ok"
def store_data_to_mongo(self):
        new_profile = Zhihu_User_Profile(
        user_name=self.user_name,
        user_be_agreed=self.user_be_agreed,
        user_be_thanked=self.user_be_thanked,
        user_followees=self.user_followees,
        user_followers=self.user_followers,
        user_education_school=self.user_education_school,
        user_education_subject=self.user_education_subject,
        user_employment=self.user_employment,
        user_employment_extra=self.user_employment_extra,
        user_location=self.user_location,
        user_gender=self.user_gender,
        user_info=self.user_info,
        user_intro=self.user_intro,
        user_url=self.url
        )
        new_profile.save()

(三)多进程提高效率

python由于GIL锁的原因,多线程并不能达到真正的并行。这里使用python提供的进程池进行多进程操作,这里有一个问题需要大家注意:

实际测试下来,在选取将数据存储至mongodb数据库这个方式下,多进程没能提高效率,甚至比单进程还要慢,我分析了下原因:由于计算的部分花时间很少,主要的瓶颈在磁盘IO,也就是写进数据库,一个时刻只能有一个进程在写,多进程的话会增加很多锁机制的无端开销,造成了上述结果。

但是直接输出的话速度会快很多。这也提示我们多进程并不是一定能提高速度的,要根据情况选择合适的模型。

使用多进程,注意,实际测试出来,并没有明显速度的提升,瓶颈在IO写;如果直接输出的话,速度会明显加快
    res=[]
    process_Pool=Pool(4)
    for i in range(4):
        res.append(process_Pool.apply_async(BFS_Search,(option, )))

    process_Pool.close()
    process_Pool.join()

    for num in res:
        print ":::",num.get()
    print 'Work had done!'

(四)数据分析

这里我们使用csv,pandas模块进行数据分析,关于模块的使用请自行google,这里贴出自己做出的一些分析图:

知乎用户城市分布:

一线城市的用户高居榜首,尤其北京。美国的也好多啊..

知乎用户专业分布:

果然知乎上的程序猿最多。。

知乎用户学校分布:

清北和华东五虎高校的学校居多,看来知乎的学生群体质量很高。

知乎用户职业分布:

很多大佬啊,这么多创始人和CEO,还有天敌:产品经理....

好了,就展示到这里吧,对这个项目有兴趣的同学,可以到我的Github查看,源码全部在 这里

数据分析部分并不专业,希望更多的人来完善这个项目,我自己也会开启下一步学习,将其改为分布式爬虫,希望给大家带来帮助~

时间: 2024-11-05 17:29:10

python: 知乎大规模(34k)用户爬虫的相关文章

Python爬虫入门【21】: 知乎网全站用户爬虫 scrapy

全站爬虫有时候做起来其实比较容易,因为规则相对容易建立起来,只需要做好反爬就可以了,今天咱们爬取知乎.继续使用scrapy当然对于这个小需求来说,使用scrapy确实用了牛刀,不过毕竟这个系列到这个阶段需要不断使用scrapy进行过度,so,我写了一会就写完了. 你第一步找一个爬取种子,算作爬虫入口 https://www.zhihu.com/people/zhang-jia-wei/following 我们需要的信息如下,所有的框图都是我们需要的信息. 获取用户关注名单 通过如下代码获取网页返

我用爬虫一天时间“偷了”知乎一百万用户,只为证明PHP是世界上最好的语言

我用爬虫一天时间“偷了”知乎一百万用户,只为证明PHP是世界上最好的语言 2015-08-06 猿圈 我用爬虫一天时间“偷了”知乎一百万用户 只为证明PHP是世界上最好的语言 看了不少朋友圈里推荐的Python爬虫文章, 都觉得太小儿科,处理内容本来就是PHP的强项,Python唯一的好处估计也就天生的Linux自带,和Perl一样,这点觉得挺不够意思的 Linux,还是Mac厚道,天生就自带了Python.Perl.PHP.Ruby,当然我也很讨厌讨论一门语言的好坏,每门语言存在就一定有它的道

Python爬虫入门【20】:掘金网全站用户爬虫 scrapy

获取全站用户,理论来说从1个用户作为切入点就可以,我们需要爬取用户的关注列表,从关注列表不断的叠加下去. 随便打开一个用户的个人中心 绿色圆圈里面的都是我们想要采集到的信息.这个用户关注0人?那么你还需要继续找一个入口,这个用户一定要关注了别人.选择关注列表,是为了让数据有价值,因为关注者里面可能大量的小号或者不活跃的账号,价值不大. 我选了这样一个入口页面,它关注了3个人,你也可以选择多一些的,这个没有太大影响!https://juejin.im/user/55fa7cd460b2e36621

[python]南邮OJ代码备份爬虫

之前看过Python学习的经验,说以工程为导向学习. 自己分析了一下,一般接触Python的都有一定的其他语言基础,对于程序设计的基本逻辑,语法都有一个大概的了解.而Python这种脚本语言,没有过于独特的语法,在一定的其他语言的基础上,更是可以直接上手的. 之前看Python简明教程,半天没有进度.正好遇上Python爬虫项目,直接上手,方便快捷. 网站:http://acm.njupt.edu.cn/welcome.do?method=index,正值系统更新,于是写一个备份代码的爬虫. 使

利用Python实现批量注册网站用户,注意不可用于商业用途哦!

场景目标 现在大多数网站的「用户注册功能」都需要用户正确输入了验证码,才能发起注册的请求,如果想大量注册用户,正确识别验证码变的很关键. 普通的验证码使用 tesserocr,加上训练可以完成,如果想简单一点,可以使用「百度云的文字识别 API」. 今天的目标是使用 selenium + 百度云OCR 批量注册「中知网」一批用户.<pre style="-webkit-tap-highlight-color: transparent; box-sizing: border-box; fon

Window上python开发--4.Django的用户登录模块User

在搭建网站和web的应用程序时,用户的登录和管理是几乎是每个网站都必备的.今天主要从一个实例了解以下django本身自带的user模块.本文并不对user进行扩展. 主要使用原生的模块. 1.User模块基础: 在使用user 之前先import到自己的iew中.相当与我们自己写好的models.只不过这个是系统提供的models. from django.contrib.auth.models import User # 导入user模块 1.1User对象属性 User 对象属性:usern

python学习(二)百度爬虫0.1

参照着网上的爬虫案例(点我),先做了一个demo,基本的爬虫项目创建,以及数据抽取,数据分析,数据保存等等过程基本上有所掌握. 我的需求是需要检索指定的百度贴吧,根据指定的关键字库,搜索出含有关键字的链接,并抽取出来,用于后续告警. 因此,基于需求,分如下步骤: 第一:基于Scrapy创建爬虫项目: 第二:新建TieBaSpider爬虫: 第三:新建外部关键字库dictionary.txt文件,贴吧地址配置url.txt文件: 第一步参考晚上案例. 从第二步开始,编写爬虫,同时创建实例对象以及创

python&amp;php数据抓取、爬虫分析与中介,有网址案例

最近在做一个网络爬虫程序,后台使用python不定时去抓取数据,前台使用php进行展示 网站是:http://se.dianfenxiang.com python&php数据抓取.爬虫分析与中介,有网址案例,布布扣,bubuko.com

简明Python教程(四)———用户登录验证

例子: 实现目标,用Python编写用户登录验证脚本. 知识点: 1.while和if控制流 2.运算表达式 验证过程: 脚本: #!/usr/bin/env python#filename : User login authentication#import sysname = 'Tiger'passwd = '123456'counter = 0times = 3while True:                         #-----------无限循环 username = r