用python获取B站字幕
ubuntu 的浏览器
1 F12,进入后台资源
2 网络tab-标签栏
3 另外的页面打开 io.json
windows 的chrome浏览器
打开bilibili窗口
检查
切换到网络
刷新页面
用文件类型排序
xlr文件中找到 .json 结尾的文件。属性是(磁盘缓存)
先要准备视频号,在弹窗输入
# 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()
下面的程序一次性将文件夹中的字幕.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()