知乎所有用户信息爬虫

今天用递归写了个知乎所有用户信息的爬虫,源代码放在了github上,有兴趣的同学可以上去下载一下看看,源码地址:https://github.com/xiaobeibei26/zhihu_user_spider
这里介绍一下代码逻辑以及分页分析,首先看网页,这里本人随便选了一个大V作为入口,然后点开他的关注列表,如图


注意,本人爬虫的全称都是处于非登录状态的。
这里的粉丝列表以及关注者列表都是后台ajax请求得到的数据(没有听过ajax的童鞋别慌,ajax请求跟普通浏览器的请求没有区别,它主要就是在我们浏览网页时候偷偷给服务器发送的请求,就是为了节省流量以及减少请求数,不然每次看点新数据都全部刷新网页,服务器压力很大的,所以有了这玩意),
然后我们找到粉丝列表以及关注者列表的URL,这个很简单,在chrome浏览器下面点击一下页数切换就可以找到,如图

找到关注者以及粉丝的URL就好办理,下面看一看这些数据,这里以粉丝的数据举例,如图,是一段json

Paste_Image.png

这里找到了粉丝的数据,不过这里不是用户的详细信息,只有部分数据,不过他提供了一个token_url,我们就可以获取这个ID访问用户的详细信息了,我们看看每个用户的详细信息怎么提取。
这里楼主发现,在观看粉丝或者关注列表的时候,网页是会自动触发该用户详细信息的请求,如图

Paste_Image.png

这次获得的是用户详细信息查询的URL,这里看一看这个详细信息的URL,如图

Paste_Image.png

上面介绍了网页的基础分析,下面说一下代码的思路,这次爬虫用到了递归,本次用的scrapy抓取以及mogodb数据库存储的。
首先本人是用了一个大V作为爬虫第一个网页,然后分三步,第一步是爬了该大V的详细信息然后存入数据库,第二步是爬取了该大V的粉丝,第三是爬取了该大V的关注者(其实就是爬取粉丝或者关注者的token_url),完成之后,利用爬取的粉丝以及关注者的数据构造他们每个人详细信息的url,然后挖取详细信息存入数据库。到这里递归第一步算是完成了,然后爬虫会从每一个粉丝和关注者入手,分别爬取他们的粉丝以及关注者的详细数据,不断递归
在代码里面还有加入了一些自动翻页的功能,有兴趣可以看看。
这里贴两张代码图
第一张是我们item里面定义要抓取的数据

import scrapy


class ZhihuUserItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    answer_count = scrapy.Field()#回答数量
    articles_count = scrapy.Field()#写过的文章数
    follower_count = scrapy.Field()#粉丝数量
    following_count = scrapy.Field()#关注了多少人
    educations=scrapy.Field()#教育背景
    description = scrapy.Field()#个人描述
    locations = scrapy.Field()#所在地
    url_token =scrapy.Field()#知乎给予的每个人用户主页唯一的ID
    name=scrapy.Field()#用户昵称
    employments = scrapy.Field()#工作信息
    business=scrapy.Field()#一些工作或者商业信息的合集
    user_type =scrapy.Field()#用户类型,可以是个人,也可以是团体等等
    headline =scrapy.Field()#个人主页的标签
    voteup_count = scrapy.Field()#获得的赞数
    thanked_count=scrapy.Field()#获得的感谢数
    favorited_count = scrapy.Field()#被收藏次数
    avatar_url = scrapy.Field()#头像URl

第二张是主爬虫的代码,有兴趣的可以去github看看详细的

# -*- coding: utf-8 -*-
import scrapy
from scrapy import Request
import json
from zhihuuser.items import ZhihuUserItem#导入我们刚刚定义的items,这里从文件最外层开始带入

class ZhihuSpider(scrapy.Spider):
    name = "zhihu"
    allowed_domains = ["www.zhihu.com"]
    start_urls = ['http://www.zhihu.com/']
    start_user ='wang-tuan-jie-55'#开始放进去的第一个用户的ID

    include_follow='data[*].answer_count, articles_count, gender, follower_count, is_followed, is_following, badge[?(type = best_answerer)].topics'
    #上面这个是查询粉丝或者关注列表里面的用户需要附带的参数
    include_userinfo='locations,employments,gender,educations,business,voteup_count,thanked_Count,follower_count,following_count,cover_url,following_topic_count,following_question_count,following_favlists_count,following_columns_count,avatar_hue,answer_count,articles_count,pins_count,question_count,commercial_question_count,favorite_count,favorited_count,logs_count,marked_answers_count,marked_answers_text,message_thread_token,account_status,is_active,is_force_renamed,is_bind_sina,sina_weibo_url,sina_weibo_name,show_sina_weibo,is_blocking,is_blocked,is_following,is_followed,mutual_followees_count,vote_to_count,vote_from_count,thank_to_count,thank_from_count,thanked_count,description,hosted_live_count,participated_live_count,allow_message,industry_category,org_name,org_homepage,badge[?(type=best_answerer)].topics'
    #上面这个是查询个人信息需要附带的一个参数


    followers_url = 'https://www.zhihu.com/api/v4/members/{user_name}/followers?include={include_follow}&offset={offset}&limit={limit}'
    #获取粉丝列表的url,里面的参数分别是用户的ID,查询参数,这个在浏览器复制就可以了,offset表示第几页的粉丝或者关注者,limit表示每页的数量,这里网页上默认是20
    followees_url = 'https://www.zhihu.com/api/v4/members/{user_name}/followees?include={include_follow}&offset={offset}&limit={limit}'
    # 获取关注列表的URL,根上面的就差了一个字母
    userinfo_url= 'https://www.zhihu.com/api/v4/members/{user_name}?include={include_userinfo}'
    #上面这个是提取用户信息信息的url
    def start_requests(self):
        yield Request(url=self.userinfo_url.format(user_name=self.start_user,include_userinfo=self.include_userinfo),callback=self.get_user_info)
        #上面是访问第一个用户,获取详细信息
        yield Request(url=self.followers_url.format(user_name=self.start_user,include_follow=self.include_follow,offset=0,limit=20),callback=self.get_followers_parse)
        #上面是访问第一个用户的粉丝列表,下面是访问关注列表
        yield Request(url=self.followees_url.format(user_name=self.start_user,include_follow=self.include_follow,offset=0,limit=20),callback=self.get_followees_parse)

    def get_user_info(self,response):#获取用户信息信息
        data = json.loads(response.text)
        #print(data)
        item = ZhihuUserItem()
        for Field in item.fields:#可以获取在item里面定义的key值,就是那些locations,employments等
            #print(Field)
            if Field in data.keys():
                item[Field]=data.get(Field)#获取字典里面的值
        yield item
        yield Request(url=self.followers_url.format(user_name=data.get('url_token'),include_follow=self.include_follow,offset=0,limit=20),callback=self.get_followers_parse)
        yield Request(url=self.followees_url.format(user_name=data.get('url_token'), include_follow=self.include_follow, offset=0,limit=20), callback=self.get_followees_parse)

    def get_followers_parse(self, response):#获取粉丝列表
        try:#这里添加的异常是防止有些用户没有粉丝
            followers_data = json.loads(response.text)

            try:
                if  followers_data.get('data'):  # data里面是一个由字典组成的列表,每个字典是粉丝的相关信息
                    for one_user in followers_data.get('data'):
                        user_name = one_user['url_token']#提取url_token然后访问他的详细信息
                        yield Request(url=self.userinfo_url.format(user_name=user_name,include_userinfo=self.include_userinfo),callback=self.get_user_info)
                        #将所有粉丝或者关注者的url_token提取出来,放进一开始我们构造的用户详细信息的网址里面,提取他们的信息

                if  'paging' in followers_data.keys() and followers_data.get('paging').get('is_end') ==False:
                    yield Request(url=followers_data.get('paging').get('next'),callback=self.get_followers_parse)
            except Exception as e:
                print(e,'该用户没有url_token')
        except Exception as e:
            print(e,' 该用户没有粉丝')

    def get_followees_parse(self,response):#获取关注者的函数
        try:#这里添加的异常是防止有些用户没有关注者
            followees_data = json.loads(response.text)
            try:
                if followees_data.get('data'):
                    for one_user in followees_data.get('data'):
                        user_name = one_user['url_token']#提取url_token然后访问他的详细信息
                        yield Request(url=self.userinfo_url.format(user_name=user_name,include_userinfo=self.include_userinfo),callback=self.get_user_info)
                        #将所有粉丝或者关注者的url_token提取出来,放进一开始我们构造的用户详细信息的网址里面,提取他们的信息

                if  'paging' in followees_data.keys() and followees_data.get('paging').get('is_end') ==False:#判断是否有下一页
                    yield Request(url=followees_data.get('paging').get('next'),callback=self.get_followees_parse)
            except Exception as e:
                print(e,'该用户没有url_token或者data')
        except Exception as e:
            print(e,' 该用户没有粉丝')

代码一共不足80行,运行了一分钟就抓了知乎一千多个用户的信息,
pipline代码如图

from pymongo import MongoClient



class ZhihuuserPipeline(object):
    def __init__(self):
        self.client = MongoClient(host='123.207.126.72',port=27017)
        self.database = self.client['zhuhu_spider']
        self.db = self.database['zhuhu_user_infomation']

    def process_item(self, item, spider):#这里以每个用户url_token为ID,有则更新,没有则插入
        self.db.update({'url_token':item['url_token']},dict(item),True)
        return item

    def close_spider(self,spider):
        self.client.close()

这里上张结果图



最近忙完别的事了,终于可以天天写爬虫了,不知道大家这篇有什么问题不,可以随便向我提
最后提一提,爬取一定要伪装好headers,里面有些东西服务器每次都会检查

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容