目录
- 一、微博爬虫类型介绍
- 二、明星粉丝信息爬虫
- 三、可视化
一、微博爬虫类型介绍
微博有关的爬虫,由于根据网址的不同,可分为三种类型:
1.移动端爬取:利用selenium去模拟登录然后再去爬取,比较麻烦,但是可以根据个人需求依据关键词进行指定爬取。
2.手机端爬取:网址为手机端微博网址,这在我之前的博客中也有提及微博超话内容爬取,在此不再赘述。无需登录,利用Chrome进行抓包即可实现,而且较selenium来说,性能也是更高一点。(不过要注意设置随机睡眠时间)
3.旧版网址爬取:这是微博最简化版本的网址weibo.cn(感觉回到了诺基亚的年代),界面简单无需抓包,直接利用正则或者xpath等方式提取即可(需要拿到登录后的cookie值)
建议:如果只是爬取指定用户的评论、基本信息这些,后两种方法就够用了;如果涉及到更复杂的需求时再考虑selenium爬取
二、明星粉丝信息爬虫
旧版的网址,粉丝数量只显示了前20页,一页10个,总共才200个。手机端下的粉丝列表总共也只能显示5000个,对于5000个之后的粉丝信息,微博出于隐私保护,是爬取不了。详细的情况可参考新浪微博如何获取用户全部粉丝列表
1.微博用户URL说明:
旧版网址用户首页的URL为:
手机端用户首页的URL为:
以邓紫棋为例,她的ID为1705586121,首页如下:
她的粉丝信息抓包结果如下:
这里的用户信息只有用户的简介(screen_name)、关注数(follow_count)、粉丝数(follow_count),对应用户性别和地区是没有显示的。
所以,考虑先用手机端爬取用户ID,再用旧版网址登录,提取信息。(旧版网址个人信息更全一些)
2.爬取邓紫棋粉丝所有的user_id
考虑到部分用户可能是机器人,初步筛选条件为粉丝数大于等于20
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | import requests import json import random import os os.chdir('C:/Users/dell/Desktop') import time base_url='https://m.weibo.cn/api/container/getIndex?containerid=231051_-_fans_-_1705586121&since_id=' head=[ "Opera/12.0(Windows NT 5.2;U;en)Presto/22.9.168 Version/12.00", "Opera/12.0(Windows NT 5.1;U;en)Presto/22.9.168 Version/12.00", "Mozilla/5.0 (Windows NT 5.1) Gecko/20100101 Firefox/14.0 Opera/12.0", "Opera/9.80 (Windows NT 6.1; WOW64; U; pt) Presto/2.10.229 Version/11.62", "Opera/9.80 (Windows NT 6.0; U; pl) Presto/2.10.229 Version/11.62", ] header={ 'user-agent':random.choice(head) } with open('user_id.txt','w') as f: for page in range(2,251): #注意是从2开始才是用户信息 try: url=base_url+str(page) r=requests.get(url,headers=header) data=json.loads(r.text) all_user=data['data']['cards'][0]['card_group'] for user in all_user: fans=int(user.get('desc2').split(':')[1]) if fans >=20: f.write(str(user.get('user')['id'])+'\n') print('第{}页用户id爬取完毕'.format(page)) time.sleep(random.randint(1,3)) except: print('未爬到数据') |
爬取的部分用户ID如下:
3.以旧版本界面,爬取粉丝基本信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | import numpy as np import pandas as pd import requests from lxml import etree import random import time header={'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36', 'cookie':'你自己的cookie', 'accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3', } url_new='https://weibo.cn/u/' data=[] count=0 def get_id(path): with open(path,'r') as f: user_id=f.readlines() user_id=np.char.rstrip(user_list,'\n') return user_id def gethtml(url,header): r=requests.get(url,headers=header) if r.status_code==200: return r.text else: print('网络连接异常') for user_id in get_id('user_id.txt'): try: url=url_new+user_id r_text=gethtml(url,header) html=etree.HTML(r_text.encode('utf-8')) user_name=html.xpath('//span[@class="ctt"]/text()')[0] inf=html.xpath('//span[@class="ctt"]/text()')[1] weibo_number=html.xpath('//div[@class="tip2"]/span[@class="tc"]/text()')[0].replace('微博','').strip('[]') focus_number=html.xpath('//div[@class="tip2"]/a[1]/text()')[0].replace('关注','').strip('[]') fan_number=html.xpath('//div[@class="tip2"]/a[2]/text()')[0].replace('粉丝','').strip('[]') data.append([user_name,inf,weibo_number,focus_number,fan_number]) count+=1 print('第{}个用户信息写入完毕'.format(count)) time.sleep(random.randint(1,2)) except: print('用户信息不完全') df=pd.DataFrame(data,columns=['user_id','inf','weibo_num','focus_num','fans_num']) df.to_csv('weibo_user.csv',index=False,encoding='gbk') |
最终爬取到粉丝数量大于等于20的用户共1362个,清洗后的部分数据如下:
三、可视化
(1) 粉丝性别占比
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import matplotlib.pyplot as plt plt.style.use('ggplot') plt.rcParams['font.sans-serif']=['SimHei'] %config InlineBackend.figure_format='svg' df=pd.read_csv('weibo_user.csv',encoding='gbk') gender=pd.DataFrame(df['gender'].value_counts()) plt.pie(gender['gender'], labels=['女','男'], startangle=90, shadow=False, autopct='%1.1f%%', textprops={'fontsize': 13, 'color': 'w'}, colors=['#f26d5b','#2EC4B6'] ) plt.legend(loc='best') plt.title('邓紫棋粉丝性别占比') plt.axis('equal') plt.tight_layout() plt.show() |
从饼图来看,女粉较男粉稍多一些
(2) 全国粉丝分布情况
注意:使用的是pycharts最新版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | from pyecharts.charts import Map from pyecharts import options as opts loc=pd.DataFrame(df['loc'].value_counts()).drop(loc.index[0]) #去除其他 city=np.char.rstrip(list(loc.index)) map1=Map(init_opts=opts.InitOpts(width="1200px",height="800px")) map1.set_global_opts( title_opts=opts.TitleOpts(title="邓紫棋粉丝地区分布"), visualmap_opts=opts.VisualMapOpts(max_=200, is_piecewise=True, pieces=[ {"max": 200, "min": 150, "label": ">150", "color": "#754F44"}, {"max": 149, "min": 100, "label": "100-149", "color": "#EC7357"}, {"max": 99, "min": 50, "label": "50-99", "color": "#FDD692"}, {"max": 49, "min": 1, "label": "1-49", "color": "#FBFFB9"}, {"max": 0, "min": 0, "label": "0", "color": "#FFFFFF"}, ], )) #最大数据范围,分段 map1.add("",[list(z) for z in zip(city,loc['loc'])], maptype='china',is_roam=False, is_map_symbol_show=False) map1.render('fans_loc.html') |
从地区分布来看,广东粉最多,其次在四川、湖北、河南、山东、江苏、浙江分布较多
(3) 性别与地区交叉分布情况
1 2 3 4 5 6 7 | df_new=df[~df['loc'].isin(['其他'])] index=df_new.groupby('loc').count().sort_values(by='gender',ascending=False).index plt.figure(figsize=(15,6)) sns.countplot(data=df_new,x='loc',hue='gender',order=index,palette=['#f26d5b','#2EC4B6']) plt.xticks(rotation=90) plt.legend(loc='upper right') plt.show() |
大部分省份女粉是大于男粉的,也有部分地区如北京、上海、安徽等,男粉丝数量大于女粉数量。
(4) 用户微博数、关注数、粉丝量基本情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | gender_group=df.pivot_table(aggfunc=np.mean, index=df['gender'], values=df[['weibo_num','focus_num','fans_num']]).round(0) f,ax=plt.subplots(1,3,figsize=(15,6)) sns.barplot(x=gender_group.index,y=gender_group['weibo_num'], palette=['#f26d5b','#2EC4B6'],alpha=0.8,ax=ax[0]) ax[0].set_title('男女粉丝平均微博数') ax[0].set_xlabel('性别') ax[0].set_ylabel('平均微博数') sns.barplot(x=gender_group.index,y=gender_group['focus_num'], palette=['#f26d5b','#2EC4B6'],alpha=0.8,ax=ax[1]) ax[1].set_title('男女粉丝平均关注数') ax[1].set_xlabel('性别') ax[1].set_ylabel('平均关注数') sns.barplot(x=gender_group.index,y=gender_group['fans_num'], palette=['#f26d5b','#2EC4B6'],alpha=0.8,ax=ax[2]) ax[2].set_title('男女粉丝平均粉丝数') ax[2].set_xlabel('性别') ax[2].set_ylabel('平均粉丝数') plt.suptitle('邓紫棋粉丝微博基本信息') #子图添加总标题 plt.show() |
(5) 微博数、关注量、粉丝量相关性
1 2 3 4 | plt.figure(figsize=(10,6)) sns.heatmap(df[['weibo_num','focus_num','fans_num']].corr(),cmap='YlGn',annot=True) plt.title('微博数、关注数、粉丝数相关热力图') plt.show() |
相关系数的范围在-1到1之间。越接近1,正相关性越强,越接近-1,负相关性越强。
从上图来看,基本上三者之间的相关性还是很弱的,也就微博数与关注数相关性相对较高一点,但也没有超过0.5。
需要原数据的可以在评论回复"weibo"