赞
踩
用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()
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。