1. 首页
  2. 未分类

我爬取了七万条弹幕,看看RNG和SKT打得怎么样

“u003Cdivu003Eu003Cp class=”ql-align-justify”u003Eu003Cstrongu003E一、写在前面u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cp class=”ql-align-justify”u003E直播行业已经火热几年了,几个大平台也有了各自独特的“弹幕文化”,不过现在很多平台直播比赛时的弹幕都基本没法看的,主要是因为网络上的喷子还是挺多的,尤其是在观看比赛的时候,很多弹幕不是喷选手就是喷战队,如果看了这种弹幕,真是让比赛减分不少。u003Cu002Fpu003Eu003Cdiv class=”pgc-img”u003Eu003Cimg src=”http:u002Fu002Fp1.pstatp.comu002Flargeu002Fpgc-imageu002F87b2e10a13f342318b3f11aa56ca800e” img_width=”682″ img_height=”324″ alt=”我爬取了七万条弹幕,看看RNG和SKT打得怎么样” inline=”0″u003Eu003Cp class=”pgc-img-caption”u003Eu003Cu002Fpu003Eu003Cu002Fdivu003Eu003Cp class=”ql-align-justify”u003Eu003Cbru003Eu003Cu002Fpu003Eu003Cp class=”ql-align-justify”u003E但和别的平台比起来,B 站的弹幕会好一些。正好现在是英雄联盟的世界总决赛时间,也有不少人选择在 B 站看比赛直播,那么大家在看直播的时候会发什么弹幕呢?话不多说,这就用 Python 写个爬虫来爬取 B 站直播时的弹幕吧!u003Cu002Fpu003Eu003Cp class=”ql-align-justify”u003E u003Cu002Fpu003Eu003Cp class=”ql-align-justify”u003Eu003Cstrongu003E二、爬取分析u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cp class=”ql-align-justify”u003E首先打开 Bilibili,然后找到英雄联盟比赛的直播间:u003Cu002Fpu003Eu003Cdiv class=”pgc-img”u003Eu003Cimg src=”http:u002Fu002Fp1.pstatp.comu002Flargeu002Fpgc-imageu002F755211112e8e4a309870c0a795efbdd3″ img_width=”547″ img_height=”273″ alt=”我爬取了七万条弹幕,看看RNG和SKT打得怎么样” inline=”0″u003Eu003Cp class=”pgc-img-caption”u003Eu003Cu002Fpu003Eu003Cu002Fdivu003Eu003Cp class=”ql-align-justify”u003Eu003Cbru003Eu003Cu002Fpu003Eu003Cp class=”ql-align-justify”u003E先找一个直播链接,这个链接中的 broadcast_type 和 visit_id 是随机生成的,不过对我们的爬取也没影响,只要找到直播间的链接就好了。u003Cu002Fpu003Eu003Cp class=”ql-align-justify”u003E打开开发者工具,切换到 NetWork,点选上 XHR,在其中能找到一个请求:https:u002Fu002Fapi.live.bilibili.comu002Fajaxu002Fmsg。这个请求需要四个参数(roomid,csrf_token,csrf,visit_id),其中 roomid 为直播间的 id,csrf_token 和 csrf 可以从浏览器上 copy,visit_id 为空。该请求返回的结果中包含十条弹幕信息,包括弹幕内容、弹幕发送人昵称等等。所以要获得更多弹幕内容,我们只需要一直发送这个请求就 OK 了!u003Cu002Fpu003Eu003Cp class=”ql-align-justify”u003E u003Cu002Fpu003Eu003Cp class=”ql-align-justify”u003Eu003Cstrongu003E三、爬取实现u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cp class=”ql-align-justify”u003E通过前面的分析可以发现要爬取 B 站直播弹幕还是很轻松的,但是要得到大量弹幕可能就需要考虑使用多线程了。对于爬取到的弹幕,还要及时地保存下来,这里我选择使用 MongoDB 数据库来保存弹幕信息。在爬取直播弹幕的时候,我开了四个线程来爬取,开了两个线程来解析和保存数据,线程之间使用队列来处理数据。u003Cu002Fpu003Eu003Cp class=”ql-align-justify”u003E这里建了两个类 CrawlThread 和 ParseThread,CrawThread 是用于爬取弹幕的线程,ParseThread 是用于解析和保存弹幕的线程,两个类都继承了 threading.Thread,并重写了 run() 方法。下面是爬取弹幕的代码内容:u003Cu002Fpu003Eu003Cpre class=”ql-align-justify”u003E 1 class CrawlThread(threading.Thread):u003Cbru003E 2 def __init__(self, url: str, name: str, data_queue: Queue):u003Cbru003E 3 “””u003Cbru003E 4 initial functionu003Cbru003E 5 :param url: room urlu003Cbru003E 6 :param name: thread nameu003Cbru003E 7 :param data_queue: data queueu003Cbru003E 8 “””u003Cbru003E 9 super(CrawlThread, self).__init__()u003Cbru003E10 self.room_url = urlu003Cbru003E11 self.room_id = re.findall(r”u002F(\d+)\?”, url)[0]u003Cbru003E12 self.headers = {u003Cbru003E13 “Accept”: “applicationu002Fjson, textu002Fplain, *u002F*”,u003Cbru003E14 “Content-Type”: “applicationu002Fx-www-form-urlencoded”,u003Cbru003E15 “Origin”: “https:u002Fu002Flive.bilibili.com”,u003Cbru003E16 “Referer”: “”,u003Cbru003E17 “Sec-Fetch-Mode”: “cors”,u003Cbru003E18 “UserAgent”: get_random_ua()u003Cbru003E19 }u003Cbru003E20 self.name = nameu003Cbru003E21 self.data_queue = data_queueu003Cbru003E22 u003Cbru003E23 def run(self):u003Cbru003E24 “””u003Cbru003E25 send request and receive responseu003Cbru003E26 :return:u003Cbru003E27 “””u003Cbru003E28 while 1:u003Cbru003E29 try:u003Cbru003E30 time.sleep(1)u003Cbru003E31 msg_url = “https:u002Fu002Fapi.live.bilibili.comu002Fajaxu002Fmsg”u003Cbru003E32 # set refereru003Cbru003E33 self.headers[“Referer”] = self.room_urlu003Cbru003E34 # set datau003Cbru003E35 data = {u003Cbru003E36 “roomid”: self.room_id,u003Cbru003E37 “csrf_token”: “e7433feb8e629e50c8c316aa52e78cb2”,u003Cbru003E38 “csrf”: “e7433feb8e629e50c8c316aa52e78cb2”,u003Cbru003E39 “visit_id”: “”u003Cbru003E40 }u003Cbru003E41 res = requests.post(msg_url, headers=self.headers, data=data)u003Cbru003E42 self.data_queue.put(res.json()[“data”][“room”])u003Cbru003E43 except Exception as e:u003Cbru003E44 logging.error(self.name, e)u003Cbru003Eu003Cu002Fpreu003Eu003Cp class=”ql-align-justify”u003E下面是解析和保存弹幕的代码内容,主要是一直查询队列,如果队列中有数据,就取出来进行解析和保存:u003Cu002Fpu003Eu003Cpre class=”ql-align-justify”u003E 1 class ParseThread(threading.Thread):u003Cbru003E 2 def __init__(self, url: str, name: str, data_queue: Queue):u003Cbru003E 3 “””u003Cbru003E 4 initial functionu003Cbru003E 5 :param url: room urlu003Cbru003E 6 :param name: thread nameu003Cbru003E 7 :param data_queue: data queueu003Cbru003E 8 “””u003Cbru003E 9 super(ParseThread, self).__init__()u003Cbru003E10 self.name = nameu003Cbru003E11 self.data_queue = data_queueu003Cbru003E12 self.room_id = re.findall(r”u002F(\d+)\?”, url)[0]u003Cbru003E13 client = pymongo.MongoClient(host=MONGO_HOST, port=MONGO_PORT)u003Cbru003E14 self.col = client[MONGO_DB][MONGO_COL + self.room_id]u003Cbru003E15 u003Cbru003E16 def run(self):u003Cbru003E17 “””u003Cbru003E18 get data from queueu003Cbru003E19 :return:u003Cbru003E20 “””u003Cbru003E21 while 1:u003Cbru003E22 comments = self.data_queue.get()u003Cbru003E23 logging.info(“Comment count: {}”.format(len(comments)))u003Cbru003E24 self.parse(comments)u003Cbru003E25 u003Cbru003E26 def parse(self, comments):u003Cbru003E27 “””u003Cbru003E28 parse comment to get messageu003Cbru003E29 :return:u003Cbru003E30 “””u003Cbru003E31 for x in comments:u003Cbru003E32 comment = {u003Cbru003E33 “text”: x[“text”],u003Cbru003E34 “time”: x[“timeline”],u003Cbru003E35 “username”: x[“nickname”],u003Cbru003E36 “user_id”: x[“uid”]u003Cbru003E37 }u003Cbru003E38 # print(comment)u003Cbru003E39 self.save_msg(comment)u003Cbru003E40 u003Cbru003E41 def save_msg(self, msg: dict):u003Cbru003E42 “””u003Cbru003E43 save comment to MongoDBu003Cbru003E44 :param msg: commentu003Cbru003E45 :return:u003Cbru003E46 “””u003Cbru003E47 try:u003Cbru003E48 self.col.insert_one(msg)u003Cbru003E49 except Exception as e:u003Cbru003E50 logging.info(msg)u003Cbru003E51 logging.error(e)u003Cbru003Eu003Cu002Fpreu003Eu003Cp class=”ql-align-justify”u003E从比赛开始到比赛结束,总共爬取到了76530条弹幕,在 Robot 3T 中截图如下:u003Cu002Fpu003Eu003Cdiv class=”pgc-img”u003Eu003Cimg src=”http:u002Fu002Fp1.pstatp.comu002Flargeu002Fpgc-imageu002F1a745a63e334404abfd5827baeb9cc4a” img_width=”971″ img_height=”343″ alt=”我爬取了七万条弹幕,看看RNG和SKT打得怎么样” inline=”0″u003Eu003Cp class=”pgc-img-caption”u003Eu003Cu002Fpu003Eu003Cu002Fdivu003Eu003Cp class=”ql-align-justify”u003Eu003Cbru003Eu003Cu002Fpu003Eu003Cp class=”ql-align-justify”u003E u003Cu002Fpu003Eu003Cp class=”ql-align-justify”u003Eu003Cstrongu003E四、生成词云u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cp class=”ql-align-justify”u003E弹幕信息已经存好了,但是考虑到其中有很多表情等无用内容,所以需要将这些内容给清洗掉。清洗结束之后就能够进行分词操作了,这里我选择用 jieba 库来处理,在使用 jieba 的时候,可以设置用户词典,因为像选手 ID,英雄名称这些内容是会被分词的,但设置用户词典之后就不会被分词了,设置方法如下:u003Cu002Fpu003Eu003Cblockquoteu003Eu003Cemu003Ejieba.load_userdict(“userdict.txt”)u003Cu002Femu003Eu003Cu002Fblockquoteu003Eu003Cp class=”ql-align-justify”u003Euserdict.txt 中保存了选手 ID,选手外号,英雄名称等内容,在设置了用户词典后,这些内容在分词的时候都不会被分开了。在分词结束之后,需要将那些长度为1的部分清除掉,然后将出现频次高的内容提取出来,这里用到了 collecttions 中的 Counter,利用 Counter 可以很方便地统计频次。这一部分代码内容如下:u003Cu002Fpu003Eu003Cpre class=”ql-align-justify”u003E 1 def get_words(txt: str) -> str:u003Cbru003E 2 “””u003Cbru003E 3 use jieba to cut wordsu003Cbru003E 4 :param txt: input textu003Cbru003E 5 :return:u003Cbru003E 6 “””u003Cbru003E 7 # cut wordsu003Cbru003E 8 seg_list = jieba.cut(txt)u003Cbru003E 9 c = Counter()u003Cbru003E10 # count wordsu003Cbru003E11 for x in seg_list:u003Cbru003E12 if len(x) > 1 and x != ‘\r\n’:u003Cbru003E13 c[x] += 1u003Cbru003E14 result = “”u003Cbru003E15 for (k, v) in c.most_common(300):u003Cbru003E16 # print(‘%s %d’ % (k, v))u003Cbru003E17 result += “\n” + ku003Cbru003E18 return resultu003Cbru003Eu003Cu002Fpreu003Eu003Cp class=”ql-align-justify”u003E 在进行完上述操作之后,就可以使用 wordcloud 这个库来生成词云了,生成词云时可以设置停止词和字体,这一部分的代码如下:u003Cu002Fpu003Eu003Cpre class=”ql-align-justify”u003E 1 def generate_word_cloud(text):u003Cbru003E 2 “””u003Cbru003E 3 generate word cloudu003Cbru003E 4 :param text: textu003Cbru003E 5 :return:u003Cbru003E 6 “””u003Cbru003E 7 # text cleaningu003Cbru003E 8 with open(“stopwords.txt”, “r”, encoding=’utf-8′) as f:u003Cbru003E 9 stopwords = set(f.read().split(“\n”))u003Cbru003E10 wc = WordCloud(u003Cbru003E11 font_path=”font.ttf”,u003Cbru003E12 background_color=”white”,u003Cbru003E13 width=1200,u003Cbru003E14 height=800,u003Cbru003E15 max_words=100,u003Cbru003E16 max_font_size=200,u003Cbru003E17 min_font_size=10,u003Cbru003E18 stopwords=stopwords, # 设置停用词u003Cbru003E19 )u003Cbru003E20 # generate word cloudu003Cbru003E21 wc.generate(“”.join(text))u003Cbru003E22 # save as an imageu003Cbru003E23 wc.to_file(“rng_vs_skt.png”)u003Cbru003Eu003Cu002Fpreu003Eu003Cp class=”ql-align-justify”u003E 最终生成的词云图为:u003Cu002Fpu003Eu003Cdiv class=”pgc-img”u003Eu003Cimg src=”http:u002Fu002Fp9.pstatp.comu002Flargeu002Fpgc-imageu002F25fe1a924fc8480ea11f14bee3d2720e” img_width=”923″ img_height=”617″ alt=”我爬取了七万条弹幕,看看RNG和SKT打得怎么样” inline=”0″u003Eu003Cp class=”pgc-img-caption”u003Eu003Cu002Fpu003Eu003Cu002Fdivu003Eu003Cpu003E最后,小编想说:我是一名python开发工程师,整理了一套最新的python系统学习教程,想要这些资料的可以关注私信小编“01”即可,希望能对你有所帮助u003Cu002Fpu003Eu003Cp class=”ql-align-justify”u003Eu003Cbru003Eu003Cu002Fpu003Eu003Cp class=”ql-align-justify”u003E u003Cu002Fpu003Eu003Cu002Fdivu003E”

原文始发于:我爬取了七万条弹幕,看看RNG和SKT打得怎么样

主题测试文章,只做测试使用。发布者:熱鬧獨處,转转请注明出处:http://www.cxybcw.com/18189.html

联系我们

13687733322

在线咨询:点击这里给我发消息

邮件:1877088071@qq.com

工作时间:周一至周五,9:30-18:30,节假日休息

QR code