微博数据爬虫教程,怎么用爬虫记录明星微博数据注水全过程

微博数据爬虫教程,怎么用爬虫记录明星微博数据注水全过程(1)

第 0 分钟开始就能看到数据,这是观察这个姐姐微博真实人气的绝佳机会,也是观察这个姐姐的微博是否发水的绝佳时间窗的起点。

根据过往经验总结,对于基于时间线传播的内容来说,从第 0 分钟开始的那十几分钟的数据有以下特点:

  • 内容不可能火到上热搜,所以热搜榜没有影响;
  • 机器人水军要去主动联系还要排期,因此一时半会也没法到位;
  • 粉丝数据组轮博刷评论,也要去群里和超话先布置任务什么的,因此也没法这么快就进来。

因此,刚开始那十几分钟的数据,是最「干净」的。

当后面热搜、水军、粉丝数据组进来之后,只要一和最初那十几分钟的干净数据一对比,一下子就都能现原形了。

然而,要从第 0 分钟开始收集数据,靠人工盯和手抄是不太靠谱的。

一方面,你不知道明星什么时候发微博;另一方面,手刷再手记的话,会占用自己大量的时间,记录效率也低。

为了解决这两个问题,我想了想,作为一个流行病学搬砖工,我最会的就是 R 了,那就用 R 写个微博爬虫自动监视明星主页吧。

如何在 R 中实现微博爬虫

(对技术细节不感兴趣的观众朋友们,你们可以划过这部分,直接看下一个大标题「爬虫监视结果:娱乐圈人均发水,区别只在多少」)

写爬虫,有一个基本格言,叫做「可见即可爬」。不过,微博 web 版对爬虫设置了登陆屏障,直接通过爬虫访问微博,只能抓回一个跳转中的网页:「Sina Visitor System」。

幸好,微博移动端是可以被爬虫直接访问的。

  • 找到要爬取的具体网址

观察微博移动端加载全过程的网络活动,可以发现:微博移动端的全部微博数据,都可以在一个 json 中找到。

微博数据爬虫教程,怎么用爬虫记录明星微博数据注水全过程(2)

经过确认,value= 后面的这个东西是固定的用户 ID,也就是每个人微博主页的 uid;containerid,不知道从哪儿来的,但是很幸运的是,每次加载,这个 containerid 都是不变的。

作为一个学流行病学而非计算机专业的人,我直觉觉得这个 containerid 怎么生成对我来说应该是个很难查的问题。鉴于每次加载它这个链接都不会变,那本外行就懒得去研究怎么找到这个 containerid 了,直接复制这个 json 的链接拿来爬就是。

URLs = 'https://m.weibo.cn/api/container/getIndex?type=uid&value=1757744065&containerid=1076031757744065'

取回 json 之后,照例美化一下格式,方便阅读和后续数据提取:

### require a package to format json file from weibo require(jsonlite) ### read json file for weibo lists json=readLines(jsonURL,encoding = 'UTF-8') ### format the json file fetched json=prettify(json) writeLines(json,'D:/desktop/weibocrawler/json.txt')

这里输出了 txt,是因为 jsonlite 这个轮子美化格式换行用的是直接加换行符,这种换行符 gsub() 是识别不了的,因此得弄成 txt 让 readLines() 重新读一遍,才能做成 gsub() 能够识别的分行的对象。

微博数据爬虫教程,怎么用爬虫记录明星微博数据注水全过程(3)

观察这个 json,可以发现它一次会包含 10 条最近的微博,其中每条微博开始和结束的时候长这样,而且用黄色标识出来的这两个字段是唯一的:

微博数据爬虫教程,怎么用爬虫记录明星微博数据注水全过程(4)

红线以上是上一条微博,红线以下是下一条微博

所以,用这两个黄色的开始、结束标志作为分段,撰写代码如下:

### separate the 10 weibos page=readLines('json.txt') starts=grep(' "card_type": 9,',page) ends=grep(' "show_type": 0',page)

  • 将取回的 json 中含有的数据提取出来

我前面遇到的主要问题是,我不知道明星啥时候发微博。所以,爬虫要能够监测新微博的出现,就不能指定具体哪条微博。

此外,每条微博我都想监测起码两天以上的数据变化,如果只抓最新两三条微博,那么明星万一失心疯连着刷个五六条的,我的程序就不抓了,这可不行。

固然,我可以每次抓回来列表之后取一下发表时间再算算这微博还要不要抓,但是这实在是太麻烦了。既然这个 json 文件一次能提供个人主页全部前 10 条微博的数据,那就每次爬取都把这最新 10 条微博的数据全都记录下来好了!后边如果有空,再慢慢迭代添加算时间的代码吧。

接下来是每条微博的实时累计互动数据。观察 json 文件,可以发现我们要的数据在以下这些字段里:

微博数据爬虫教程,怎么用爬虫记录明星微博数据注水全过程(5)

因此,通过如下代码,把这些数据用 gsub() 提取出来,然后放进数据库。

#### create the data matrix for saving data: weibo ID, timestamp, repost, comment, like topwb=length(grep('"text": "置顶",',page))!=0 db=matrix(nrow = length(starts),ncol = 8) if (topwb) {db=matrix(nrow = length(starts)-1,ncol = 8)} colnames(db)=c('weibo_ID', 'weibo_text', 'timestamp', 'repost', 'comment', 'like', 'isRepost', 'fromChaoHua') #### fill in the data for (i in 1:length(starts)) { weibo=page[starts[i]:ends[i]] # remove pinned weibo if (length(grep('"text": "置顶",',weibo))!=0) {next} # correct i for skipped weibos rowdb=length(db[,1])-(length(starts)-i) # get attributes wbid=gsub(' "bid": "','',weibo[grep(' "bid": "',weibo)]) wbid=gsub(',|"|\\s','',wbid) wbtext=gsub(' "raw_text": "','',weibo[grep('"raw_text": "',weibo)]) wbtext=gsub('",','',wbtext) repo=gsub("[^0-9]",'',weibo[grep('"reposts_count": ',weibo)]) comment=gsub("[^0-9]",'',weibo[grep('"comments_count": ',weibo)]) like=gsub("[^0-9]",'',weibo[grep('"attitudes_count": ',weibo)]) if (length(grep(' "retweeted": 1,',weibo))>0) {repost=1} else {repost=0} if (grepl('超话',weibo[grep(' "source": ',weibo)][1])) {fromch=1} else {fromch=0} # if a weibo is a repost, keep only the data from the user being observed db[rowdb,1]=as.character(wbid[length(wbid)]) db[rowdb,2]=wbtext[length(wbtext)] db[rowdb,3]=as.numeric(Sys.time()) db[rowdb,4]=repo[length(repo)] db[rowdb,5]=comment[length(comment)] db[rowdb,6]=like[length(like)] db[rowdb,7]=repost db[rowdb,8]=fromch }

第二部分就是简单转移了下数据,看起来很多此一举,其实是因为,如果一条微博是转发微博,那么前面的那些字段抓回来的数据都会有两套。我们只关心明星的数据,不关心原博的,所以需要只留第二个。

理论上,写成类似 wbid[2]这样也行,但是我「有如无必要绝不写死参数」的强迫症,所以还是习惯性写成动态的最后一个。

最后,把以上过程全部打包在一起,写成一个函数,方便调用:

wbwatcher = function(jsonURL) { <.........> return(db) }

  • 自动监视自动存数据

光写一个函数,肯定是不够的。所以这里我们要搞一个自动轮询的循环。

既然都写爬虫了,那就干脆一次多整点明星上去吧。我刚看完浪姐,那就以 30 位浪姐作为样本,然后再加上肉眼确认过不买水军的何老师作为阴性对照,加上大家公认的四字水后作阳性对照。

微博数据爬虫教程,怎么用爬虫记录明星微博数据注水全过程(6)

接下来是循环本体:

while (Sys.time()<"2020-11-10 23:59:59 CEST") { # define stop time for (i in 1:length(urltable$URLs)) { URL=urltable$URLs[i] if (length(grep('m.weibo.cn/statuses/show?id=',URL,fixed = T))!=0) { try({ # use try() to prevent breaks from errors caused by network failure db=wbpostwatcher(URL) }) if (!is.na(db[1,1])) { print(paste('Success!', 'Checked', urltable$names[i], ' at',Sys.time())) } } else { try({ db=wbwatcher(URL) # another similar function, used to watch a single weibo only }) if (!is.na(db[1,1])) { print(paste('Success!', 'Checked', urltable$names[i], ' at',Sys.time())) } } db=as.table(db) if (!is.na(db[1,1])) { db=cbind(rep(urltable$names[i],length(db[,1])),db) colnames(db)[1]='name' write.table(db, "D:/desktop/weibocrawler/db_sisters.csv", sep = ",", col.names = !file.exists("D:/desktop/weibocrawler/db_sisters.csv"), row.names = F, append = T) } else {print(paste('Error! at',Sys.time()))} Sys.sleep(5) # Pause query to prevent being banned by weibo } }

最后这一套程序执行下来的效果是这样的:

微博数据爬虫教程,怎么用爬虫记录明星微博数据注水全过程(7)

爬虫监视结果:娱乐圈人均发水,区别只在多少

正常情况下,在基本没有粉丝做数据、没有机器刷数据的时候,作为一种基于时间线的、与多个博主内容相互竞争传播的、时间越长排序越后被刷到的概率越低的内容,一条微博的转评赞数据增长曲线大体应该是这样的:

微博数据爬虫教程,怎么用爬虫记录明星微博数据注水全过程(8)

即使是靠近半夜,也只是曲线下降的速度变快而已:

微博数据爬虫教程,怎么用爬虫记录明星微博数据注水全过程(9)

请记住上面的正常的曲线长啥样。然后,坐稳了,我们要看不正常的了~

以下是部分被监测的明星的微博评论数据变化趋势:有午夜惊魂型的,半夜十二点前在 638 秒内突然集中增加了 2000 条评论和 20000 个赞:

微博数据爬虫教程,怎么用爬虫记录明星微博数据注水全过程(10)

微博数据爬虫教程,怎么用爬虫记录明星微博数据注水全过程(11)

微博数据爬虫教程,怎么用爬虫记录明星微博数据注水全过程(12)

微博数据爬虫教程,怎么用爬虫记录明星微博数据注水全过程(13)

也有光天化日公然刷量的:

微博数据爬虫教程,怎么用爬虫记录明星微博数据注水全过程(14)

当然,请务必注意,前面这些图,虽然能强力提示这些明星的微博有水分,但并不能证明水是明星本人买的——毕竟,这些水也可能是广告公司、经纪公司、粉丝买的。比如金晨的微博转发之所以有异常增长,就很可能是她粉丝干的:

微博数据爬虫教程,怎么用爬虫记录明星微博数据注水全过程(15)

微博数据爬虫教程,怎么用爬虫记录明星微博数据注水全过程(16)

而如果你问她们,为什么要给自己姐姐用机器刷数据,她们的回答一般是:为了给姐姐排面、为了让姐姐数据更好看——与此同时,却浑然不知或者假装不知,这样低劣的机刷数据,在稍微像样点的娱乐数据分析公司那里,都能一秒现原形。

后记

在这篇文章里举出的疑似发大水的曲线,还只是我观测到的所有曲线图中的一小部分。

我的程序从德国的昨天早上跑到现在,一共抓住了十几位发了新微博的明星,有了他们的微博从第 0 分钟开始的传播数据全程变化。

在这十几个人当中,除了我肉眼翻完过评论鉴定的何炅何老师仍然保持着阴性对照的优良作风之外,其他大部分人,包括一些非常有名的演员和歌手,都有这种几分钟内几千几万的异常的增长。

唯一区别,只在这些刷的量和他们真实流量的比例多少:

有的人 5/1,有的人 10~20/1,有的人甚至 100/1 以上。

是的,数据造假是不光彩的。然而,在这泥沙俱下的流量经济时代之中,无论是初出茅庐急需认可的年轻艺人,还是已经功成名就的圈内前辈,只要还想继续从广告投放商那里赚钱,那么每个人都得被逼着接受这样的现实。这一风雨晦暝的时代,何时才能落下帷幕呢?愿我们仍能见证那一天的到来。

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页