牙叔教程 简单易懂
我想学习某个人的文案, 怎么把它的文案全下载下来?
- 批量下载视频和音频
- 批量音频转文字
下载视频和音频
我在github找到的是这个仓库
GitHub - Johnserf-Seed/TikTokDownload: 抖音去水印批量下载用户主页作品、喜欢、图文、音频
经过实际测试, 可以使用, 只是失败的频率略高.
获取用户信息的时候, 尝试了5次才正确获取到用户信息,
只有获取到用户信息, 才能下载到视频;
虽然失败的概率有点高, 但是也仅是要多按几下 ↑ 和 回车键, 也不费啥事.
如果, 填写了cookie, 那么成功率大大提高, 不懂的话就看仓库的 issue.
这是下载好的视频和音频, 可以看到mp4和mp3的后缀名,
音频是直接下载下来的, 不是后期提取的.
文件 conf.ini 默认是不下载音频的, 所以要改一下.
music后面默认是no, 改成yes
[music] # 视频原声保存(yes|no) music = yes
其他的就照着README.md做就可以了
语音转文字
一共三种方案
- 某讯
- 微软
- 有道
某讯
我看了一下某讯的价格, 70块30个小时,
微软
微软也有语音转文字的服务, 就是要绑卡, 绑卡的话, 某宝是几十块左右;
网易
网易, 他是2块钱一个小时, 这个就很人性化,
某讯开始就是30个小时, 我又用不了那么多, 至少我现在用不了.
批量自动化的时候, 你才需要买它, 你单独转的话, 可以直接使用
网易见外 网易见外工作台
网易见外不用花一分钱, 但是依然很好用
那么今天给大家试试两种方案
- 微软
- 网易 - 长语音转写服务
微软
如果你没有卡, 可以去某宝搞;
如果你不会创建微软的服务, 可以看这个教程
文本转语音-微软Azure-一步一步教你从注册到使用
文本转语音-微软Azure-一步一步教你从注册到使用
我们要把音频转文字, 所以选择第二个, 脱机字幕
他的文档有代码, 直接复制黏贴就可以使用了
代码在此
语音转文本快速入门 - 语音服务 - Azure Cognitive Services | Microsoft Learn
下面是我的代码例子
语音转文字, 分两步
- mp3转wav
- wav转文字
// 此示例支持最多 30 秒的音频。 const fs = require("fs"); const sdk = require("microsoft-cognitiveservices-speech-sdk"); const { exec } = require("child_process"); const { secretKey: YourSubscriptionKey, region: YourServiceRegion, mp3FilePath } = require("./config.js"); let wavFilePath = mp3FilePath.replace(".mp3", ".wav"); let mp3ToWavCmd = `ffmpeg -i "${mp3FilePath}" "${wavFilePath}"`; const speechConfig = sdk.SpeechConfig.fromSubscription(YourSubscriptionKey, YourServiceRegion); speechConfig.speechRecognitionLanguage = "zh-CN"; async function recognizeSpeechFromFile() { let speechRecognizer; try { // Convert MP3 to WAV await new Promise((resolve, reject) => { exec(mp3ToWavCmd, (error) => { if (error) { console.error(`Error converting MP3 to WAV: ${error.message}`); reject(error); } else { console.log("MP3 file converted to WAV successfully."); resolve(); } }); }); const audioConfig = sdk.AudioConfig.fromWavFileInput(fs.readFileSync(wavFilePath)); speechRecognizer = new sdk.SpeechRecognizer(speechConfig, audioConfig); await new Promise((resolve, reject) => { speechRecognizer.recognizeOnceAsync((result) => { switch (result.reason) { case sdk.ResultReason.RecognizedSpeech: console.log(`RECOGNIZED: Text=${result.text}`); resolve(result.text); break; case sdk.ResultReason.NoMatch: console.log("NOMATCH: Speech could not be recognized."); reject("NOMATCH"); break; case sdk.ResultReason.Canceled: { const cancellation = sdk.CancellationDetails.fromResult(result); console.log(`CANCELED: Reason=${cancellation.reason}`); if (cancellation.reason === sdk.CancellationReason.Error) { console.log(`CANCELED: ErrorCode=${cancellation.ErrorCode}`); console.log(`CANCELED: ErrorDetails=${cancellation.errorDetails}`); console.log("CANCELED: Did you set the speech resource key and region values?"); } reject("CANCELED"); break; } } }); }); } catch (error) { console.error("Error during recognition:", error); } finally { if (speechRecognizer) { speechRecognizer.close(); } } } recognizeSpeechFromFile();
不过, 还是应该看看文档再动手,
这是微软文字转语音的文档
使用语音转文本添加字幕 - 语音服务 - Azure Cognitive Services | Microsoft Learn
上面的代码只支持30s, 如果改成这种订阅式的代码, 就支持更长时间了
我们将订阅从 SpeechRecognizer 发送的事件: recognizing:事件信号,包含中间识别结果。 recognized:包含最终识别结果的事件信号,指示成功的识别尝试。 sessionStopped:事件信号,指示识别会话的结束(操作)。 canceled:事件信号,包含已取消的识别结果。 这些结果指示因直接取消请求而取消的识别尝试。 或者,它们指示传输或协议失败。
speechRecognizer.recognizing = (s, e) => { console.log(`RECOGNIZING: Text=${e.result.text}`); }; speechRecognizer.recognized = (s, e) => { if (e.result.reason == sdk.ResultReason.RecognizedSpeech) { console.log(`RECOGNIZED: Text=${e.result.text}`); } else if (e.result.reason == sdk.ResultReason.NoMatch) { console.log("NOMATCH: Speech could not be recognized."); } }; speechRecognizer.canceled = (s, e) => { console.log(`CANCELED: Reason=${e.reason}`); if (e.reason == sdk.CancellationReason.Error) { console.log(`"CANCELED: ErrorCode=${e.errorCode}`); console.log(`"CANCELED: ErrorDetails=${e.errorDetails}`); console.log("CANCELED: Did you set the speech resource key and region values?"); } speechRecognizer.stopContinuousRecognitionAsync(); }; speechRecognizer.sessionStopped = (s, e) => { console.log("\n Session stopped event."); speechRecognizer.stopContinuousRecognitionAsync(); };
下载的数据
mp4 + mp3 + txt
语音转的文字
这是一个5分钟的电影解说, 1412个字,
如果是小说, 估计字数得翻倍, 这个是电影, 有一些时间是放的电影片段, 没有台词.
ffmpge
由于微软默认支持wav, 所以我们需要转换语音格式, 把mp3转成wav,
因此, 需要在电脑上安装 FFMPEG, 不会装的可以百度 Windows 10系统下安装FFmpeg教程详解
ffmpeg使用注意事项
- 如果文件存在, 那么命令会卡住
网易
长语音转写文档
产品文档-语音识别ASR服务
创建应用时, 选择 长语音转写
网易文档中的错误
这个sliceId是 大写的i (爱),
但是他这个文档里是小写的l (矮楼)
文档中的响应结果, 是写文档的人复制黏贴的.
比如, 这几张响应结果, msg都是sucess
实际上, msg的值都是 null
文件上传的时候, 这里是字节数组, 而不是text
你就说这样写文档快不快吧, 类型全是text
网易长语音转文本的代码
const fs = require("fs"); const axios = require("axios"); const path = require("path"); const crypto = require("crypto"); const FormData = require("form-data"); const util = require("util"); const { wangyi } = require("./config.js"); const stat = util.promisify(fs.stat); async function getFileSize(filePath) { try { const stats = await stat(filePath); const fileSizeInBytes = stats.size; console.log(`文件大小: ${fileSizeInBytes} 字节`); return fileSizeInBytes; } catch (err) { console.error("发生错误:", err); } } async function wangYiRcognizeSpeechFromFile(audioFilePath) { let fileName = path.basename(audioFilePath); // 请在这里设置您的应用ID和应用密钥 const appKey = wangyi.appKey; const appSecret = wangyi.secretKey; let fileSize = await getFileSize(audioFilePath); let salt = uuidv4(); let curtime = Math.floor(Date.now() / 1000); let sign = crypto .createHash("sha256") .update(appKey + salt + curtime + appSecret) .digest("hex"); let formData = new FormData(); formData.append("salt", salt); formData.append("type", 1); formData.append("appKey", appKey); formData.append("sliceNum", "1"); formData.append("name", fileName); formData.append("fileSize", fileSize); formData.append("curtime", curtime); formData.append("langType", "zh-CHS"); formData.append("sign", sign); formData.append("signType", "v4"); formData.append("format", "mp3"); formData.append("noitn", 1); const prepareResponse = await axios.post("http://openapi.youdao.com/api/audio/prepare", formData, { headers: formData.getHeaders() }); if (prepareResponse.data.errorCode !== "0") { throw new Error(`Prepare failed: ${prepareResponse.data.msg}`); } console.log("准备上传"); console.log(prepareResponse.data); const taskid = prepareResponse.data.result; formData = new FormData(); formData.append("q", taskid); formData.append("appKey", appKey); salt = uuidv4(); formData.append("salt", salt); formData.append("curtime", curtime); sign = crypto .createHash("sha256") .update(appKey + salt + curtime + appSecret) .digest("hex"); formData.append("sign", sign); formData.append("signType", "v4"); formData.append("sliceId", "1"); // 判断文件是否存在 if (!fs.existsSync(audioFilePath)) { throw new Error(`File not found: ${audioFilePath}`); } // 打印文件大小 console.log(`文件大小: ${fs.statSync(audioFilePath).size} 字节`); formData.append("file", fs.readFileSync(audioFilePath), { contentType: "audio/mp3", filename: fileName }); formData.append("type", "1"); const uploadResponse = await axios.post("http://openapi.youdao.com/api/audio/upload", formData, { headers: formData.getHeaders() }); if (uploadResponse.data.errorCode !== "0") { throw new Error(`Upload failed: ${uploadResponse.data.msg}`); } console.log("上传文件"); console.log(uploadResponse.data); /* -------------------------------------------------------------------------- */ formData = new FormData(); formData.append("q", taskid); formData.append("appKey", appKey); salt = uuidv4(); formData.append("salt", salt); curtime = Math.floor(Date.now() / 1000); formData.append("curtime", curtime); sign = crypto .createHash("sha256") .update(appKey + salt + curtime + appSecret) .digest("hex"); formData.append("sign", sign); formData.append("signType", "v4"); const mergeResponse = await axios.post("http://openapi.youdao.com/api/audio/merge", formData, { headers: formData.getHeaders() }); if (mergeResponse.data.errorCode !== "0") { throw new Error(`Merge failed: ${mergeResponse.data.msg}`); } console.log("合并文件"); console.log(mergeResponse.data); // process.exit(0); let progressResponse; do { await new Promise((resolve) => setTimeout(resolve, 60 * 1000)); formData = new FormData(); formData.append("q", taskid); formData.append("appKey", appKey); salt = uuidv4(); formData.append("salt", salt); curtime = Math.floor(Date.now() / 1000); formData.append("curtime", curtime); sign = crypto .createHash("sha256") .update(appKey + salt + curtime + appSecret) .digest("hex"); formData.append("sign", sign); formData.append("signType", "v4"); progressResponse = await axios.post("http://openapi.youdao.com/api/audio/get_progress", formData, { headers: formData.getHeaders() }); console.log("获取进度"); console.log(progressResponse.data); } while (progressResponse.data.result[0].status !== "9"); formData = new FormData(); formData.append("q", taskid); formData.append("appKey", appKey); salt = uuidv4(); formData.append("salt", salt); curtime = Math.floor(Date.now() / 1000); formData.append("curtime", curtime); sign = crypto .createHash("sha256") .update(appKey + salt + curtime + appSecret) .digest("hex"); formData.append("sign", sign); formData.append("signType", "v4"); const resultResponse = await axios.post("http://openapi.youdao.com/api/audio/get_result", formData, { headers: formData.getHeaders() }); if (resultResponse.data.errorCode !== "0") { throw new Error(`Get result failed: ${resultResponse.data.msg}`); } console.log("获取结果"); console.log(resultResponse.data); const text = resultResponse.data.result.map((item) => item.sentence).join("\n"); fs.writeFileSync(fileName, text); } // 生成 UUID v4 function uuidv4() { return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) { var r = (Math.random() * 16) | 0, v = c == "x" ? r : (r & 0x3) | 0x8; return v.toString(16); }); }
网易与微软对比
微软 | 网易 | |
获取结果需要轮询 | 不需要 | 需要 |
准确度 | 略高 | 略低 |
接口方便程度 | 一个订阅模式, 每秒钟都会给你返回信息, 直到任务完成, 感觉比网易方便一些 | 四个步骤: 准备, 上传, 获取状态, 获取结果 |
需要mp3转wav | 需要 | 不需要 |
建议用哪个
都可以, 都差不多
写代码利器
本文的代码大部分是 ChatGPT4 写的,
你如果不想动手, 可以像我一样, 直接复制黏贴网易有道云的文档, 然后叫chatgpt给你代码
就像这样
我用的 ChatGPT4, 是这个
ChatGPT联网版, Stable Diffusion画图, 这个星球全都有, 低调使用, 别外传
声明
本文仅供学习研究使用, 禁止用于其他用途