社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

我用Python爬了7W知乎用户信息,终于捕获了心仪小姐姐......

51CTO技术栈 • 8 年前 • 677 次点击  

双十一就要来了,在举国一片“买买买”的呼声中,单身汪的咆哮声也愈发凄厉了。


作为一个 Python 程序员,要如何找到小姐姐,避开暴击伤害,在智中取胜呢?于是就有了以下的对话:

so~今天我们的目标是,爬社区的小姐姐~而且,我们又要用到新的姿势(雾)了~scrapy 爬虫框架~


本文主要讲 scrapy 框架的原理和使用,建议至少在理解掌握 Python 爬虫原理后再使用框架(不要问我为什么,我哭给你看)。

scrapy 原理


在写过几个爬虫程序之后,我们就会知道,利用爬虫获取数据大概的步骤:

  • 请求网页。

  • 获取网页。

  • 匹配信息。

  • 下载数据。

  • 数据清洗。

  • 存入数据库。


scrapy 是一个很有名的爬虫框架,可以很方便的进行网页信息爬取。那么 scrapy 到底是如何工作的呢?之前在网上看了不少 scrapy 入门的教程,大多数入门教程都配有这张图。

也不知道是这张图实在太经典了,还是程序员们都懒得画图,我第一次看到这个图的时候,心情是这样的。

经过了一番深入的理解,大概知道这幅图的意思,让我来举个栗子(是的,我又要举奇怪的栗子了):

scrapy 原理图之我要吃好吃的

当我们想吃东西的时候,我们会出门,走到街上,寻找一家想吃的店,然后点餐,服务员再通知厨房去做,最后菜到餐桌上,或者被打包带走。这就是爬虫程序在做的事,它要将所有获取数据需要进行的操作,都写好。


而 scrapy 就像一个点餐 APP 一般的存在,在订餐列表(spiders)选取自己目标餐厅里想吃的菜(items),在收货(pipeline)处写上自己的收货地址(存储方式)。


点餐系统(scrapy engine)会根据订餐情况要求商铺(Internet)的厨房(download)将菜做好,由于会产生多个外卖取货订单(request),系统会根据派单(schedule)分配外卖小哥从厨房取货(request)和送货(response)。说着说着我都饿了。。。。


什么意思呢?在使用 scrapy 时,我们只需要设置 spiders(想要爬取的内容),pipeline(数据的清洗,数据的存储方式),还有一个 middlewares,是各功能间对接时的一些设置,就可以不用操心其他的过程,一切交给 scrapy模块来完成。


创建 scrapy 工程


安装 scrapy 之后,创建一个新项目:



  1. $ scrapy startproject zhihuxjj



我用的是 pycharm 编译器,在 spiders 文件下创建 zhihuxjj.py。

在 zhihuxjj.py 这个文件中,我们要编写我们的爬取规则。


爬取规则制定(spider)


创建好了项目,让我们来看一下我们要吃的店和菜…哦不,要爬的网站和数据。


我选用了知乎作为爬取平台,知乎是没有用户从 1 到 n 的序列 id 的,每个人可以设置自己的个人主页 id,且为唯一。


所以采选了一枚种子用户,爬取他的关注者,也可以关注者和粉丝一起爬,考虑到粉丝中有些三无用户,我仅选择了爬取关注者列表,再通过关注者主页爬取关注者的关注者,如此递归。

对于程序的设计,是这样的。

之后就是种子用户的个人主页,知乎粉丝多的大 V 很多,但是关注多的人就比较难发现了,这里我选择了知乎的黄继新,联合创始人,想必关注了不少优质用户(≖‿≖)✧。


分析一下个人主页可知,个人主页由'https://www.zhihu.com/people/' + 用户 id 组成。


我们要获取的信息是用 callback 回调函数(敲黑板!!划重点!!)的方式设计,这里一共设计了俩个回调函数:用户的关注列表和关注者的个人信息。

使用 chrome 浏览器查看上图的页面可知获取关注列表的 url,以及关注者的用户 id。


将鼠标放在用户名上,如下图:

可以获得个人用户信息的 url,分析 url 可知:


  1. 关注者列表链接构成:'https://www.zhihu.com/api/v4/members/' + '用户id' + '/followees?include=data[*].answer_count,articles_count,gender,follower_count,is_followed,is_following,badge[?(type=best_answerer)].topics&offset=0&limit=20'

  2. 个人信息链接构成:'https://www.zhihu.com/api/v4/members/' + '用户id' + '?include=allow_message%2Cis_followed%2Cis_following%2Cis_org%2Cis_blocking%2Cemployments%2Canswer_count%2Cfollower_count%2Carticles_count%2Cgender%2Cbadge%5B%3F(type%3Dbest_answerer)%5D.topics'


so,我们在上一节中创建的 zhihuxjj.py 文件中写入以下代码:


  1. import json

  2. from zhihuxjj.items import ZhihuxjjItem

  3. from scrapy import Spider,Request

  4. class ZhihuxjjSpider (Spider):

  5.    name='zhihuxjj' #scrapy用于区别其他spider的名字,具有唯一性。

  6.    allowed_domains = ["www.zhihu.com"] #爬取范围

  7.    start_urls = ["https://www.zhihu.com/"]

  8.    start_user = "jixin"

  9.    followees_url = 'https://www.zhihu.com/api/v4/members/{user}/followees?include=data[*].answer_count,articles_count,gender,follower_count,is_followed,is_following,badge[?(type=best_answerer)].topics&offset={offset}&limit=20' #关注列表网址

  10.    user_url = 'https://www.zhihu.com/api/v4/members/{user}?include=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' #个人信息链接

  11.     def start_requests(self):

  12.        yield Request(self.followees_url.format(user=self.start_user,offset=0),callback=self.parse_fo) #回调种子用户的关注列表

  13.        yield Request(self.user_url.format(user=self.start_user,include = self.user_include),callback=self.parse_user) #回调种子用户的个人信息

  14.    def parse_user(self, response):

  15.        result = json.loads(response.text)

  16.        print(result)

  17.        item = ZhihuxjjItem()

  18.        item['user_name'] = result['name']

  19.        item['sex'] = result['gender']  # gender为1是男,0是女,-1是未设置

  20.        item['user_sign'] = result['headline']

  21.        item['user_avatar'] = result['avatar_url_template'].format(size='xl')

  22.        item['user_url'] = 'https://www.zhihu.com/people/' + result['url_token']

  23.        if len(result['locations']):

  24.            item['user_add'] = result['locations'][0]['name']

  25.        else:

  26.            item['user_add'] = ''

  27.        yield item

  28.    def parse_fo(self, response):

  29.        results = json.loads(response.text)

  30.        for result in results['data']:

  31.            yield Request(self.user_url.format(user=result['url_token'], include=self.user_include),callback=self.parse_user)

  32.            yield Request(self.followees_url.format(user=result['url_token' ], offset=0),callback=self.parse_fo)  # 对关注者的关注者进行遍历,爬取深度depth+=1

  33.        if results['paging']['is_end'] is False: #关注列表页是否为尾页

  34.            next_url = results['paging']['next'].replace('http','https')

  35.            yield Request(next_url,callback=self.parse_fo)

  36.        else:

  37.            pass


这里需要划重点的是 yield 的用法,以及 item['name'],将爬取结果赋值给 item,就是告诉系统,这是我们要选的菜…啊呸…要爬的目标数据。


设置其他信息


在 items.py 文件中,按照 spider 中设置的目标数据 item,添加对应的代码。


  1. import scrapy

  2. class ZhihuxjjItem(scrapy.Item):

  3.    # define the fields for your item here like:

  4.    # name = scrapy.Field()

  5.    user_name = scrapy.Field()

  6.    sex  = scrapy.Field()

  7.    user_sign = scrapy.Field()

  8.    user_url = scrapy.Field()

  9.    user_avatar = scrapy.Field()

  10.    user_add = scrapy.Field()

  11.    pass

在 pipeline.py 中添加存入数据库的代码:

  1. import pymysql

  2. def dbHandle():

  3.    conn = pymysql.connect(

  4.        host='localhost',

  5.        user='root',

  6.        passwd='数据库密码',

  7.        charset='utf8',

  8.        use_unicode=False

  9.    )

  10.    return conn

  11. class ZhihuxjjPipeline(object):

  12.     def process_item(self, item, spider):

  13.        dbObject = dbHandle()  # 写入数据库

  14.        cursor = dbObject.cursor()

  15.        sql = "insert into xiaojiejie.zhihu(user_name,sex,user_sign,user_avatar,user_url,user_add) values(%s,%s,%s,%s,%s,%s)"

  16.        param = (item['user_name'],item['sex'],item['user_sign'],item['user_avatar'],item['user_url'],item['user_add'])

  17.        try:

  18.            cursor.execute(sql, param)

  19.            dbObject.commit()

  20.        except Exception as e:

  21.            print(e)

  22.            dbObject.rollback()

  23.        return item


因为使用了 pipeline.py,所以我们还需要在 setting.py 文件中,将 ITEM_PIPELINE 注释解除,这里起到连接两个文件的作用。

到这里,基本就都设置好了,程序基本上就可以跑了。


不过因为 scrapy 是遵循robots.txt法则的,所以让我们来观察一下知乎的法则:https://www.zhihu.com/robots.txt


emmmmmmm,看完法则了吗,很好,然后我们在setting.py中,将ROBOTSTXT_OBEY 改成 False。

好像…还忘了点什么,对了,忘记设置 headers 了。


通用的设置 headers 的方法同样是在 setting.py 文件中,将 DEFAULTREQUESTHEADERS 的代码注释状态取消,并设置模拟浏览器头。


知乎是要模拟登录的,如果使用游客方式登录,就需要添加 authorization,至于这个 authorization 是如何获取的,我,就,不,告,诉,你......


  1. DEFAULT_REQUEST_HEADERS = {

  2.    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36",

  3.    'authorization': 'oauth c3cef7c66a1843f8b3a9e6a1e3160e20'

  4. }


为了减少服务器压力&防止被封,解除 DOWNLOAD_DELAY 注释状态,这时设置下载延迟,将下载延迟设为 3(robots 法则里要求是 10,但 10 实在太慢了_(:зゝ∠)知乎的程序员小哥哥看不见这句话看不见这句话…

写到这里你会发现,很多我们需要进行的操作,scrapy 都已经写好了,只需要将注释去掉,再稍作修改,就可以实现功能了。scrapy 框架还有很多功能,可以阅读官方文档了解。


运行scrapy文件


写好 scrapy 程序后,我们可以在终端输入。



  1. $ scrapy crawl zhihuxjj



运行文件,但也可以在文件夹中添加 main.py,并添加以下代码。

然后直接用 pycharm 运行 main.py 文件即可,然后我们就可以愉快的爬知乎用户啦~(小姐姐我来啦~)


查找小姐姐


经过了 X 天的运行,_(:зゝ∠)_爬到了 7w 条用户数据,爬取深度 5。(这爬取速度让我觉得有必要上分布式爬虫了…这个改天再唠)


有了数据我们就可以选择,同城市的用户进行研究了……先国际惯例的分析一下数据。

知乎用户性别分布

在 7w 用户中,明显男性超过了半数,标明自己是女性的用户只占了 30% 左右,还有一部分没有注明性别,优质的小姐姐还是稀缺资源呀~


再来看看小姐姐们都在哪个城市。(从 7w 用户中筛选出性别女且地址信息不为空的用户)

知乎女性用户位置分布

看来小姐姐们还是集中在北上广深杭的,所以想发现优质小姐姐的男孩纸们还是要向一线看齐啊,当然也不排除在二三线的小姐姐们没有标记出自己的地理位置。


emmmmm……这次的分析,就到此为止,你们可以去撩小姐姐们了。


研究小姐姐


意不意外?开不开心?这里还有一章。正所谓,授之以鱼,不如授之以渔;撒了心灵鸡汤,还得加一只心灵鸡腿;找到了小姐姐,我们还要了解小姐姐…………

让我再举个栗子~来研究一个小姐姐。(知乎名:动次,已获取小姐姐授权作为示例。)

知乎用户:动次

让我们来爬一下她的动态,chrome 右键检查翻 network 这些套路我就不说了,直接讲研究目标。

  • 赞同的答案和文章(了解小姐姐的兴趣点) 

  • 发布的答案和文章(了解小姐姐的世界观、人生观、价值观) 

  • 关注的问题和收藏夹(了解小姐姐需求) 

  • 提出的问题(了解小姐姐的疑惑)


代码也不贴了,会放在 GitHub 的,来看一下输出。

研究动次的结果输出

因为你乎风格,所以对停用词进行了一些加工,添加了“如何”、“看待”“体验”等词语,得到了小姐姐回答问题的词频。小姐姐的回答里出现了喜欢、朋友、爷爷等词语。

动次回答问题的词频

还有!!在关注、赞同和输出中,都有的词(✪ω✪)。(是不是可以靠美味捕获小姐姐呢……

再来一张刘看山背景的,答题词云。

动次的回答问题词云

后记


本文涉及项目会持续更新,会将研究对象拓展至各平台,并进行后续优化,有兴趣的盆友可以关注 GitHub 项目。


结尾引用知乎用户陈壮壮在《当你追求女生时,你们聊些什么?》的回答。(因为穷我就不申请转载了你们自己点进去看吧(ಥ﹏ಥ),你们只要知道我有颗带你们撩妹的心就行了)


参考链接:

安装scrapy:

http://scrapy-chs.readthedocs.io/zh_CN/1.0/intro/install.html

pycharm编译器:

http://www.jianshu.com/p/23e52f7b8ec7

回调函数:

https://www.zhihu.com/question/19801131

yield的用法:

https://www.ibm.com/developerworks/cn/opensource/os-cn-python-yield/

robots.txt法则:

https://baike.baidu.com/item/robots%E5%8D%8F%E8%AE%AE/2483797?fr=aladdin&fromid=9518761&fromtitle=robots.txt

scrapy官方文档:

http://scrapy-chs.readthedocs.io/zh_CN/1.0/index.html

动次:https://www.zhihu.com/people/wang-dong-ci/activities

GitHub项目:

https://github.com/otakurice/danshengoustyle

当你追求女生时,你们聊些什么?

https://www.zhihu.com/question/25955712/answer/37668446


作者:大吉大利小米酱

简介:Python 爱好者,顽强地自学中,18线灵魂画手/段子手/脑洞女王,求职中,欢迎公司勾搭

编辑:陶家龙、孙淑娟

来源:知乎专栏:https://zhuanlan.zhihu.com/p/30903845,经作者授权转载

精彩文章推荐:

喂,小姐姐,你的程序员男朋友已经加入购物车!

我用Python爬了鹿晗、关晓彤微博的热门评论,并进行了情感分析

支撑百万用户同时在线的高并发直播弹幕系统是如何炼成的?


今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/Sc4ZkcnKWX
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/4095