小工具(for朗读软件) ,用python获取bilibili字幕,并清洗序号和时间戳

用python获取B站字幕

1、手动方法获取字幕


ubuntu 的浏览器

    1  F12,进入后台资源
    2  网络tab-标签栏
    3  另外的页面打开 io.json


windows 的chrome浏览器
    打开bilibili窗口
    检查
    切换到网络
    刷新页面
    用文件类型排序
    xlr文件中找到 .json 结尾的文件。属性是(磁盘缓存)

2、自动方法获取字幕

先要准备视频号,在弹窗输入

# from    https://gitee.com/KGDKL/BiliCC-Srt/tree/master/Python   
# 使用代理软件时报错,例如连接  翻==墙 软件
import gzip
import requests
import json
import time
import urllib
 

txtCode = 'utf-8'
 
he = {
    "Host": 'api.bilibili.com',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0',
    'Accept': '*/*',
    'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
    'Accept-Encoding': 'gzip,deflate',
    'Connection': 'keep-alive',
    }
 
 
 
def downAll(bv):
    '''
    传入BV号,下载该BV号下的全部字幕
    '''
    videoList = getVideoList(bv)
    p = 1
    for i in videoList:
        cid = i['cid']
        downSolo(cid, bv, p, i['part'])                         # 下载该P视频的字幕,part是单P视频名。
        print ('【任务总进度:%s/%sP】\n'%(p,len(videoList)))
        p += 1
    print ('\n\n*** 任务完成 ***\n')
 
 
def getVideoList(bv):
    '''
    传入BV号,返回该BV号的视频列表
    '''
    url = 'https://api.bilibili.com/x/player/pagelist?bvid=%s' % bv # 创建URL
    response  = requests.get(url,headers=he)                # 获取Json
    videoList = json.loads(response.text)['data']           # Json转换
    print ('请求URL:', url)
    print ('视频目录获取成功!共%sP。\n'%len(videoList))      #汇报
    return videoList
 
 
def downSolo(cid, bv, p, part=''):
    '''
    根据cid,下载单P里的全部语言字幕
    '''
    url = 'https://api.bilibili.com/x/player/v2?bvid=%s&cid=%s'%(bv,cid)
    response = requests.get(url,headers=he)
    data = json.loads(response.text)
 
    subList = data['data']['subtitle']['subtitles']      # 字幕信息列表
 
    if len(subList) == 0:print('【警告】P%s无字幕!' % p)
 
    i = 1
    for d in subList:
        lan = d['lan']                          # 字幕的语言编号(ZH JP EN之类)
        name = bv + ' - P' + str(p) + ':' + rep(part) + ' - ' + lan   # 根据BV号、P数、语言,生成字幕文件名
        subUrl = 'http:' + d['subtitle_url']    # 字幕的URL
 
        # urllib.request.urlretrieve(subUrl,'%s.json' % name)   # 下载json字幕文件
        response = urllib.request.urlopen(subUrl)               # 不下载了,直接获取内容
        if response.info().get('Content-Encoding') == 'gzip':   # 在响应头中获取编码格式
            j = gzip.decompress(response.read())
        else:
            j = response.read()
        jsonToSrt (name, j)
 
        print ('P%s 第%s种语言下载完成,进度:%s/%s'%(p,i,i,len(subList)))    #报告任务进度(以该P视频的字幕语言数算)
 
        i += 1
        time.sleep(0.2)
 
 
def jsonToSrt(fileName,j):
    '''
    传入文件名和json字幕内容,将json输出为Srt字幕文件
    '''
    data = json.loads(j)['body']
    file = open('%s.srt'%fileName,'w',encoding=txtCode)     # 创建srt字幕文件
    i = 1   # Srt字幕的序号计数器
    for d in data:
        f = round(d['from'],3)      # 开始时间 (round(n,3)四舍五入为三位小数)
        t = round(d['to'],3)        # 结束时间
        c = d['content']            # 字幕内容
        ff = time.strftime("%H:%M:%S",time.gmtime(f)) + ',' + miao(f)   # 开始时间,秒数转 时:分:秒 格式,加逗号、毫秒修正为三位
        tt = time.strftime("%H:%M:%S",time.gmtime(t)) + ',' + miao(t)   # 结束时间,处理方式同上
 
        srt = str(i) + '\n' + ff + ' ' + '-->' + ' ' + tt + '\n' + c + '\n\n'     # 格式化为Srt字幕
        file.write(srt)             # 写入文件
        i += 1                      # 计数器+1
 
    file.close()
    print ('%s OK.' % fileName)
 
 
 
li = [
    ['/','、'],
    ['\\','、'],
    ['|','、'],
    ['*','X'],
    [':',':'],
    ['?','?'],
    ['<','《'],
    ['>','》'],
    ['\"','“'],
    ['\"','”'],
]
 
def rep(s=''):
    '''
    根据列表li,去除特殊符号(不能用于文件名的)
    '''
    for i in li:
        s.replace(i[0],i[1])
    return s
 
def miao(m):
    '''
    修正毫秒为三位
    '''
    m = str(m).partition('.')[2]    #取小数部分
    if len(m)==0:m = '000'          #补齐三位小数
    if len(m)==1:m = m + '00'
    if len(m)==2:m = m + '0'
    return m                           #返回标准三位的毫秒数
 
 
#########################################################
import tkinter          #载入模块
import threading
 
# BV1m3411P7TG gzip
# BV13f4y1G7sA 无压缩
# BV18a4y1H73s 很多P
 
 
def xc():
    thread1 = threading.Thread(target=zzz)   # 定义线程,运行抓取程序
    thread1.start()                          # 让线程开始工作
def zzz():
	downAll(avID.get())
 
 
# 单选按钮回调函数,就是当单选按钮被点击会执行该函数
def radCall():
    radSel = radVar.get()
    if radSel == 1:
        txtCode = 'utf-8'
        print ('编码输出变更为:UTF-8')
    elif radSel == 2:
        txtCode = 'utf-16'
        print ('编码输出变更为:UTF-16')
 
 
### Tk GUI窗口 ###
windowsInput = tkinter.Tk()
windowsInput.title('BLIBILI CC字幕下载器 V4.1')
windowsInput.geometry('400x220')
 
group1 = tkinter.Frame(windowsInput)      #第一节
group2 = tkinter.Frame(windowsInput)      #第二节
group3 = tkinter.Frame(windowsInput)      #第三节
 
tag = tkinter.Label(windowsInput,text='BLIBILI CC字幕下载器 V4.1',width=20,height=2,font=("微软雅黑",22))   #标签
tag.pack()
 
group1.pack()  #显示一二三节
group2.pack()
group3.pack()
 
tkinter.Label(group1,text='目标BV号:',width=8,height=1,font=("微软雅黑",15)).pack(side='left')      #标签
avID = tkinter.Entry(group1)                                                                      #AV号输入框
avID.pack(side='right')
 
radVar = tkinter.IntVar()    # 通过tk.IntVar() 获取单选按钮value参数对应的值
rad1 = tkinter.Radiobutton(group2,text='UTF-8     ',variable=radVar,value=1,command=radCall,font=("微软雅黑",15))        #单选框
rad1.pack(side='left')
 
rad2 = tkinter.Radiobutton(group2,text='UTF-16',variable=radVar,value=2,command=radCall,font=("微软雅黑",15))
rad2.pack(side='right')
 
button1 = tkinter.Button(group3,text='抓取',command=xc,width=15,height=1,font=("微软雅黑",18))        #按钮
button1.pack(side='right')
 
print ('### 编码默认输出:UTF-8。\n### 如果字幕乱码,可尝试选择UTF-16编码。\n')
 
windowsInput.mainloop()

2.1  获取字幕后,清洗字幕,去除序号和时间戳。

下面的程序一次性将文件夹中的字幕.txt文件全部清洗,需要对下面程序中的地址做修改:

filenames=os.listdir(r'/home/x220/depthai-python/字幕到音频/trans')   ##存储原始字幕文件路径,绝对路径

inputfile = open('./trans/'+filename ,'r')  ##存储原始字幕文件路径,相对路径,与下面的程序保存地点有关

# for ubuntu system

import os            #  文件夹、文件
import re            #  通配符搜索
   
    
    
    
filenames=os.listdir(r'/home/x220/depthai-python/字幕到音频/trans')
print(filenames)


for filename in filenames:

    # 读取
    inputfile = open('./trans/'+filename ,'r')
    
    datalist=inputfile.readlines()
    
    print(inputfile)   #   打印 <_io.TextIOWrapper name='test.txt' mode='r' encoding='UTF-8'>
    a = []

    # 将数据进行格式化处理 
    for data in datalist:
            if  re.search(r'\A\d*', data ).group() :        # 如果是数字跳过此次循环
                continue

            a.append(data )


        
    testoutputfile = open(filename+'OutPut.txt' ,"w")
    testoutputfile.writelines(a)  
    testoutputfile.close()   
        
    inputfile.close()        
        
'''
\d 的含义是 [0-9]
\D 的含义是 [^0-9]
\w 任何一个字母数字字符(大小写均可)或下划线,等价于 [A-Za-z0-9_]
\W 表示[^A-Za-z0-9_]
+ 表示匹配一个或多个字符(至少一个,不匹配零个字符的情况)
邮箱中是允许出现下划线和 . 的
* 表示含有零个或者多个指定的字符
? 表示匹配零个或者一个字符

    
\A	只在字符串开始进行匹配
\Z	只在字符串结尾进行匹配
\b	匹配位于开始或结尾的空字符串
\B	匹配不位于开始或结尾的空字符串
\d	相当于[0-9]
\D	相当于[^0-9]
\s	匹配任意空白字符:[\t\n\r\r\v]
\S	匹配任意非空白字符:[^\t\n\r\r\v]
\w	匹配任意数字和字母:[a-zA-Z0-9]
\W	匹配任意非数字和字母:[^a-zA-Z0-9]
'''

# for windows system ,jupyter lab

import os            #  文件夹、文件
import re            #  通配符搜索

  
    
filenames=os.listdir(r'C:\Users\Administrator.ZX-202202281837\temp\trans')
print(filenames)
 

for filename in filenames:
 
    # 读取
    inputfile = open('C:\\Users\\Administrator.ZX-202202281837\\temp\\trans\\'+filename ,'r',  encoding='utf-8-sig')
                    # 
    
                    # debug <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<   , UnicodeEncodeError: 'gbk' codec can't encode character '\ufeff' in position 0: illegal multibyte sequence
                     # debug <<<<<<<<<<<<<<< encoding='utf-8-sig' 可以, encoding='utf-8-sig' 
        
                     #  filename 无论是 srt. 还是txt 都行
    
                     # debug <<<<<<<<<<<<<<<<<<<<<<<<<<<<       SyntaxError: EOL while scanning string literal
                     
                     # 为何 字符串不能 以 \ (反斜杠) 结束    https://blog.csdn.net/u012065954/article/details/126641698
    
    datalist=inputfile.readlines()
    
    print(inputfile)   #   打印 <_io.TextIOWrapper name='test.txt' mode='r' encoding='UTF-8'>
    a = []
 
    # 将数据进行格式化处理 
    for data in datalist:
            if  re.search(r'\A\d*', data ).group() :        # 如果是数字跳过此次循环
                continue
 
            a.append(data )
 
        
    testoutputfile = open(filename+'OutPut.txt' ,"w")
    testoutputfile.writelines(  a  )  
    testoutputfile.close()   
        
    inputfile.close()        

你可能感兴趣的:(工具软件,python)