导航菜单
首页 » IN南京 » 正文

盾安环境-我爬取了七万条弹幕,看看RNG和SKT打得怎么样!能怪UZI吗?

一、写在前面

直播职业现已炽热几年了,几个大渠道也有了各自共同的“弹幕文明”,不过现在许多渠道直播竞赛时的弹幕都根本无法看的,首要是由于网络上的喷子仍是挺多的,尤其是在观看竞赛的时分,许多弹幕不是喷选手便是喷战队,假如看了这种弹幕,真是让竞赛减分不少。

私信小编01 获取更多事例源码!

但和其他渠道比起来,B 站的弹幕会好一些。正好现在是英豪联盟的国际总决赛时刻,也有不少人挑选在 B 站看竞赛直播,那么咱们在看直播的时分会发什么弹幕呢?话不多说,这就用 Python 写个爬虫来爬取 B 站直播时的弹幕吧!

二、爬取剖析

首要翻开 Bilibili ,然后找到英豪联盟竞赛的直播间:

我得到的直播间的链接为: https://live.bilibili.com/6?broadcast_type=0&visit_id=8a盾安环境-我爬取了七万条弹幕,看看RNG和SKT打得怎么样!能怪UZI吗?bcmywu95s0#/ ,这个链接中的 broadcast_type 和 visit_id 是随机生成的,不过对咱们的爬取也没影响,只需找到直播间的链接就好了。

翻开开发者东西,切换到 NetWork,点选上 XHR,在其间能找到一个恳求:https://api.live.bilibili.com/ajax/msg。这个恳求需求四个参数(roomid,csrf_token,csrf,visit_id),其间 roomid 为直播间的 id,csrf_token 和 csrf 能够从浏览器上 copy,visit_id 为空。该恳求回来的成果中包含十条弹幕信息,包含弹幕内容、弹幕发送人昵称等等。所以要取得更多弹幕内容,咱们只需求一向发送这个恳求就 OK 了!

三、爬取完成

经过前面的剖析能够发现要爬取 B 站直播弹幕仍是很轻松的,可是要得到许多弹幕或许就需求考虑运用多线程了。关于爬取到的弹幕,还要及时地保存下来,这儿我挑选运用 MongoDB 数据库来保存弹幕信息。在爬取直播弹幕的时分,我开了四个线程来爬取,开了两个线程来解析和保存数据,线程之间运用行列来处理数据。

这儿建了两个类 CrawlThread 和 ParseThread,CrawThread 是用于爬取弹幕的线程,ParseThread 是用于解析和保存弹幕的线程,两个类都承继了 threading.Thread,偏重写了 run() 办法。下面是爬取弹幕的代码内容:

 1 class CrawlThread(threading.Thread):
2 def __init__(self, url: str, name: str, data_queue: Queue):
3 """
4 initial function
5 :param url: room url
6 :param na雄韬股份me: thread name
7 :param data_queue: data queue
8 """
9 super(CrawlThread, self).__init__()
10 self.room_url = url
11 self.room_id = re.findall(r"/(\d+)\?", url)[0]
12 self.headers = {
13 "Accept": "application/json,盾安环境-我爬取了七万条弹幕,看看RNG和SKT打得怎么样!能怪UZI吗? text/plain, */*",
14 "Content-Type": "application/x-www-form-urlencoded",
15 "Origin": "https://live.bilibili.com",
16 "Referer": "",
17 "Sec-Fetch-Mode": "cors",
18 "UserAgent": get_random_ua()
19 }
20 self.name = name
21 self.data_queue = data_queue
22
23 def run(self):
24 """
25 send request and receive response
26 :return:
27 """
28 while 1:
29 try:
30 time.sleep(1)
31 msg_url = "https://api.live.bilibili.com/ajax/msg"
32 # set referer
33 self.headers["Referer"] = self.room_url
34 # set data
35 data = {
36 "roomid": self.room_id,
37 "csrf_token": "e7433feb8e629e50c8c316aa52e78cb2",
38 "csrf": "e7433feb8e629e50c8c316aa52e78cb2",
39 "visit_id"盾安环境-我爬取了七万条弹幕,看看RNG和SKT打得怎么样!能怪UZI吗?: ""
40 }
41 res = requests.post(msg_url, headers=self.headers, data=data)
42 self.data_queue.put(res.json()["data"]["room"])
43 except Exception as e:
44 logging.error(self.name, e)

下面是解析和保存弹幕的代码内容,首要是一向查询行列,假如行列中有数据,就取出来进行解析和保存:

 1 class ParseThread(threading.Thread):
2 def __init__(self, url: str, name: str, data_queue: Queue):
3 """
4 initial function
5 :param url: room url
6 :param name: thread name
7 :param data_queue: data queue
8 """
9 super(ParseThread, self).__init__()
10 self.name = name
11 self.data_queue = data_queue
12 self.room_id = re.findall(r"/(\d+)\?", url)[0]
13 client = pymongo.MongoClient(host=MONGO_HOST, port=MONGO_PORT)
14 self.col = client[MONGO_DB][MONGO_COL + self.room_id]
15
16 def run(self):
17 """
18 get data from queue
19 :return:
20 """
21 while 1:
22 comments = self.data_queue.get()
23 logging.info("Comment count: {}".format(len(comments)))
24 self.parse(comments)
25
26 def parse(self, comments):
27 """
28 parse comment to get message
29 :return:
30 """
31 for x in comments:
32 comment = {
33 "text": x["text"],
34 "time": x["timeline"],
35 "username": x["nickname"],
36 "user_id": x["uid"]
37 }
38 # print(comment)
39 self.save_msg(comment)
40
41 def save_msg(self, msg: dict):
42 """
43 save comment to MongoDB
44 :param msg: comment
45 :return:
46 """
47 try:
48 self.col.insert_one(msg)
49 except Exception as e:
50 logging.info(msg)
51 logging.error(e)

从竞赛开端到竞赛完毕,一共爬取到了76530条弹幕,在 Robot 3T 中截图如下:

四、生成词云

弹幕信息现已存好了,可是考虑到其间有许多表情等无用内容,所以需求将这些内容给清洗掉。清洗完毕之后就能够进行分词操作了,这儿我挑选用 jieba 库来处理,在运用 jieba 的时分,能够设置用户词典,由于像选手 ID,英豪称号这些内容是会被分词的,但设置用户词典之后就不会被分词了,设置办法如下:

jieba.load_userdict("userdict.txt")

userdict.txt 中保存了选手 ID,选手外号,英豪称号等内容,在设置了用户词典后,这些内容在分词的时分都不会被分开了。在分词完毕之后,需求将那些长度为1的部分清除去,然后将呈现频次高的内容提取出来,这儿用到了 collecttions 中的 Counter,运用 Counter 能够很方便地计算频次。这一部分代码内容如下:

 1 def get_words(txt: str) -> str:
2 """
3 use jieba to cut words
4 :param txt: input text
5 :return:
6 """
7 # cut words
8 seg_list = jieba.cut(txt)
9 c = Counter()
10 # count words
11 for x in seg_list:
12 if len(x) > 1 and x != '\r\n':
13 c[x] += 1
14 result = ""
15 for (k, v) in c.most_common(300):
16 # print('%s %d' % (k, v))
17 result += "\n" + k
18 return result

在进行完上述操作之后,就能够运用 wordcloud 这个库来生成词云了,生成词云时能够设置中止词和字体,这一部分的代码如下:

 1 def generate_word_cloud(text):
2 """
3 generate word cloud
4 :param text: text
5 :return:
6 """
7 # text cleaning
8 with open("stopwords.txt", "r", encoding='utf-8') as f:
9 stopwords = set(f.read().split("\n"))
10 wc = WordCloud(
11 font_path="font.ttf",
12 background_color="white",
13 width=1200,
14 height=800,
15 max_words=100,
16 max_font_size=200,
17 min_font_size=10,
18 stopwords=stopwords, # 设置停用词
19 )
20 # generate word cloud
21 wc.generate("".join(text))
22 # save as an image
23 wc盾安环境-我爬取了七万条弹幕,看看RNG和SKT打得怎么样!能怪UZI吗?.to_file("rng_vs_skt.png")

终究生成的词云图为:

能够看到许多人都在评论 faker 的,李哥仍是李哥啊,李哥的瑞兹也是强的不可,也有不少弹幕在说天使和加里奥的问题,不得不说,小虎小明的发挥是有问题的,此外还有一些说喷子的,看来 B 站的喷子也不少啊。

二维码