用Scrapy爬取知乎用户信息,并存到MongoDB

大兔子大兔子 提交于 2019-11-29 21:17:14

*相关背景:本篇文章是学习了崔庆才老师的爬虫实践课程后的一篇学习笔记,更多相关的信息请到崔老师博客。
崔庆才的个人博客:https://ask.hellobi.com/blog/id-cuiqingcai*

目标:
1.通过一个大V用户开始,通过递归抓取粉丝列表和关注列表,实现知乎所有用户的详细信息的抓取。
2.将抓取到的结果存储到MongoDB,并进行去重操作。
分析思路:
众所周知,在知乎上面每个人都会有关注列表以及粉丝列表,如果我们从一个大V开始,首先可以获取他的个人信息,然后我们获取他的粉丝列表和关注列表,然后遍历列表中的每一个用户,进一步抓取每一个用户的信息还有他们各自的粉丝列表和关注列表,然后再进一步遍历获取到的列表中的每一个用户,进一步抓取他们的信息和关注粉丝列表,循环往复,不断递归,这样就可以做到一爬百,百爬万,万爬百万,通过社交关系自然形成了一个爬取网,这样就可以爬到所有的用户信息了。

创建项目:

scrapy startproject zhihuuser

创建爬虫

cd zhihuuser
scrapy genspider zhihu www.zhihu.com

禁止ROBOTSTXT_OBEY
打开settings.py文件,将ROBOTSTXT_OBEY修改为False

ROBOTSTXT_OBEY = False

它默认为True,就是要遵守robots.txt 的规则,那么 robots.txt 是个什么东西呢?

通俗来说, robots.txt 是遵循 Robot 协议的一个文件,它保存在网站的服务器中,它的作用是,告诉搜索引擎爬虫,本网站哪些目录下的网页 不希望 你进行爬取收录。在Scrapy启动后,会在第一时间访问网站的 robots.txt 文件,然后决定该网站的爬取范围。

当然,我们并不是在做搜索引擎,而且在某些情况下我们想要获取的内容恰恰是被 robots.txt 所禁止访问的。所以,某些时候,我们就要将此配置项设置为 False ,拒绝遵守 Robot协议 !

所以在这里设置为False。当然可能本次爬取不一定会被它限制,但是我们一般来说会首先选择禁止它。
设置UA
打开settings.py文件,取消DEFAULT_REQUEST_HEADERS的注释,加入如下的内容:

DEFAULT_REQUEST_HEADERS = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko)Chrome/56.0.2924.87 Safari/537.36'
}

设置OA
它是Open Authorization的缩写。

OAUTH_token:OAUTH进行到最后一步得到的一个“令牌”,通过此“令牌”请求,就可以去拥有资源的网站抓取任意有权限可以被抓取的资源。

DEFAULT_REQUEST_HEADERS = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36',
    'authorization': 'oauth c3cef7c66a1843f8b3a9e6a1e3160e20',
}

爬取步骤
以轮子哥为例:https://www.zhihu.com/people/excited-vczh/following
这里写图片描述
这里写图片描述
我在这里找到了关注列表的URL以及相关参数include,offset,limit.
构造动态URL

 user_url = 'https://www.zhihu.com/api/v4/members/{user}?include={include}'
    follows_url='https://www.zhihu.com/api/v4/members/{user}/followees?include={include}&offset={offset}&limit={limit}'

处理需要保存的信息
在items里新声明一个UserItem
from scrapy import Item, Field

class UserItem(Item):
    # define the fields for your item here like:
    id = Field()
    name = Field()
    avatar_url = Field()
    headline = Field()
    description = Field()
    url = Field()
    url_token = Field()
    gender = Field()
    cover_url = Field()
    type = Field()
    badge = Field()

    answer_count = Field()
    articles_count = Field()
    commercial_question_count = Field()
    favorite_count = Field()
    favorited_count = Field()
    follower_count = Field()
    following_columns_count = Field()
    following_count = Field()
    pins_count = Field()
    question_count = Field()
    thank_from_count = Field()
    thank_to_count = Field()
    thanked_count = Field()
    vote_from_count = Field()
    vote_to_count = Field()
    voteup_count = Field()
    following_favlists_count = Field()
    following_question_count = Field()
    following_topic_count = Field()
    marked_answers_count = Field()
    mutual_followees_count = Field()
    hosted_live_count = Field()
    participated_live_count = Field()

    locations = Field()
    educations = Field()
    employments = Field()

在解析方法里面我们解析得到的response内容,然后转为json对象,然后依次判断字段是否存在

result = json.loads(response.text)
item = UserItem()
for field in item.fields:
    if field in result.keys():
        item[field] = result.get(field)
yield item

得到item后通过yield返回就好了。

这样保存用户基本信息就完成了。

接下来我们还需要在这里获取这个用户的关注列表,所以我们需要再重新发起一个获取关注列表的request

在parse_user后面再添加如下代码:
yield Request(
            self.follows_url.format(user=result.get('url_token'), include=self.follows_query, limit=20, offset=0),
            self.parse_follows)

parse_follows
接下来我们处理一下关注列表,首先也是解析response的文本,然后要做两件事:

通过关注列表的每一个用户,对每一个用户发起请求,获取其详细信息。
处理分页,判断paging内容,获取下一页关注列表。

小结
通过以上的spider,我们实现了如上逻辑:

start_requests方法,实现了第一个大V用户的详细信息请求还有他的粉丝和关注列表请求。
parse_user方法,实现了详细信息的提取和粉丝关注列表的获取。
paese_follows,实现了通过关注列表重新请求用户并进行翻页的功能。
paese_followers,实现了通过粉丝列表重新请求用户并进行翻页的功能。
加入pipeline

项目完整代码:
https://github.com/dik111/zhihuuser

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!