【Python3爬虫】微博用户爬虫

这次爬虫要实现的是爬取某个微博用户的关注和粉丝的用户公开基本信息,包括用户昵称、id、性别、所在地和其粉丝数量,而后将爬取下来的数据保存在MongoDB数据库中,最后再生成几个图表来简单分析一下咱们获得的数据。git

 

1、具体步骤:

这里咱们选取的爬取站点是https://m.weibo.cn,此站点是微博移动端的站点,咱们能够直接查看某个用户的微博,好比https://m.weibo.cn/profile/5720474518
github

而后查看其关注的用户,打开开发者工具,切换到XHR过滤器,一直下拉列表,就会看到有不少的Ajax请求。这些请求的类型是Get类型,返回结果是Json格式,展开以后就能看到有不少用户的信息。
数据库

这些请求有两个参数,containerid和page,经过改变page的数值,咱们就能获得更多的请求了。获取其粉丝的用户信息的步骤是同样的,除了请求的连接不一样以外,参数也不一样,修改一下就能够了。json

因为这些请求返回的结果里只有用户的名称和id等信息,并无包含用户的性别等基本资料,因此咱们点进某我的的微博,而后查看其基本资料,好比这个,打开开发者工具,能够找到下面这个请求:api

因为这我的的id是6857214856,所以咱们能够发现当咱们获得一我的的id的时候,就能够构造获取基本资料的连接和参数了,相关代码以下(uid就是用户的id):app

 1 uid_str = "230283" + str(uid)  2 url = "https://m.weibo.cn/api/container/getIndex?containerid={}_-_INFO&title=%E5%9F%BA%E6%9C%AC%E8%B5%84%E6%96%99&luicode=10000011&lfid={}&featurecode=10000326".format(uid_str, uid_str)  3 data = {  4     "containerid": "{}_-_INFO".format(uid_str),  5     "title": "基本资料",  6     "luicode": 10000011,  7     "lfid": int(uid_str),  8     "featurecode": 10000326
 9 }

而后这个返回的结果也是Json格式,提取起来就很方便,由于不少人的基本资料都不怎么全,因此我提取了用户昵称、性别、所在地和其粉丝数量。并且由于一些帐号并不是我的帐号,就没有性别信息,对于这些帐号,我选择将其性别设置为男性。不过在爬取的时候,我发现一个问题,就是当页数超过250的时候,返回的结果就已经没有内容了,也就是说这个方法最多只能爬250页。对于爬取下来的用户信息,全都保存在MongoDB数据库中,而后在爬取结束以后,读取这些信息并绘制了几个图表,分别绘制了男女比例扇形图、用户所在地分布图和用户的粉丝数量柱状图。dom

 

2、主要代码:

因为第一页返回的结果和其余页返回的结果格式是不一样的,因此要分别进行解析,并且由于部分结果的json格式不一样,因此可能报错,所以采用了try...except...把出错缘由打印出来。ide

爬取第一页并解析的代码以下:工具

 1 def get_and_parse1(url):  2     res = requests.get(url)  3     cards = res.json()['data']['cards']  4     info_list = []  5     try:  6         for i in cards:  7             if "title" not in i:  8                 for j in i['card_group'][1]['users']:  9                     user_name = j['screen_name']  # 用户名
10                     user_id = j['id']  # 用户id
11                     fans_count = j['followers_count']  # 粉丝数量
12                     sex, add = get_user_info(user_id) 13                     info = { 14                         "用户名": user_name, 15                         "性别": sex, 16                         "所在地": add, 17                         "粉丝数": fans_count, 18  } 19  info_list.append(info) 20             else: 21                 for j in i['card_group']: 22                     user_name = j['user']['screen_name']  # 用户名
23                     user_id = j['user']['id']  # 用户id
24                     fans_count = j['user']['followers_count']  # 粉丝数量
25                     sex, add = get_user_info(user_id) 26                     info = { 27                         "用户名": user_name, 28                         "性别": sex, 29                         "所在地": add, 30                         "粉丝数": fans_count, 31  } 32  info_list.append(info) 33         if "followers" in url: 34             print("第1页关注信息爬取完毕...") 35         else: 36             print("第1页粉丝信息爬取完毕...") 37  save_info(info_list) 38     except Exception as e: 39         print(e)

爬取其余页并解析的代码以下:ui

 1 def get_and_parse2(url, data):  2     res = requests.get(url, headers=get_random_ua(), data=data)  3     sleep(3)  4     info_list = []  5     try:  6         if 'cards' in res.json()['data']:  7             card_group = res.json()['data']['cards'][0]['card_group']  8         else:  9             card_group = res.json()['data']['cardlistInfo']['cards'][0]['card_group'] 10         for card in card_group: 11             user_name = card['user']['screen_name']  # 用户名
12             user_id = card['user']['id']  # 用户id
13             fans_count = card['user']['followers_count']  # 粉丝数量
14             sex, add = get_user_info(user_id) 15             info = { 16                 "用户名": user_name, 17                 "性别": sex, 18                 "所在地": add, 19                 "粉丝数": fans_count, 20  } 21  info_list.append(info) 22         if "page" in data: 23             print("第{}页关注信息爬取完毕...".format(data['page'])) 24         else: 25             print("第{}页粉丝信息爬取完毕...".format(data['since_id'])) 26  save_info(info_list) 27     except Exception as e: 28         print(e)

 

3、运行结果:

在运行的时候可能会出现各类各样的错误,有的时候返回结果为空,有的时候解析出错,不过仍是能成功爬取大部分数据的,这里就放一下最后生成的三张图片吧。

 

 

完整代码已上传到GitHub