爬取b站肖科长所有语录,学习废话文学

如有侵权,请联系我立马删除,本篇文章仅供学习参考。

前言

近期在看b站的时候,发现有个up主的废话文学很有意思,再加上现生成式AI大火,因此想来用它的废话来教AI说话,因此花了几个小时时间将该UP主的所有视频里的言论给爬了下来,现记录爬取过程。

需求分析

为达成我们的目的,整个项目可以简单分为以下几个步骤:

  1. 获取视频音频文件
  2. 获取所有视频链接,对每个视频进行解析
  3. 语音转文字
  4. 保存

实操

下面一步步来讲一讲如何实现这样一个功能。

获取视频音频文件

随便打开B站一个视频链接,按F12打开开发者工具,查看网络请求,查看请求信息。 file 可以看到的第一个网络请求包含了许多信息,能够发现在它的返回响应下有一个在video字段下有一个baseUrl,同时还有一个对应的audio字段,可以推测出B站的音频文件和视频文件是分开的,我们直接通过浏览器打开这个链接会发现是404 Forbidden,推测是需要在请求的时候带上一些参数,索性这里直接通过代码来模拟请求参数。到请求出找到对应的cookie填入代码。 file 代码示例如下,运行代码(请自行导入必要的库文件),可以看到音频文件已经成功保存在audio文件夹下,同时音频能够正确播放。

url = "https://www.bilibili.com/video/BV1Px4y1t7oc"
headers = {
    "Referer": url,
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
    "Cookie": "buvid3=F5F33C44-C82E-5255-9D24-CEA4EA9A466700800infoc; b_nut=1716952800; _uuid=6D2EC47D-2F1A-8781-2E4D-5149CB6CC1A800547infoc; buvid_fp=9c0fb91bd0992985da0bf0d686d59d22; buvid4=277DD6BD-CDD6-CCBA-7689-4129F307271A01980-024052903-qpfGkYpPUlsOG5ISWxdeMA%3D%3D; enable_web_push=DISABLE; home_feed_column=4; header_theme_version=CLOSE; browser_resolution=1232-678; CURRENT_FNVAL=4048; rpdid=|(m~l~JRRkY0J'u~u~uRm~)R; DedeUserID=97057949; DedeUserID__ckMd5=393ec8e667ea9712; CURRENT_QUALITY=80; b_lsid=96964F19_1903A086DE3; bili_ticket=eyJhbGciOiJIUzI1NiIsImtpZCI6InMwMyIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTkyMTk3NDksImlhdCI6MTcxODk2MDQ4OSwicGx0IjotMX0.5WZh9IdmrNlW4c2CE1rMYcRwzQkEMvaCVMXW02t1CFc; bili_ticket_expires=1719219689; SESSDATA=04730752%2C1734512557%2C3b2f6%2A61CjCfwyiyNNfV3wEqaL3iVi8Uga5Cld5v2IvlL17tyEEm6yOLDsg_JR2Y6ej17ze_nPcSVmUzc2dsRWEwVGFSWTROOFllQ1lJT3lWYm1RT21MVlNwWG44LUE4VW9Kc2VLbnJSYnlIY3pmX0tIQ203ZF80Ykg0NE1udk1yeHVBZDhUcXpXNjFOWFlnIIEC; bili_jct=79b47f0aea80a58d67729e8f18a062aa; sid=70ubcgpc"
}
response = requests.get(url=url, headers=headers)
text = response.text
title = re.findall('title="(.*?)"', text)[0]
info = re.findall('window.__playinfo__=(.*?)</script>', text)[0]
json_data = json.loads(info)
audio_url = json_data['data']['dash']['audio'][0]['baseUrl']
# 打印以下两个链接是否成功获取到
print(audio_url)
# 然后再次发起请求,并且保存音频文件
audio_content = requests.get(url=audio_url, headers=headers).content
with open('audios/' + title + '.mp3', mode='wb') as a:
    a.write(audio_content)
print("saved.")

file

获取所有视频链接

为了获取所有的视频链接,我们需要对肖科长的个人主页进行爬取,看看B站视频列表信息的存放形式,同样地,打开个人主页和开发者工具,查看网络请求,看看返回的参数。(小tips:直接搜索文章标题看看哪条请求的响应中包含了这个标题,一般来说可以快速定位到具体的请求信息) file 可以看到个人视频信息是由vlist来保存的,和上面一样去对它进行解析,不过这个查询应该是一个分页查询,果不其然在请求下面能够找到分页的信息,不过我们只需要在请求的时候指定一下参数就好了。 file

import re
import requests
import json

url = "https://api.bilibili.com/x/space/wbi/arc/search?mid=628154800&ps=30&tid=0&pn=1&keyword=&order=pubdate&platform=web&web_location=1550101&order_avoided=true&dm_img_list=[%7B%22x%22:2156,%22y%22:1533,%22z%22:0,%22timestamp%22:4,%22k%22:96,%22type%22:0%7D,%7B%22x%22:2793,%22y%22:2076,%22z%22:68,%22timestamp%22:192,%22k%22:101,%22type%22:0%7D]&dm_img_str=V2ViR0wgMS4wIChPcGVuR0wgRVMgMi4wIENocm9taXVtKQ&dm_cover_img_str=QU5HTEUgKEludGVsLCBJbnRlbChSKSBJcmlzKFIpIFhlIEdyYXBoaWNzICgweDAwMDBBN0EwKSBEaXJlY3QzRDExIHZzXzVfMCBwc181XzAsIEQzRDExKUdvb2dsZSBJbmMuIChJbnRlbC&dm_img_inter=%7B%22ds%22:[%7B%22t%22:0,%22c%22:%22%22,%22p%22:[228,76,76],%22s%22:[147,3745,678]%7D],%22wh%22:[2983,2441,27],%22of%22:[288,576,288]%7D&w_rid=6be17d43d26261d001c50ae194ae63bd&wts=1721285773"
headers = {
    "Referer": "https://space.bilibili.com/628154800",
    "Origin": "https://space.bilibili.com",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
    "Cookie": "buvid3=F5F33C44-C82E-5255-9D24-CEA4EA9A466700800infoc; b_nut=1716952800; _uuid=6D2EC47D-2F1A-8781-2E4D-5149CB6CC1A800547infoc; buvid4=277DD6BD-CDD6-CCBA-7689-4129F307271A01980-024052903-qpfGkYpPUlsOG5ISWxdeMA%3D%3D; enable_web_push=DISABLE; header_theme_version=CLOSE; CURRENT_FNVAL=4048; rpdid=|(m~l~JRRkY0J'u~u~uRm~)R; DedeUserID=97057949; DedeUserID__ckMd5=393ec8e667ea9712; CURRENT_QUALITY=80; fingerprint=1ae13135f14be8b56e2acc41afd7e4ba; buvid_fp_plain=undefined; buvid_fp=1ae13135f14be8b56e2acc41afd7e4ba; SESSDATA=40c35a62%2C1736662528%2Cbd815%2A71CjAiBcr9It8aZjSjwquNGR-AWd0i6smu_a3dvHWVmOhf2ubD8hk5acsmJhV5ia1u4A4SVkx6NTA1MWtJeWYtQnZBeTZnb3BjV21jeDBiRWRtZU9PN3FqWjc3eDhwU3I0UU9kSERSNGp2bGxfM0s0ZjF6LWZ0TndmemZONmEwaU9ybndpOTVMYmZnIIEC; bili_jct=2d160b37ebddfd56c91b02b15ef3258a; bili_ticket=eyJhbGciOiJIUzI1NiIsImtpZCI6InMwMyIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjEzNjk3NDYsImlhdCI6MTcyMTExMDQ4NiwicGx0IjotMX0.j3EjsA3SvcGApzDzHIzs7kj4Rmq5kAfAHLp8HfzjQ2A; bili_ticket_expires=1721369686; b_lsid=51071E72B_190C474643B; bsource=search_bing; home_feed_column=5; browser_resolution=1872-1078; bp_t_offset_97057949=955392234927161344; sid=g3hqeg3g",
}
response = requests.get(url=url, headers=headers)
html = response.text
print(html)
json_data = json.loads(html)
vlist = json_data['data']['list']['vlist']
with open("xiao_infos.txt", "w") as f:
    for li in vlist:
        res = "title:{}, author:{}, bvid:{}\n".format(li["title"], li["author"], li["bvid"])
        print(res)
        f.write(res)
print("saved.")

file

语音转文字

根据以上两步,我们已经保存了所有的视频链接,通过这样的链接接着就能获取到所有音频文件,于是接下来就需要将音频文件来转文字,音频转文字的方案我这里直接使用讯飞送的一点离线时长来调用这个API,在调用的过程中可以使用多线程加快保存速度(单线程调用几十个视频耗时还是蛮久的,讯飞API有限制,推荐开10个线程左右)。 这里给一个官方的调用示例:

# -*- coding: utf-8 -*-
import base64
import hashlib
import hmac
import json
import os
import time
import requests
import urllib

lfasr_host = 'https://raasr.xfyun.cn/v2/api'
# 请求的接口名
api_upload = '/upload'
api_get_result = '/getResult'


class RequestApi(object):
    def __init__(self, appid, secret_key, upload_file_path):
        self.appid = appid
        self.secret_key = secret_key
        self.upload_file_path = upload_file_path
        self.ts = str(int(time.time()))
        self.signa = self.get_signa()

    def get_signa(self):
        appid = self.appid
        secret_key = self.secret_key
        m2 = hashlib.md5()
        m2.update((appid + self.ts).encode('utf-8'))
        md5 = m2.hexdigest()
        md5 = bytes(md5, encoding='utf-8')
        # 以secret_key为key, 上面的md5为msg, 使用hashlib.sha1加密结果为signa
        signa = hmac.new(secret_key.encode('utf-8'), md5, hashlib.sha1).digest()
        signa = base64.b64encode(signa)
        signa = str(signa, 'utf-8')
        return signa

    def upload(self):
        print("上传部分:")
        upload_file_path = self.upload_file_path
        file_len = os.path.getsize(upload_file_path)
        file_name = os.path.basename(upload_file_path)

        param_dict = {}
        param_dict['appId'] = self.appid
        param_dict['signa'] = self.signa
        param_dict['ts'] = self.ts
        param_dict["fileSize"] = file_len
        param_dict["fileName"] = file_name
        param_dict["duration"] = "200"
        print("upload参数:", param_dict)
        data = open(upload_file_path, 'rb').read(file_len)

        response = requests.post(url=lfasr_host + api_upload + "?" + urllib.parse.urlencode(param_dict),
                                 headers={"Content-type": "application/json"}, data=data)
        print("upload_url:", response.request.url)
        result = json.loads(response.text)
        print("upload resp:", result)
        return result

    def get_result(self):
        uploadresp = self.upload()
        orderId = uploadresp['content']['orderId']
        param_dict = {}
        param_dict['appId'] = self.appid
        param_dict['signa'] = self.signa
        param_dict['ts'] = self.ts
        param_dict['orderId'] = orderId
        param_dict['resultType'] = "transfer,predict"
        print("")
        print("查询部分:")
        print("get result参数:", param_dict)
        status = 3
        # 建议使用回调的方式查询结果,查询接口有请求频率限制
        while status == 3:
            response = requests.post(url=lfasr_host + api_get_result + "?" + urllib.parse.urlencode(param_dict),
                                     headers={"Content-type": "application/json"})
            # print("get_result_url:",response.request.url)
            result = json.loads(response.text)
            print(result)
            status = result['content']['orderInfo']['status']
            print("status=", status)
            if status == 4:
                break
            time.sleep(5)
        print("get_result resp:", result)
        return result


# 输入讯飞开放平台的appid,secret_key和待转写的文件路径
if __name__ == '__main__':
    api = RequestApi(appid="46dab912",
                     secret_key="94efcb95a696667fd9b78b1e5add1830",
                     upload_file_path=r"audios/下集预告.mp3")

    res = api.get_result()
    with open("a.txt", "w", encoding="utf-8") as f:
        f.write(str(res))

总结

通过以上几个步骤我们就获取到了所有的科长发言了,接下来我们就可以进一步好好学习这些语录了!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

zzr-rr

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值