Python Selenium简单爬取虎牙直播弹幕(仅学习)


前言

学习python的第二周,在此记录学习进程:

这次有了需求,由于要做主播的视频剪辑,但是虎牙提供的弹幕热力流在长时间轴中极不敏感,很难快速在6个小时的录播中找到热点,因此打算直接使用爬虫爬取直播弹幕。


本文内容仅用于学习,请勿商用

一、爬虫思路

直播界面的弹幕和礼物都不需要登录态,因此不需要借助cookie;
但是直播本身是使用了socket,而且初步研究之后觉得使用socket破解加密实在超出水平太多,因此打算使用神器selenium。

二、使用步骤

1.引入库

代码如下(示例):

这次的库除了基本库套餐+selenium外,加入了signal,用于监听中断信号。

import csv,time,sys,signal
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

2.通过selenium进入直播间

安装webdriver的具体事宜有很多文章可参考,这里就不赘述了;

代码如下(示例):

一句话打开浏览器:

driver = webdriver.Chrome()

组装URL,打开网页:

url  ='https://www.huya.com/'+self.target
driver.get(url)

3.分析HTML

到了直播间页面,首先找到我们想要的东西:弹幕窗口
在这里插入图片描述
然后F12,分析HTML结构:
在这里插入图片描述
显然,弹幕(聊天)窗口在一个id=‘chat-room__list’的ul标签中,里面有li标签装起来的每条聊天(class=‘J_msg’)。

chatRoomList = driver.find_element_by_id("chat-room__list")
chatMsgs = chatRoomList.find_elements_by_class_name("J_msg")

J_msg有很多条,先观察一下大致的长相:

  • 礼物

礼物

  • 消息

消息
其他的都不需要收集,忽略就好。


for chatMsg in chatMsgs:
    try:
        content = {} #初始化弹幕内容字典
        #尝试是否为礼物弹幕
        try:
            hSend = chatMsg.find_element_by_class_name("tit-h-send")
            content['username'] = hSend.find_elements_by_class_name("cont-item")[0].text
            content['gift'] = hSend.find_element_by_class_name("send-gift").find_element_by_tag_name("img").get_attribute("alt")
            content['num'] = hSend.find_elements_by_class_name("cont-item")[3].text
       except:
              pass
       #尝试是否为消息弹幕
       try:
           mSend = chatMsg.find_element_by_class_name("msg-normal")
           content["username"] = mSend.find_element_by_class_name("J_userMenu").text
           content["msg"] = mSend.find_element_by_class_name("msg").text
           except:
                  pass
       #存入弹幕列表
	   #...
                    
    except:
           continue

刚学try-except,所以写了好几个
想要的都找到了。跑起来看看效果:

在这里插入图片描述
效果不错,空字典是因为存储的方法没有去空,导致进入直播间的J_msg也被当成消息存了。
稍微修改一下存储方法:

def SaveToBarrageList(self,content):#弹幕列表存储
        if not content: #去空
            pass
        else:
            content['time'] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) 

再加了一条时间,这样可以大致知道这些弹幕出现的时间(不精确)

4.实现伪监听

由于直播的内容都是通过socket实时传输的,而我们没办法通过socket去监听响应,只能高频获取HTML来实现伪监听了——这种形式并没有发送请求,因此也不会因为高频访问被封号或禁止。

while True: #无限循环,伪监听
            time.sleep(1) #等待1秒加载
            #...

用一个非常简单的无限循环将刚刚的selenium部分框进来,这样脚本就会不停地去重复刚刚的动作,采集HTML里的J_msg,正好配合J_msg的更新。

但是这样会导致另一个问题,也就是J_msg的重复读取:
因此我们再观察J_msg的标签,可以看到J_msg的标签带有属性data-id

显然这个id不重复,因此可以将data-id作为弹幕的id来导入:

dataId = chatMsg.get_attribute('data-id') #每条弹幕都有独立data-id
self.SaveToBarrageList(dataId,content)

把data-id作为key存入字典中,利用字典去重:

if dataId in self.barrageList or not content: #去重、去空
	pass

跑起来看看:
在这里插入图片描述

这样就可以得到一个完美的弹幕字典了!
这里再加一个监听ctrl+C信号的方法,这样录完弹幕就可以直接ctrl+C退出了:

def QuitAndSave(signum, frame):#监听退出信号
    print ('catched singal: %d' % signum)
    hyObj.SaveToCSV('test',['username','time','msg','gift','num'],hyObj.barrageList.values())
    sys.exit(0)

看看最终导出到csv的结果:
在这里插入图片描述
大功告成!

总结

以下为完整代码:

#!/usr/bin/env python3
# coding=utf-8
# author:sakuyo
#----------------------------------

import csv,time,sys,signal
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

class Huya(object):
    def SaveToCSV(self,fileName,headers,contents):
        titles = headers
        data = contents
        #csv用utf-8-sig来保存
        with open(fileName+'.csv','a',newline='',encoding='utf-8-sig') as f:
            writer = csv.DictWriter(f,fieldnames=titles)
            writer.writeheader()
            writer.writerows(data)
            print('写入完成!')

class HuyaLive(Huya):

    def __init__(self,target):#初始化 输入值target为直播间ID
        self.target = target
        self.barrageList = {}
    
    def Connect(self):#连接直播间
        chrome_options = Options()
        # 使用headless无界面浏览器模式
        chrome_options.add_argument('--headless') #增加无界面选项
        chrome_options.add_experimental_option("detach", True)
        driver = webdriver.Chrome(options=chrome_options)
        url  ='https://www.huya.com/'+self.target
        driver.get(url)
        time.sleep(5)
       
        while True: #无限循环,伪监听
            time.sleep(1) #等待1秒加载
            chatRoomList = driver.find_element_by_id("chat-room__list")
            chatMsgs = chatRoomList.find_elements_by_class_name("J_msg")
            #定位弹幕div,逐条解析
            for chatMsg in chatMsgs:
                try:
                    dataId = chatMsg.get_attribute('data-id') #每条弹幕都有独立data-id
                    content = {} #初始化弹幕内容字典
                    #尝试是否为礼物弹幕
                    try:
                        hSend = chatMsg.find_element_by_class_name("tit-h-send")
                        content['username'] = hSend.find_elements_by_class_name("cont-item")[0].text
                        content['gift'] = hSend.find_element_by_class_name("send-gift").find_element_by_tag_name("img").get_attribute("alt")
                        content['num'] = hSend.find_elements_by_class_name("cont-item")[3].text
                    except:
                        pass
                    #尝试是否为消息弹幕
                    try:
                        mSend = chatMsg.find_element_by_class_name("msg-normal")
                        content["username"] = mSend.find_element_by_class_name("J_userMenu").text
                        content["msg"] = mSend.find_element_by_class_name("msg").text
                    except:
                        pass
                    #存入弹幕列表
                    self.SaveToBarrageList(dataId,content)
                    
                except:
                    continue

    def SaveToBarrageList(self,dataId,content):#弹幕列表存储
        if dataId in self.barrageList or not content: #去重、去空
            pass
        else:
            content['time'] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) 
            self.barrageList[dataId] = content
            print(dataId,content)







def QuitAndSave(signum, frame):#监听退出信号
    print ('catched singal: %d' % signum)
    hyObj.SaveToCSV('test',['username','time','msg','gift','num'],hyObj.barrageList.values())
    sys.exit(0)


if __name__ == '__main__':#执行层
    #信号监听
    signal.signal(signal.SIGTERM, QuitAndSave)
    signal.signal(signal.SIGINT, QuitAndSave)

    hyObj = HuyaLive('chuhe')
    hyObj.Connect()
  • 7
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
使用selenium爬取虎牙直播弹幕的大致流程如下: 1. 安装selenium库和对应的浏览器驱动(如ChromeDriver)。 2. 打开浏览器,并访问虎牙直播间的页面。 3. 利用selenium模拟用户操作,点击“登录”按钮,输入账号密码进行登录。 4. 定位弹幕输入框,利用selenium模拟输入弹幕并发送。 5. 利用selenium定位弹幕显示区域,获取其中的弹幕信息。 6. 不断循环执行第5步,可以实现持续爬取弹幕的功能。 下面是一个简单的示例代码,可以爬取指定虎牙直播间的弹幕: ```python from selenium import webdriver import time # 设置浏览器选项 options = webdriver.ChromeOptions() options.add_argument('--headless') # 无头模式,不显示浏览器界面 # 打开浏览器 driver = webdriver.Chrome(options=options) # 访问虎牙直播间 driver.get('https://www.huya.com/123456') # 将123456替换成指定直播间的ID # 登录 login_button = driver.find_element_by_css_selector('.login-btn') login_button.click() time.sleep(1) # 等待登录弹窗加载 username_input = driver.find_element_by_css_selector('#loginU') password_input = driver.find_element_by_css_selector('#loginP') username_input.send_keys('your_username') # 将your_username替换成自己的虎牙账号 password_input.send_keys('your_password') # 将your_password替换成自己的虎牙密码 submit_button = driver.find_element_by_css_selector('.login-btns .login-btn') submit_button.click() time.sleep(3) # 等待登录完成 # 发送弹幕 danmu_input = driver.find_element_by_css_selector('.msg-input textarea') danmu_input.send_keys('hello, world!') send_button = driver.find_element_by_css_selector('.msg-send-btn') send_button.click() # 获取弹幕信息 while True: danmu_list = driver.find_elements_by_css_selector('.msg-normal') for danmu in danmu_list: print(danmu.text) time.sleep(1) # 等待1秒后再次获取弹幕信息 ``` 注意,上述代码中的账号密码需要替换成你自己的虎牙账号密码,而直播间的ID需要替换成你要爬取直播间的ID。此外,由于虎牙网站对爬虫有一定的限制,建议在爬取时加入一些限制(如适当增加等待时间、降低爬取频率等),以避免被封禁账号。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sakuyooo

给住在深圳河里的水吗喽赏点零食

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值