通过之前爬取新浪微博发现,无论通过这里,还是这里,都没办法获取全部粉丝数据
那如果我想分析一个明星的男女粉丝数据怎么办,比如想知道某明星的男女粉丝占比,可以通过这样一个思路来解决这个问题采集该明星的所有微博
获取每条微博中 评论、点赞、转发 的用户id
根据id获取该用户数据(性别)
用户数据 存储到数据库中
存储到数据库中的用户数据允许重复,出现过一次该用户数据就代表他进行过 评论、点赞、转发 某一项中的一次 ;凡是有参与过的亲密值加一,当这个值超过一定限度时(比如说10或者20),我们就认为该用户是该明星的粉丝
在站点中 所发所有微博url还是很容易获取
start_urls = ['/api/container/getIndex?containerid=1076031223178222&page={}' .format(i) for i in range(1, 376)]
这里我们爬取胡歌的粉丝为例,谁叫人们总说胡歌男粉多呢 containerid=1076031223178222 中 1223178222 为用户id,可以自行修改换成其他用户 id
这里可以看到一共有多少微博,一个url大概10条微博,可以试出来大概多少页
代码
import scrapy
import json
from scrapy import Request
from ..items import WeiboFansSpiderItem
class WeiboFansSpdSpider(scrapy.Spider):
name = 'weibo_fans_spd'
start_urls = ['/api/container/getIndex?containerid=1076031223178222&page={}'
.format(i) for i in range(1, 376)]
repost_url = '/api/statuses/repostTimeline?id={}&page={}'
comment_url = '/api/comments/show?id={}&page={}'
attitudes_url = '/api/attitudes/show?id={}&page={}'
user_url = '/api/container/getIndex?type=uid&value={}'
def parse(self, response):
data = json.loads(response.text)
if data.get('ok') == 1:
weibos = data.get('data').get('cards')
for weibo in weibos:
mblog = weibo.get('mblog')
if mblog:
mid = mblog.get('mid')
# 转发
yield scrapy.Request(self.repost_url.format(mid, 1), callback=self.parse_repost, meta={'mid': mid, 'page': 1})
# 评论
yield scrapy.Request(ment_url.format(mid, 1), callback=self.parse_comment, meta={'mid': mid, 'page': 1})
# 点赞
yield scrapy.Request(self.attitudes_url.format(mid, 1), callback=self.parse_attitudes, meta={'mid': mid
处理转发
转发页面中可以直接获取用户详细数据
# 转发
def parse_repost(self, response):
data = json.loads(response.text)
if data['ok'] == 1:
for i in data.get('data').get('data'):
item = WeiboFansSpiderItem()
item['id'] = i.get('user').get('id')
item['statuses_count'] = i.get('user').get('statuses_count')
item['screen_name'] = i.get('user').get('screen_name')
item['profile_url'] = i.get('user').get('profile_url')
item['description'] = i.get('user').get('description')
item['gender'] = i.get('user').get('gender')
item['followers_count'] = i.get('user').get('followers_count')
item['follow_count'] = i.get('user').get('follow_count')
yield item
mid = response.meta['mid']
page = response.meta['page'] + 1
yield Request(self.repost_url.format(mid, page),
callback=self.parse_repost, meta={'page': page, 'mid': mid})
处理评论及点赞
评论或点赞中获取到id后,需要Ruquest 到 def parse_user 中获取详细用户数据
# 评论
def parse_comment(self, response):
data = json.loads(response.text)
if data['ok'] == 1:
for i in data.get('data').get('data'):
id = i.get('user').get('id')
yield Request(self.user_url.format(id), callback=self.parse_user)
mid = response.meta['mid']
page = response.meta['page'] + 1
yield Request(ment_url.format(mid, page),
callback=self.parse_comment, meta={'page': page, 'mid': mid})
# 点赞
def parse_attitudes(self, response):
data = json.loads(response.text)
if data['ok'] == 1:
for i in data.get('data').get('data'):
id = i.get('user').get('id')
yield Request(self.user_url.format(id), callback=self.parse_user)
mid = response.meta['mid']
page = response.meta['page'] + 1
yield Request(self.attitudes_url.format(mid, page),
callback=self.parse_attitudes, meta={'page': page, 'mid': mid})
处理用户数据
# 用户数据
def parse_user(self, response):
data = json.loads(response.text)
if data['ok'] == 1:
item = WeiboFansSpiderItem()
item['id'] = data.get('data').get('userInfo').get('id')
item['statuses_count'] = data.get('data').get('userInfo').get('statuses_count')
item['screen_name'] = data.get('data').get('userInfo').get('iscreen_named')
item['profile_url'] = data.get('data').get('userInfo').get('profile_url')
item['description'] = data.get('data').get('userInfo').get('description')
item['gender'] = data.get('data').get('userInfo').get('gender')
item['followers_count'] = data.get('data').get('userInfo').get('followers_count')
item['follow_count'] = data.get('data').get('userInfo').get('follow_count')
yield item
处理数据
在mongodb中 运用aggregate方法 并生成一个新集合
db.getCollection('WeiboFansSpiderItem').aggregate(
[
{"$group" : {_id:{id:"$id"}, count:{$sum:1}}},
{$sort:{"count":-1}},
{ $out:"result_id"},
],
{
allowDiskUse:true,
cursor:{}
}
)
MongoDB中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果
根据新生成的集合再进行处理
db.getCollection('result_id').find({'_id.gender':'f'}).count()
db.getCollection('result_id').find({'count':{'$gte':10},'_id.gender':'f'}).count()
我这里 代理ip时间有限 只爬取了11w+条数据就停止了爬取,只是做一个简单的参考吧原始数据 未根据id进行去重处理数据--------------男粉丝占比%32.74,女粉丝占比%67.26
根据id进行去重处理数据--------------------------男粉丝占比%33.67,女粉丝占比%66.33
亲密度大于10的粉丝-----------------------------男粉丝占比%25.30,女粉丝占比%74.70
谁说胡歌男粉多来着?