1.参考 #
本节为你整理了项目相关的官方文档和API资源。新手遇到不懂的库、API或报错时,可以直接查阅这些链接,快速找到权威答案。
1.1 文档 #
- python语法
- DrissionPage
- python-dotenv
- pypinyin
- requests
- ffmpeg
- subprocess
- re
- uuid
- time
- json
- opencv-python
- numpy
- openai
- watermark
1.2 资源 #
这里是你需要注册和获取密钥的平台入口。建议提前注册好账号,获取好API密钥,后续配置会用到。
2.配置VSCode #
本节介绍如何用 VSCode 配置开发环境,包括虚拟环境、代码格式化和编码设置。新手照做可以避免很多环境和编码问题。
2.1. 创建虚拟环境 #
# 创建虚拟环境
python -m venv .venv
# 激活虚拟环境(Windows)
.venv\Scripts\activate.bat
# 激活虚拟环境(Linux/macOS)
source .venv/Scripts/activate2.2 格式化python代码插件 #
按下Ctrl+Shift+P 选择 Preferences:OpenUserSettings(JSON)
添加
{
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter",
"editor.formatOnSave": true
}
}2.3. 格式化python代码插件 #
VS Code 的 "Run Code"(由 Code Runner 扩展提供)可能未正确配置编码。
- 打开 VS Code 设置(
Ctrl + ,),搜索Code-runner: Executor Map。 - 点击
Edit in settings.json, 在settings.json中修改或添加:如果想在Run Code时使用当前目录的虚拟环境可以配置"code-runner.executorMap": { "python": "set PYTHONIOENCODING=utf8 && python -u $fullFileName" }(Windows 用户用"code-runner.executorMap": { "python": "set PYTHONIOENCODING=utf8 && $workspaceRoot/.venv/Scripts/python.exe -u $fullFileName", }set,Mac/Linux 用export)
3.安装类库 #
本节教你如何一键安装项目所需的所有依赖库。新手只需复制命令到终端执行即可。
pip install DrissionPage openai python-dotenv pypinyin cos_python_sdk_v5 opencv-python
4.编写入口文件 #
本节讲解如何编写和理解 main.py 入口文件及常用的日志模块。新手可以学会如何让项目跑起来。
4.1 main.py #
# 从common模块导入get_logger函数
from common import get_logger
# 创建当前模块的日志记录器实例
logger = get_logger(__name__)
# 定义主函数
def main():
# 记录主流程开始的日志信息
logger.info("主流程开始")
# 判断是否作为主程序运行
if __name__ == "__main__":
# 调用主函数
main()4.2 common.py #
# 导入Python标准库中的日志模块
import logging
# 配置日志系统的基本设置:设置日志级别为INFO,定义日志格式包含时间戳、日志级别和消息内容
logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s')
# 定义获取日志记录器的函数,参数name用于指定日志记录器的名称
def get_logger(name):
# 根据传入的名称创建或获取日志记录器实例
logger = logging.getLogger(name)
# 返回创建的日志记录器实例
return logger4.3 .env #
# 腾讯云 COS 配置
# 腾讯云访问密钥 ID,用于身份验证
TENCENT_SECRET_ID=AKIDYzEI9nDRgrxufDi5FB0ueLuJZo7ITyQm
# 腾讯云访问密钥 Key,用于身份验证
TENCENT_SECRET_KEY=HXmu11voYAdv483nS0OacVAg6Sj3GLFz
# 腾讯云 COS 存储桶所在地区
TENCENT_REGION=ap-beijing
# 腾讯云 COS 存储桶名称
TENCENT_BUCKET=xiaohongshu-1258145019
# 火山引擎语音识别配置
# 火山引擎应用 ID,用于语音识别服务
VOLC_APPID=8709644943
# 火山引擎访问令牌,用于 API 调用认证
VOLC_TOKEN=6X54d8pz6HcUijsC3BKKcuYlxxMqX4qy
# OpenAI/火山大模型 API 配置
# OpenAI API 密钥,用于调用大模型服务
OPENAI_API_KEY=d52e49a1-36ea-44bb-bc6e-65ce789a72f6
# OpenAI API 基础 URL 地址
OPENAI_BASE_URL=https://ark.cn-beijing.volces.com/api/v3
# 视频存放目录
DOUYIN_SAVE_DIR=douyin_videos
# 图片保存目录路径
IMAGE_SAVE_DIR=images
# 默认生成图片数量
IMAGE_NUM_DEFAULT=35.打开网页 #
本节介绍如何用自动化浏览器打开网页,为后续自动化操作(如扫码登录、自动发文)做准备。
5.1. config.py #
config.py
# 导入操作系统相关的模块,用于处理文件和目录等操作
import os
# 从dotenv库中导入load_dotenv函数,用于加载.env文件中的环境变量
from dotenv import load_dotenv
# 加载.env文件中的所有环境变量到系统环境变量中
load_dotenv()
# 常量配置区
# 获取环境变量"DOUYIN_SAVE_DIR"的值,如果没有设置则默认使用"douyin_videos"
DOUYIN_SAVE_DIR = os.environ.get("DOUYIN_SAVE_DIR", "douyin_videos")
5.2. douyin_utils.py #
douyin_utils.py
# 导入os模块,用于文件和目录操作
import os
# 从common模块导入get_logger函数和browser对象
from common import get_logger, browser
# 从config模块导入抖音视频保存目录常量
from config import DOUYIN_SAVE_DIR
# 创建当前模块的日志记录器实例
logger = get_logger(__name__)
# 定义爬取抖音热门视频的函数,参数为搜索关键词
def crawl_douyin_videos(keyword):
# 记录日志,表示开始爬取抖音热门视频
logger.info("开始爬取抖音热门视频...")
# 构造抖音搜索页面的URL,使用传入的关键词
url = f"https://www.douyin.com/search/{keyword}?type=video"
# 如果保存视频的目录不存在,则创建该目录
if not os.path.exists(DOUYIN_SAVE_DIR):
os.makedirs(DOUYIN_SAVE_DIR)
# 使用browser对象打开新标签页,访问构造好的抖音搜索页面
browser.new_tab(url)5.3. common.py #
common.py
# 导入Python标准库中的日志模块
import logging
# 从DrissionPage库中导入Chromium和ChromiumOptions类
+from DrissionPage import Chromium, ChromiumOptions
# 配置日志系统的基本设置
# 设置日志级别为INFO,日志格式为"时间戳 [日志级别] 日志内容"
logging.basicConfig(
level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s"
)
# 定义获取日志记录器的函数,参数name用于指定日志记录器的名称
def get_logger(name):
# 根据传入的名称创建或获取日志记录器实例
logger = logging.getLogger(name)
# 返回创建的日志记录器实例
return logger
# 创建Chromium浏览器的配置对象
+co = ChromiumOptions()
# 使用配置对象创建Chromium浏览器实例
+browser = Chromium(co)5.5. main.py #
main.py
# 从common模块导入get_logger函数
from common import get_logger
# 从douyin_utils模块导入crawl_douyin_videos函数
+from douyin_utils import crawl_douyin_videos
# 创建当前模块的日志记录器实例
logger = get_logger(__name__)
+
# 定义主函数
def main():
# 记录主流程开始的日志信息
logger.info("主流程开始")
+ try:
# 调用爬取抖音热门视频的函数,参数为"脆桃"
+ crawl_douyin_videos("脆桃")
+ except Exception as e:
# 如果主流程执行出错,记录错误日志
+ logger.error(f"主流程执行出错: {e}")
+
# 判断当前脚本是否作为主程序运行
if __name__ == "__main__":
# 调用主函数
main()6.判断是否登录 #
本节讲解如何自动检测抖音网页是否已登录,确保后续操作不会因未登录而失败。
6.1. douyin_utils.py #
douyin_utils.py
# 导入os模块,用于文件和目录操作
import os
# 从common模块导入get_logger函数和browser对象
from common import get_logger, browser
# 从config模块导入抖音视频保存目录常量
from config import DOUYIN_SAVE_DIR
# 创建当前模块的日志记录器实例
logger = get_logger(__name__)
+def is_logged_in_js(tab):
+ js = """if (document.querySelector('span.semi-avatar img')) {return true;}return false;"""
+ try:
+ return tab.run_js(js)
+ except Exception as e:
+ logger.error(f"检查登录状态时异常: {e}")
+ return False
# 定义爬取抖音热门视频的函数,参数为搜索关键词
def crawl_douyin_videos(keyword):
# 记录日志,表示开始爬取抖音热门视频
logger.info("开始爬取抖音热门视频...")
# 构造抖音搜索页面的URL,使用传入的关键词
url = f"https://www.douyin.com/search/{keyword}?type=video"
# 如果保存视频的目录不存在,则创建该目录
if not os.path.exists(DOUYIN_SAVE_DIR):
os.makedirs(DOUYIN_SAVE_DIR)
# 使用browser对象打开新标签页,访问构造好的抖音搜索页面
+ tab = browser.new_tab(url)
+ logger.info("请扫码登录抖音账号...")
+ while True:
+ try:
+ if is_logged_in_js(tab):
+ break
+ logger.info("等待登录中,请扫码登录抖音账号...")
+ tab.wait(2)
+ except Exception as e:
+ logger.error(f"等待登录时异常: {e}")
+ tab.wait(2)
+ logger.info("检测到已登录,继续执行...")
7.下载视频 #
本节介绍如何自动下载抖音视频,并用安全的文件名保存到本地,防止乱码和非法字符。
7.1. common.py #
common.py
# 导入Python标准库中的日志模块
import logging
# 导入正则表达式模块,用于处理字符串
+import re
# 从pypinyin库中导入lazy_pinyin函数,用于将汉字转为拼音
+from pypinyin import lazy_pinyin
# 导入requests库,用于网络请求
+import requests
# 从DrissionPage库中导入Chromium和ChromiumOptions类,用于浏览器自动化
from DrissionPage import Chromium, ChromiumOptions
# 配置日志系统的基本设置
# 设置日志级别为INFO,日志格式为"时间戳 [日志级别] 日志内容"
logging.basicConfig(
level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s"
)
# 定义获取日志记录器的函数,参数name用于指定日志记录器的名称
def get_logger(name):
# 根据传入的名称创建或获取日志记录器实例
logger = logging.getLogger(name)
# 返回创建的日志记录器实例
return logger
# 创建Chromium浏览器的配置对象
co = ChromiumOptions()
# 使用配置对象创建Chromium浏览器实例
browser = Chromium(co)
# 定义安全文件名生成函数
+def safe_filename(idx, title, ext):
# 汉字转拼音
+ pinyin_title = "".join(lazy_pinyin(title))
# 替换所有 Windows 不支持的特殊字符为下划线
+ name = re.sub(r'[\\/:*?"<>|]', "_", f"{idx}_{pinyin_title}")
# 只保留中英文、数字和下划线
+ name = re.sub(r"[^\w]", "_", name)
# 限制文件名长度,最多50个字符
+ name = name[:50]
# 返回最终的文件名,包含扩展名
+ return f"{name}{ext}"
# 创建一个requests的会话对象,用于复用连接
+session = requests.Session()
7.2. config.py #
config.py
# 导入操作系统相关的模块,用于处理文件和目录等操作
import os
# 从dotenv库中导入load_dotenv函数,用于加载.env文件中的环境变量
from dotenv import load_dotenv
# 加载.env文件中的所有环境变量到系统环境变量中
load_dotenv()
# ================== 常量配置区 ==================
# 获取环境变量"DOUYIN_SAVE_DIR"的值,如果没有设置则默认使用"douyin_videos"
DOUYIN_SAVE_DIR = os.environ.get("DOUYIN_SAVE_DIR", "douyin_videos")
# 设置用于请求抖音网页的User-Agent字符串,模拟浏览器访问
+DOUYIN_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36"
7.3. douyin_utils.py #
douyin_utils.py
# 导入os模块,用于文件和目录操作
import os
# 从common模块导入get_logger函数、browser对象、safe_filename函数和session对象
+from common import get_logger, browser, safe_filename, session
# 从config模块导入抖音视频保存目录常量和User-Agent字符串
+from config import DOUYIN_SAVE_DIR, DOUYIN_USER_AGENT
# 创建当前模块的日志记录器实例
logger = get_logger(__name__)
# 定义检查是否已登录的函数,参数为tab对象
def is_logged_in_js(tab):
# JavaScript代码:判断页面上是否存在头像img元素
js = """if (document.querySelector('span.semi-avatar img')) {return true;}return false;"""
try:
# 在tab页面中执行js代码,返回登录状态
return tab.run_js(js)
except Exception as e:
# 如果执行js出错,记录错误日志
logger.error(f"检查登录状态时异常: {e}")
# 返回未登录
return False
# 定义爬取抖音热门视频的函数,参数为搜索关键词
def crawl_douyin_videos(keyword):
# 记录日志,表示开始爬取抖音热门视频
logger.info("开始爬取抖音热门视频...")
# 构造抖音搜索页面的URL,使用传入的关键词
url = f"https://www.douyin.com/search/{keyword}?type=video"
# 如果保存视频的目录不存在,则创建该目录
if not os.path.exists(DOUYIN_SAVE_DIR):
os.makedirs(DOUYIN_SAVE_DIR)
# 使用browser对象打开新标签页,访问构造好的抖音搜索页面
tab = browser.new_tab(url)
# 提示用户扫码登录抖音账号
logger.info("请扫码登录抖音账号...")
# 循环等待用户扫码登录
while True:
try:
# 检查是否已登录
if is_logged_in_js(tab):
# 已登录则跳出循环
break
# 未登录则提示继续等待
logger.info("等待登录中,请扫码登录抖音账号...")
# 等待2秒
tab.wait(2)
except Exception as e:
# 捕获异常并记录日志
logger.error(f"等待登录时异常: {e}")
# 等待2秒后重试
tab.wait(2)
# 登录成功后记录日志
logger.info("检测到已登录,继续执行...")
# 获取所有视频卡片元素
+ video_cards = tab.eles(".search-result-card")
# 记录找到的视频卡片数量
+ logger.info(f"共找到{len(video_cards)}个视频卡片")
# 只处理前1个视频卡片
+ video_cards = video_cards[:1]
# 记录实际处理的视频卡片数量
+ logger.info(f"先处理{len(video_cards)}个视频卡片")
# 启动监听,捕获视频真实地址
+ tab.listen.start("/video/tos")
# 初始化视频文件路径列表
+ video_files = []
# 遍历每个视频卡片,idx为序号,card为卡片对象
+ for idx, card in enumerate(video_cards, 1):
+ try:
# 鼠标悬停到视频卡片上
+ card.hover()
# 获取视频标题
+ title = card.ele(".VDYK8Xd7").text
# 生成安全的文件名
+ filename = safe_filename(idx, title, ".mp4")
# 记录视频文件名
+ logger.info(f"视频文件名: {filename}")
# 等待监听获取真实视频地址
+ real_video_url = tab.listen.wait().url
# 记录视频真实地址
+ logger.info(f"视频地址: {real_video_url}")
# 如果获取到真实视频地址
+ if real_video_url:
# 发送GET请求下载视频数据
+ video_data = session.get(
+ real_video_url,
+ headers={
+ "Referer": "https://www.douyin.com/",
+ "User-Agent": DOUYIN_USER_AGENT,
+ },
+ timeout=10,
+ ).content
# 拼接视频文件保存路径
+ file_path = os.path.join(DOUYIN_SAVE_DIR, filename)
# 记录保存路径
+ logger.info(f"保存到: {file_path}")
# 以二进制写入方式保存视频文件
+ with open(file_path, "wb") as f:
+ f.write(video_data)
# 记录保存成功
+ logger.info(f"已保存到: {file_path}")
# 将文件路径添加到列表
+ video_files.append(file_path)
+ else:
# 未获取到视频地址,记录警告
+ logger.warning("未找到视频地址,跳过。")
+ except Exception as e:
# 捕获下载异常并记录日志
+ logger.error(f"下载失败: {e}")
# 跳过当前循环,继续下一个
+ continue8.视频转音频 #
本节讲解如何用 ffmpeg 自动提取视频中的音频,生成 mp3 文件,为后续语音识别做准备。
8.1. douyin_utils.py #
douyin_utils.py
# 导入os模块,用于文件和目录操作
import os
# 导入subprocess模块,用于调用外部命令行程序
+import subprocess
# 从common模块导入get_logger函数、browser对象、safe_filename函数和session对象
from common import get_logger, browser, safe_filename, session
# 从config模块导入抖音视频保存目录常量和User-Agent字符串
from config import DOUYIN_SAVE_DIR, DOUYIN_USER_AGENT
# 创建当前模块的日志记录器实例
logger = get_logger(__name__)
# 定义检查是否已登录的函数,参数为tab对象
def is_logged_in_js(tab):
# JavaScript代码:判断页面上是否存在头像img元素
js = """if (document.querySelector('span.semi-avatar img')) {return true;}return false;"""
try:
# 在tab页面中执行js代码,返回登录状态
return tab.run_js(js)
except Exception as e:
# 如果执行js出错,记录错误日志
logger.error(f"检查登录状态时异常: {e}")
# 返回未登录
return False
# 定义爬取抖音热门视频的函数,参数为搜索关键词
def crawl_douyin_videos(keyword):
# 记录日志,表示开始爬取抖音热门视频
logger.info("开始爬取抖音热门视频...")
# 构造抖音搜索页面的URL,使用传入的关键词
url = f"https://www.douyin.com/search/{keyword}?type=video"
# 如果保存视频的目录不存在,则创建该目录
if not os.path.exists(DOUYIN_SAVE_DIR):
os.makedirs(DOUYIN_SAVE_DIR)
# 使用browser对象打开新标签页,访问构造好的抖音搜索页面
tab = browser.new_tab(url)
# 提示用户扫码登录抖音账号
logger.info("请扫码登录抖音账号...")
# 循环等待用户扫码登录
while True:
try:
# 检查是否已登录
if is_logged_in_js(tab):
# 已登录则跳出循环
break
# 未登录则提示继续等待
logger.info("等待登录中,请扫码登录抖音账号...")
# 等待2秒
tab.wait(2)
except Exception as e:
# 捕获异常并记录日志
logger.error(f"等待登录时异常: {e}")
# 等待2秒后重试
tab.wait(2)
# 登录成功后记录日志
logger.info("检测到已登录,继续执行...")
# 获取所有视频卡片元素
video_cards = tab.eles(".search-result-card")
# 记录找到的视频卡片数量
logger.info(f"共找到{len(video_cards)}个视频卡片")
# 只处理前1个视频卡片
video_cards = video_cards[:1]
# 记录实际处理的视频卡片数量
logger.info(f"先处理{len(video_cards)}个视频卡片")
# 启动监听,捕获视频真实地址
tab.listen.start("/video/tos")
# 初始化视频文件路径列表
video_files = []
# 遍历每个视频卡片,idx为序号,card为卡片对象
for idx, card in enumerate(video_cards, 1):
try:
# 鼠标悬停到视频卡片上
card.hover()
# 获取视频标题
title = card.ele(".VDYK8Xd7").text
# 生成安全的文件名
filename = safe_filename(idx, title, ".mp4")
# 记录视频文件名
logger.info(f"视频文件名: {filename}")
# 等待监听获取真实视频地址
real_video_url = tab.listen.wait().url
# 记录视频真实地址
logger.info(f"视频地址: {real_video_url}")
# 如果获取到真实视频地址
if real_video_url:
# 发送GET请求下载视频数据
video_data = session.get(
real_video_url,
headers={
"Referer": "https://www.douyin.com/",
"User-Agent": DOUYIN_USER_AGENT,
},
timeout=10,
).content
# 拼接视频文件保存路径
file_path = os.path.join(DOUYIN_SAVE_DIR, filename)
# 记录保存路径
logger.info(f"保存到: {file_path}")
# 以二进制写入方式保存视频文件
with open(file_path, "wb") as f:
f.write(video_data)
# 记录保存成功
logger.info(f"已保存到: {file_path}")
# 将文件路径添加到列表
video_files.append(file_path)
else:
# 未获取到视频地址,记录警告
logger.warning("未找到视频地址,跳过。")
except Exception as e:
# 捕获下载异常并记录日志
logger.error(f"下载失败: {e}")
# 跳过当前循环,继续下一个
continue
# 全部下载完成后记录日志
+ logger.info("全部下载完成!")
# 记录本次下载的视频文件列表
+ logger.info(f"本次共下载视频文件: {video_files}")
# 返回视频文件路径列表
+ return video_files
# 定义视频转音频的函数,参数为视频文件路径
+def extract_audio(video_path):
# 记录准备转音频的日志
+ logger.info(f"准备将视频转音频: {video_path}")
# 获取视频文件名(不含扩展名)
+ base = os.path.splitext(os.path.basename(video_path))[0]
# 构造mp3音频文件的完整路径
+ mp3_path = os.path.join(os.path.dirname(video_path), f"{base}.mp3")
# 构造ffmpeg命令行参数列表
+ cmd = [
+ "ffmpeg",
+ "-y", # 覆盖输出文件
+ "-i", # 输入文件
+ video_path,
+ "-vn", # 不处理视频流
+ "-acodec", # 指定音频编码器
+ "libmp3lame",
+ "-ar", # 指定音频采样率
+ "44100",
+ "-ac", # 指定音频声道数
+ "2",
+ "-ab", # 指定音频比特率
+ "192k",
+ mp3_path, # 输出文件路径
+ ]
+ try:
# 记录正在提取音频的日志
+ logger.info(f"正在提取音频到: {mp3_path}")
# 调用ffmpeg命令行进行音频提取
+ subprocess.run(cmd, check=True)
# 记录音频提取完成的日志
+ logger.info(f"音频提取完成: {mp3_path}")
# 返回mp3音频文件路径
+ return mp3_path
+ except Exception as e:
# 记录音频提取失败的日志
+ logger.error(f"音频提取失败: {e}")
# 返回None表示失败
+ return None
8.2. main.py #
main.py
# 从common模块导入get_logger函数
from common import get_logger
# 从douyin_utils模块导入crawl_douyin_videos函数
+from douyin_utils import crawl_douyin_videos, extract_audio
# 创建当前模块的日志记录器实例
logger = get_logger(__name__)
# 定义主函数
def main():
# 记录主流程开始的日志信息
logger.info("主流程开始")
try:
# 调用爬取抖音热门视频的函数,参数为"脆桃"
+ video_files = crawl_douyin_videos("脆桃")
+ for video_file in video_files:
+ logger.info(f"处理视频文件: {video_file}")
# 2. 视频转音频
+ mp3_file = extract_audio(video_file)
+ if not mp3_file:
+ logger.warning(f"视频转音频失败,跳过: {video_file}")
+ continue
except Exception as e:
# 如果主流程执行出错,记录错误日志
logger.error(f"主流程执行出错: {e}")
# 判断当前脚本是否作为主程序运行
if __name__ == "__main__":
# 调用主函数
main()
9.上传音频到腾讯云 #
本节介绍如何将音频文件上传到腾讯云COS,方便后续API在线访问和处理。
9.1. cos_utils.py #
cos_utils.py
# 导入操作系统相关的模块,用于处理文件和目录等操作
import os
# 从腾讯云COS SDK中导入配置类和客户端类
from qcloud_cos import CosConfig, CosS3Client
# 从common模块导入日志记录器函数
from common import get_logger
# 从config模块导入腾讯云相关的配置参数
from config import (
TENCENT_SECRET_ID, # 腾讯云访问密钥ID
TENCENT_SECRET_KEY, # 腾讯云访问密钥
TENCENT_REGION, # 腾讯云服务区域
TENCENT_BUCKET, # 腾讯云存储桶名称
TENCENT_TOKEN, # 腾讯云临时访问令牌
TENCENT_SCHEME, # 腾讯云服务协议
)
# 为当前模块创建专用的日志记录器实例
logger = get_logger(__name__)
# 定义上传文件到腾讯云COS的函数,接收文件路径和可选的存储键名作为参数
def upload_to_cos(file_path, key=None):
# 记录开始上传文件的日志信息
logger.info(f"准备上传音频到腾讯云COS: {file_path}")
# 如果没有指定存储键名,则使用文件名作为键名
if key is None:
key = os.path.basename(file_path)
# 创建腾讯云COS配置对象,包含区域、密钥等认证信息
config = CosConfig(
Region=TENCENT_REGION, # 设置服务区域
SecretId=TENCENT_SECRET_ID, # 设置访问密钥ID
SecretKey=TENCENT_SECRET_KEY, # 设置访问密钥
Token=TENCENT_TOKEN, # 设置临时访问令牌
Scheme=TENCENT_SCHEME, # 设置服务协议
)
# 使用配置对象创建COS客户端实例
client = CosS3Client(config)
# 以二进制读取模式打开文件
with open(file_path, "rb") as fp:
# 调用客户端方法上传文件到COS存储桶
client.put_object(
Bucket=TENCENT_BUCKET, # 指定存储桶名称
Body=fp, # 文件内容
Key=key, # 存储键名
StorageClass="STANDARD", # 存储类型为标准存储
EnableMD5=False, # 禁用MD5校验
)
# 构建文件的访问URL地址
url = f"https://{TENCENT_BUCKET}.cos.{TENCENT_REGION}.myqcloud.com/{key}"
# 记录上传成功的日志信息,包含访问地址
logger.info(f"文件已上传,访问地址: {url}")
# 返回文件的访问URL地址
return url9.2. config.py #
config.py
# 导入操作系统相关的模块,用于处理文件和目录等操作
import os
# 从dotenv库中导入load_dotenv函数,用于加载.env文件中的环境变量
from dotenv import load_dotenv
# 加载.env文件中的所有环境变量到系统环境变量中
load_dotenv()
# ================== 常量配置区 ==================
# 获取环境变量"DOUYIN_SAVE_DIR"的值,如果没有设置则默认使用"douyin_videos"
DOUYIN_SAVE_DIR = os.environ.get("DOUYIN_SAVE_DIR", "douyin_videos")
# 设置用于请求抖音网页的User-Agent字符串,模拟浏览器访问
DOUYIN_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36"
# 腾讯云配置
+TENCENT_SECRET_ID = os.environ.get("TENCENT_SECRET_ID")
+TENCENT_SECRET_KEY = os.environ.get("TENCENT_SECRET_KEY")
+TENCENT_REGION = os.environ.get("TENCENT_REGION", "ap-beijing")
+TENCENT_BUCKET = os.environ.get("TENCENT_BUCKET", "xiaohongshu-1258145019")
+TENCENT_TOKEN = None
+TENCENT_SCHEME = "https"
9.3. main.py #
main.py
# 从common模块导入get_logger函数
from common import get_logger
# 从douyin_utils模块导入crawl_douyin_videos函数
from douyin_utils import crawl_douyin_videos, extract_audio
# 从cos_utils模块导入upload_to_cos函数
+from cos_utils import upload_to_cos
# 创建当前模块的日志记录器实例
logger = get_logger(__name__)
# 定义主函数
def main():
# 记录主流程开始的日志信息
logger.info("主流程开始")
try:
# 调用爬取抖音热门视频的函数,参数为"脆桃"
video_files = crawl_douyin_videos("脆桃")
for video_file in video_files:
logger.info(f"处理视频文件: {video_file}")
# 2. 视频转音频
mp3_file = extract_audio(video_file)
if not mp3_file:
logger.warning(f"视频转音频失败,跳过: {video_file}")
continue
# 3. 上传音频到腾讯云
+ cos_url = upload_to_cos(mp3_file)
+ logger.info(f"上传音频到腾讯云成功: {cos_url}")
except Exception as e:
# 如果主流程执行出错,记录错误日志
logger.error(f"主流程执行出错: {e}")
# 判断当前脚本是否作为主程序运行
if __name__ == "__main__":
# 调用主函数
main()
10.音频转文字 #
本节讲解如何调用火山引擎API,把音频自动转成文字,免去手动听写的麻烦。
10.1. asr_utils.py #
asr_utils.py
# 导入UUID模块,用于生成唯一标识符
import uuid
# 导入时间模块,用于实现延时功能
import time
# 导入JSON模块,用于处理JSON格式数据
import json
# 从common模块导入日志记录器和HTTP会话对象
from common import get_logger, session
# 从config模块导入火山引擎和音频相关的配置参数
from config import (
VOLC_APPID, # 火山引擎应用ID
VOLC_TOKEN, # 火山引擎访问令牌
AUDIO_FORMAT, # 音频文件格式
AUDIO_CODEC, # 音频编解码器
AUDIO_SAMPLE_RATE, # 音频采样率
AUDIO_BITS, # 音频位深度
AUDIO_CHANNEL, # 音频声道数
)
# 为当前模块创建专用的日志记录器实例
logger = get_logger(__name__)
# 定义音频转文字的主函数,接收音频文件URL作为参数
def audio_to_text(file_url):
# 记录开始处理音频转文字任务的日志信息
logger.info(f"准备将音频转文字,音频URL: {file_url}")
# 设置火山引擎语音识别服务的提交任务API地址
submit_url = "https://openspeech.bytedance.com/api/v3/auc/bigmodel/submit"
# 生成唯一的任务ID,用于标识本次识别任务
task_id = str(uuid.uuid4())
# 设置HTTP请求头,包含火山引擎API所需的认证和标识信息
headers = {
"X-Api-App-Key": VOLC_APPID,
"X-Api-Access-Key": VOLC_TOKEN,
"X-Api-Resource-Id": "volc.bigasr.auc",
"X-Api-Request-Id": task_id,
"X-Api-Sequence": "-1",
}
# 构建请求数据,包含用户信息、音频参数和识别请求配置
request_data = {
"user": {"uid": "fake_uid"},
"audio": {
"url": file_url, # 音频文件URL地址
"format": AUDIO_FORMAT, # 音频文件格式
"codec": AUDIO_CODEC, # 音频编解码器
"rate": AUDIO_SAMPLE_RATE, # 音频采样率
"bits": AUDIO_BITS, # 音频位深度
"channel": AUDIO_CHANNEL, # 音频声道数
},
"request": {
"model_name": "bigmodel",
"show_utterances": True,
"corpus": {"correct_table_name": "", "context": ""},
},
}
# 记录提交任务的ID信息
logger.info(f"Submit task id: {task_id}")
# 向火山引擎API发送POST请求,提交音频转文字任务
response = session.post(
submit_url, data=json.dumps(request_data), headers=headers, timeout=10
)
# 检查响应头中的状态码,判断任务是否提交成功
if (
"X-Api-Status-Code" in response.headers
and response.headers["X-Api-Status-Code"] == "20000000"
):
# 从响应头中获取日志ID,用于后续查询任务结果
x_tt_logid = response.headers.get("X-Tt-Logid", "")
# 记录任务提交成功的日志信息
logger.info("音频转文字任务提交成功,开始轮询结果...")
else:
# 记录任务提交失败的日志信息,包含响应头详情
logger.error(
f"Submit task failed and the response headers are: {response.headers}"
)
# 任务提交失败,返回None
return None
# 设置查询任务结果的API地址
query_url = "https://openspeech.bytedance.com/api/v3/auc/bigmodel/query"
# 复制请求头并添加日志ID
headers_query = headers.copy()
headers_query["X-Tt-Logid"] = x_tt_logid
# 开始轮询任务结果,直到获得最终结果或失败
while True:
# 向查询API发送POST请求,获取任务处理状态
query_response = session.post(
query_url, json.dumps({}), headers=headers_query, timeout=10
)
# 从响应头中获取状态码
code = query_response.headers.get("X-Api-Status-Code", "")
# 如果状态码为20000000,表示任务处理完成
if code == "20000000":
# 从响应JSON中提取识别出的文字内容
text = query_response.json()["result"]["text"]
# 记录识别成功的日志信息
logger.info(f"音频转文字结果:{text}")
# 返回识别出的文字内容
return text
# 如果状态码不是20000001或20000002(处理中状态),表示任务失败
elif code != "20000001" and code != "20000002":
# 记录任务失败的日志信息
logger.error("音频转文字失败!")
# 返回None表示处理失败
return None
# 如果任务仍在处理中,等待1秒后继续轮询
time.sleep(1)
10.2. config.py #
config.py
# 导入操作系统相关的模块,用于处理文件和目录等操作
import os
# 从dotenv库中导入load_dotenv函数,用于加载.env文件中的环境变量
from dotenv import load_dotenv
# 加载.env文件中的所有环境变量到系统环境变量中
load_dotenv()
# ================== 常量配置区 ==================
# 获取环境变量"DOUYIN_SAVE_DIR"的值,如果没有设置则默认使用"douyin_videos"
DOUYIN_SAVE_DIR = os.environ.get("DOUYIN_SAVE_DIR", "douyin_videos")
# 设置用于请求抖音网页的User-Agent字符串,模拟浏览器访问
DOUYIN_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36"
# 腾讯云配置
# 获取腾讯云访问密钥ID,用于身份验证
TENCENT_SECRET_ID = os.environ.get("TENCENT_SECRET_ID")
# 获取腾讯云访问密钥,用于身份验证
TENCENT_SECRET_KEY = os.environ.get("TENCENT_SECRET_KEY")
# 获取腾讯云服务区域,默认为北京
TENCENT_REGION = os.environ.get("TENCENT_REGION", "ap-beijing")
# 获取腾讯云存储桶名称,默认为小红书相关桶
TENCENT_BUCKET = os.environ.get("TENCENT_BUCKET", "xiaohongshu-1258145019")
# 腾讯云临时访问令牌,初始为空
TENCENT_TOKEN = None
# 腾讯云服务协议,使用HTTPS
TENCENT_SCHEME = "https"
# 火山引擎配置
# 获取火山引擎应用ID
+VOLC_APPID = os.environ.get("VOLC_APPID")
# 获取火山引擎访问令牌
+VOLC_TOKEN = os.environ.get("VOLC_TOKEN")
# 音频采样率,设置为16kHz
+AUDIO_SAMPLE_RATE = 16000
# 音频位深度,设置为16位
+AUDIO_BITS = 16
# 音频声道数,设置为单声道
+AUDIO_CHANNEL = 1
# 音频文件格式,设置为MP3
+AUDIO_FORMAT = "mp3"
# 音频编解码器,设置为原始格式
+AUDIO_CODEC = "raw"
10.3. main.py #
main.py
# 导入日志记录器,用于记录程序运行过程中的各种信息
from common import get_logger
# 导入抖音相关工具函数,包括爬取视频和提取音频功能
from douyin_utils import crawl_douyin_videos, extract_audio
# 导入腾讯云对象存储上传工具函数
from cos_utils import upload_to_cos
# 导入语音识别工具函数,用于将音频转换为文字
+from asr_utils import audio_to_text
# 为当前模块创建专用的日志记录器实例
logger = get_logger(__name__)
# 定义程序的主入口函数
def main():
# 在程序开始时记录一条信息日志,表示主流程已启动
logger.info("主流程开始")
try:
# 使用关键词"脆桃"爬取抖音热门视频,返回视频文件列表
video_files = crawl_douyin_videos("脆桃")
# 遍历每个爬取到的视频文件进行处理
for video_file in video_files:
# 记录当前正在处理的视频文件名称
logger.info(f"处理视频文件: {video_file}")
# 将视频文件转换为MP3音频格式
mp3_file = extract_audio(video_file)
# 检查音频转换是否成功,如果失败则跳过当前文件
if not mp3_file:
# 记录警告日志,表示音频转换失败
logger.warning(f"视频转音频失败,跳过: {video_file}")
# 跳过当前文件,继续处理下一个
continue
# 将转换后的音频文件上传到腾讯云对象存储
cos_url = upload_to_cos(mp3_file)
# 记录上传成功的日志信息,包含返回的云存储URL
logger.info(f"上传音频到腾讯云成功: {cos_url}")
# 使用语音识别服务将音频转换为文字内容
+ douyin_text = audio_to_text(cos_url)
# 记录语音识别成功的日志信息,包含识别出的文字内容
+ logger.info(f"音频转文字成功: {douyin_text}")
# 检查语音识别是否成功,如果失败则跳过当前文件
+ if not douyin_text:
# 记录警告日志,表示语音识别失败
+ logger.warning(f"音频转文字失败,跳过: {mp3_file}")
# 跳过当前文件,继续处理下一个
+ continue
except Exception as e:
# 捕获并记录主流程执行过程中的任何异常错误
logger.error(f"主流程执行出错: {e}")
# 检查当前脚本是否作为主程序直接运行(而不是被其他模块导入)
if __name__ == "__main__":
# 如果作为主程序运行,则调用主函数开始执行
main()
11.抖音文案转小红书文案 #
本节介绍如何用大模型自动改写文案,生成小红书风格的爆款内容、标题和标签。
11.1. xhs_utils.py #
xhs_utils.py
# 导入OpenAI客户端库,用于调用大语言模型API
from openai import OpenAI
# 导入日志记录器,用于记录程序运行过程中的各种信息
from common import get_logger
# 导入OpenAI相关的配置参数,包括API密钥和基础URL
from config import OPENAI_API_KEY, OPENAI_BASE_URL
# 导入时间模块,用于实现延时功能
import time
# 为当前模块创建专用的日志记录器实例
logger = get_logger(__name__)
# 定义抖音文案转小红书文案的主函数,接收抖音文案文本作为参数
def douyin_to_xhs_text(douyin_text):
# 记录开始处理抖音文案转小红书文案任务的日志信息
logger.info(f"准备将抖音文案转为小红书文案,原文案:{douyin_text}")
# 创建OpenAI客户端实例,使用配置中的基础URL和API密钥
client = OpenAI(base_url=OPENAI_BASE_URL, api_key=OPENAI_API_KEY)
# 记录开始调用大模型生成小红书正文的日志信息
logger.info("调用大模型生成小红书正文...")
# 向大模型发送请求,要求将抖音文案改写为小红书爆款正文
resp_intro = client.chat.completions.create(
# 指定使用的大模型名称
model="doubao-seed-1-6-250615",
# 构建请求消息,包含用户角色和内容
messages=[
{
# 设置消息角色为用户
"role": "user",
# 设置消息内容,包含文本类型和具体的改写要求
"content": [
{
# 指定内容类型为文本
"type": "text",
# 设置具体的改写提示词,要求将抖音文案改写为不超过1000字的小红书正文
"text": f"请将以下抖音文案改写为小红书爆款正文,正文描述不超过1000字:{douyin_text}",
},
],
}
],
)
# 从大模型响应中提取生成的小红书正文内容
xhs_intro = (
# 如果响应对象有message属性,则获取其content内容
resp_intro.choices[0].message.content
if hasattr(resp_intro.choices[0], "message")
# 否则直接使用响应对象本身
else resp_intro.choices[0]
)
# 去除正文内容首尾的空白字符
xhs_intro = xhs_intro.strip()
# 记录生成的小红书正文内容的日志信息
logger.info(f"小红书正文:{xhs_intro}")
# 等待5秒,避免API调用过于频繁
time.sleep(5)
# 记录开始调用大模型生成小红书标题的日志信息
logger.info("调用大模型生成小红书标题...")
# 向大模型发送请求,要求根据小红书正文生成爆款标题
resp_title = client.chat.completions.create(
# 指定使用的大模型名称
model="doubao-seed-1-6-250615",
# 构建请求消息,包含用户角色和内容
messages=[
{
# 设置消息角色为用户
"role": "user",
# 设置消息内容,包含文本类型和具体的标题生成要求
"content": [
{
# 指定内容类型为文本
"type": "text",
# 设置具体的标题生成提示词,要求生成不超过20字的爆款标题
"text": f"请根据以下小红书正文生成一个不超过20字的爆款标题:{xhs_intro}",
},
],
}
],
)
# 从大模型响应中提取生成的小红书标题内容
xhs_title = (
# 如果响应对象有message属性,则获取其content内容
resp_title.choices[0].message.content
if hasattr(resp_title.choices[0], "message")
# 否则直接使用响应对象本身
else resp_title.choices[0]
)
# 去除标题内容首尾的空白字符
xhs_title = xhs_title.strip()
# 记录生成的小红书标题内容的日志信息
logger.info(f"小红书标题:{xhs_title}")
# 等待5秒,避免API调用过于频繁
time.sleep(5)
# 记录开始调用大模型生成小红书标签的日志信息
logger.info("调用大模型生成小红书标签...")
# 向大模型发送请求,要求根据小红书正文生成相关标签
resp_tags = client.chat.completions.create(
# 指定使用的大模型名称
model="doubao-seed-1-6-250615",
# 构建请求消息,包含用户角色和内容
messages=[
{
# 设置消息角色为用户
"role": "user",
# 设置消息内容,包含文本类型和具体的标签生成要求
"content": [
{
# 指定内容类型为文本
"type": "text",
# 设置具体的标签生成提示词,要求生成10个相关标签,用逗号分隔,每个标签不超过10字
"text": f"请根据以下小红书正文生成10个相关标签,标签用逗号分隔,每个标签不超过10字:{xhs_intro}",
},
],
}
],
)
# 从大模型响应中提取生成的原始标签内容
tags_raw = (
# 如果响应对象有message属性,则获取其content内容
resp_tags.choices[0].message.content
if hasattr(resp_tags.choices[0], "message")
# 否则直接使用响应对象本身
else resp_tags.choices[0]
)
# 去除原始标签内容首尾的空白字符
tags_raw = tags_raw.strip()
# 将原始标签字符串按逗号分割,去除每个标签的空白字符,过滤掉空标签,生成最终的标签列表
xhs_tags = [tag.strip() for tag in tags_raw.split(",") if tag.strip()]
# 记录生成的小红书标签列表的日志信息
logger.info(f"小红书标签:{xhs_tags}")
# 返回生成的小红书标题、正文和标签列表
return xhs_title, xhs_intro, xhs_tags
11.2. config.py #
config.py
# 导入操作系统相关的模块,用于处理文件和目录等操作
import os
# 从dotenv库中导入load_dotenv函数,用于加载.env文件中的环境变量
from dotenv import load_dotenv
# 加载.env文件中的所有环境变量到系统环境变量中
load_dotenv()
# ================== 常量配置区 ==================
# 获取环境变量"DOUYIN_SAVE_DIR"的值,如果没有设置则默认使用"douyin_videos"
DOUYIN_SAVE_DIR = os.environ.get("DOUYIN_SAVE_DIR", "douyin_videos")
# 设置用于请求抖音网页的User-Agent字符串,模拟浏览器访问
DOUYIN_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36"
# 腾讯云配置
# 获取腾讯云访问密钥ID,用于身份验证
TENCENT_SECRET_ID = os.environ.get("TENCENT_SECRET_ID")
# 获取腾讯云访问密钥,用于身份验证
TENCENT_SECRET_KEY = os.environ.get("TENCENT_SECRET_KEY")
# 获取腾讯云服务区域,默认为北京
TENCENT_REGION = os.environ.get("TENCENT_REGION", "ap-beijing")
# 获取腾讯云存储桶名称,默认为小红书相关桶
TENCENT_BUCKET = os.environ.get("TENCENT_BUCKET", "xiaohongshu-1258145019")
# 腾讯云临时访问令牌,初始为空
TENCENT_TOKEN = None
# 腾讯云服务协议,使用HTTPS
TENCENT_SCHEME = "https"
# 火山引擎配置
# 获取火山引擎应用ID
VOLC_APPID = os.environ.get("VOLC_APPID")
# 获取火山引擎访问令牌
VOLC_TOKEN = os.environ.get("VOLC_TOKEN")
# 音频采样率,设置为16kHz
AUDIO_SAMPLE_RATE = 16000
# 音频位深度,设置为16位
AUDIO_BITS = 16
# 音频声道数,设置为单声道
AUDIO_CHANNEL = 1
# 音频文件格式,设置为MP3
AUDIO_FORMAT = "mp3"
# 音频编解码器,设置为原始格式
AUDIO_CODEC = "raw"
# 获取OpenAI API密钥,用于身份验证和访问OpenAI服务
+OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
# 获取OpenAI服务的基础URL地址,用于指定API请求的目标服务器
+OPENAI_BASE_URL = os.environ.get("OPENAI_BASE_URL")
11.3. main.py #
main.py
# 导入日志记录器,用于记录程序运行过程中的各种信息
from common import get_logger
# 导入抖音相关工具函数,包括爬取视频和提取音频功能
from douyin_utils import crawl_douyin_videos, extract_audio
# 导入腾讯云对象存储上传工具函数
from cos_utils import upload_to_cos
# 导入语音识别工具函数,用于将音频转换为文字
from asr_utils import audio_to_text
# 导入抖音文案转小红书文案工具函数
+from xhs_utils import douyin_to_xhs_text
# 为当前模块创建专用的日志记录器实例
logger = get_logger(__name__)
# 定义程序的主入口函数
def main():
# 在程序开始时记录一条信息日志,表示主流程已启动
logger.info("主流程开始")
try:
# 1.使用关键词"脆桃"爬取抖音热门视频,返回视频文件列表
video_files = crawl_douyin_videos("脆桃")
# 遍历每个爬取到的视频文件进行处理
for video_file in video_files:
# 记录当前正在处理的视频文件名称
logger.info(f"处理视频文件: {video_file}")
# 2.将视频文件转换为MP3音频格式
mp3_file = extract_audio(video_file)
# 检查音频转换是否成功,如果失败则跳过当前文件
if not mp3_file:
# 记录警告日志,表示音频转换失败
logger.warning(f"视频转音频失败,跳过: {video_file}")
# 跳过当前文件,继续处理下一个
continue
# 3.将转换后的音频文件上传到腾讯云对象存储
cos_url = upload_to_cos(mp3_file)
# 记录上传成功的日志信息,包含返回的云存储URL
logger.info(f"上传音频到腾讯云成功: {cos_url}")
# 4.使用语音识别服务将音频转换为文字内容
douyin_text = audio_to_text(cos_url)
# 记录语音识别成功的日志信息,包含识别出的文字内容
logger.info(f"音频转文字成功: {douyin_text}")
# 检查语音识别是否成功,如果失败则跳过当前文件
if not douyin_text:
# 记录警告日志,表示语音识别失败
logger.warning(f"音频转文字失败,跳过: {mp3_file}")
# 跳过当前文件,继续处理下一个
continue
# 5.抖音文案转小红书文案
+ xhs_title, xhs_intro, xhs_tags = douyin_to_xhs_text(douyin_text)
+ logger.info(
+ f"抖音文案转小红书文案成功: {xhs_title}, {xhs_intro}, {xhs_tags}"
+ )
except Exception as e:
# 捕获并记录主流程执行过程中的任何异常错误
logger.error(f"主流程执行出错: {e}")
# 检查当前脚本是否作为主程序直接运行(而不是被其他模块导入)
if __name__ == "__main__":
# 如果作为主程序运行,则调用主函数开始执行
main()12.根据文案生成图片 #
本节讲解如何用AI根据文案自动生成多张图片,并自动去除水印,适合内容创作和推广。
12.1. image_utils.py #
image_utils.py
# 导入OpenAI客户端库,用于调用AI图片生成服务
from openai import OpenAI
# 从common模块导入session会话对象和safe_filename安全文件名生成函数
from common import session, safe_filename
# 从config模块导入OpenAI相关配置参数
from config import (
OPENAI_API_KEY,
OPENAI_BASE_URL,
IMAGE_SIZE,
IMAGE_SAVE_DIR,
IMAGE_NUM_DEFAULT,
)
# 导入操作系统相关功能模块
import os
# 从common模块导入日志记录器
from common import get_logger
# 为当前模块创建专用的日志记录器实例
logger = get_logger(__name__)
# 定义根据文案生成图片的主函数,接收标题、正文和图片数量参数
def generate_images_by_text(title, intro, num_images=None):
# 记录开始生成图片的日志信息,包含标题和正文内容
logger.info(f"准备根据文案生成图片,标题:{title},正文:{intro}")
# 创建OpenAI客户端实例,使用配置的API密钥和基础URL
client = OpenAI(base_url=OPENAI_BASE_URL, api_key=OPENAI_API_KEY)
# 初始化图片路径列表,用于存储生成的图片文件路径
img_paths = []
# 如果未指定图片数量,则使用默认配置的数量
if num_images is None:
num_images = IMAGE_NUM_DEFAULT
# 检查图片保存目录是否存在,如果不存在则创建
if not os.path.exists(IMAGE_SAVE_DIR):
os.makedirs(IMAGE_SAVE_DIR)
# 循环生成指定数量的图片
for i in range(num_images):
# 调用OpenAI图片生成API,使用豆包模型生成图片
response = client.images.generate(
model="doubao-seedream-3-0-t2i-250415",
prompt=f"{title}\n{intro}",
size=IMAGE_SIZE,
response_format="url",
)
# 从API响应中提取图片URL
url = response.data[0].url
# 记录图片生成成功的日志信息
logger.info(f"生成图片{i+1}:{url}")
# 使用安全文件名生成函数创建文件名
filename = safe_filename(i + 1, title, ".jpg")
# 下载图片
# 构建完整的图片保存路径
img_path = os.path.join(IMAGE_SAVE_DIR, filename)
# 以二进制写入模式打开文件,下载并保存图片内容
with open(img_path, "wb") as f:
f.write(session.get(url, timeout=10).content)
# 将保存的图片路径添加到结果列表中
img_paths.append(img_path)
# 返回所有生成的图片文件路径列表
return img_paths
12.2. config.py #
config.py
# 导入操作系统相关的模块,用于处理文件和目录等操作
import os
# 从dotenv库中导入load_dotenv函数,用于加载.env文件中的环境变量
from dotenv import load_dotenv
# 加载.env文件中的所有环境变量到系统环境变量中
load_dotenv()
# ================== 常量配置区 ==================
# 获取环境变量"DOUYIN_SAVE_DIR"的值,如果没有设置则默认使用"douyin_videos"
DOUYIN_SAVE_DIR = os.environ.get("DOUYIN_SAVE_DIR", "douyin_videos")
# 设置用于请求抖音网页的User-Agent字符串,模拟浏览器访问
DOUYIN_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36"
# 腾讯云配置
# 获取腾讯云访问密钥ID,用于身份验证
TENCENT_SECRET_ID = os.environ.get("TENCENT_SECRET_ID")
# 获取腾讯云访问密钥,用于身份验证
TENCENT_SECRET_KEY = os.environ.get("TENCENT_SECRET_KEY")
# 获取腾讯云服务区域,默认为北京
TENCENT_REGION = os.environ.get("TENCENT_REGION", "ap-beijing")
# 获取腾讯云存储桶名称,默认为小红书相关桶
TENCENT_BUCKET = os.environ.get("TENCENT_BUCKET", "xiaohongshu-1258145019")
# 腾讯云临时访问令牌,初始为空
TENCENT_TOKEN = None
# 腾讯云服务协议,使用HTTPS
TENCENT_SCHEME = "https"
# 火山引擎配置
# 获取火山引擎应用ID
VOLC_APPID = os.environ.get("VOLC_APPID")
# 获取火山引擎访问令牌
VOLC_TOKEN = os.environ.get("VOLC_TOKEN")
# 音频采样率,设置为16kHz
AUDIO_SAMPLE_RATE = 16000
# 音频位深度,设置为16位
AUDIO_BITS = 16
# 音频声道数,设置为单声道
AUDIO_CHANNEL = 1
# 音频文件格式,设置为MP3
AUDIO_FORMAT = "mp3"
# 音频编解码器,设置为原始格式
AUDIO_CODEC = "raw"
# 获取OpenAI API密钥,用于身份验证和访问OpenAI服务
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
# 获取OpenAI服务的基础URL地址,用于指定API请求的目标服务器
OPENAI_BASE_URL = os.environ.get("OPENAI_BASE_URL")
# 设置图片尺寸,默认为1024x1024
+IMAGE_SIZE = "1024x1024"
# 设置图片保存目录,默认为"images"
+IMAGE_SAVE_DIR = os.environ.get("IMAGE_SAVE_DIR", "images")
# 设置默认的图片生成数量,默认为3张
+IMAGE_NUM_DEFAULT = int(os.environ.get("IMAGE_NUM_DEFAULT", "3"))
12.3. main.py #
main.py
# 导入日志记录器,用于记录程序运行过程中的各种信息
from common import get_logger
# 导入抖音相关工具函数,包括爬取视频和提取音频功能
from douyin_utils import crawl_douyin_videos, extract_audio
# 导入腾讯云对象存储上传工具函数
from cos_utils import upload_to_cos
# 导入语音识别工具函数,用于将音频转换为文字
from asr_utils import audio_to_text
# 导入抖音文案转小红书文案工具函数
from xhs_utils import douyin_to_xhs_text
# 为当前模块创建专用的日志记录器实例
logger = get_logger(__name__)
# 导入根据文案生成图片工具函数
+from image_utils import generate_images_by_text
# 导入图片生成配置参数
+from config import IMAGE_NUM_DEFAULT
# 定义程序的主入口函数
def main():
# 在程序开始时记录一条信息日志,表示主流程已启动
logger.info("主流程开始")
try:
# 1.使用关键词"脆桃"爬取抖音热门视频,返回视频文件列表
video_files = crawl_douyin_videos("脆桃")
# 遍历每个爬取到的视频文件进行处理
for video_file in video_files:
# 记录当前正在处理的视频文件名称
logger.info(f"处理视频文件: {video_file}")
# 2.将视频文件转换为MP3音频格式
mp3_file = extract_audio(video_file)
# 检查音频转换是否成功,如果失败则跳过当前文件
if not mp3_file:
# 记录警告日志,表示音频转换失败
logger.warning(f"视频转音频失败,跳过: {video_file}")
# 跳过当前文件,继续处理下一个
continue
# 3.将转换后的音频文件上传到腾讯云对象存储
cos_url = upload_to_cos(mp3_file)
# 记录上传成功的日志信息,包含返回的云存储URL
logger.info(f"上传音频到腾讯云成功: {cos_url}")
# 4.使用语音识别服务将音频转换为文字内容
douyin_text = audio_to_text(cos_url)
# 记录语音识别成功的日志信息,包含识别出的文字内容
logger.info(f"音频转文字成功: {douyin_text}")
# 检查语音识别是否成功,如果失败则跳过当前文件
if not douyin_text:
# 记录警告日志,表示语音识别失败
logger.warning(f"音频转文字失败,跳过: {mp3_file}")
# 跳过当前文件,继续处理下一个
continue
# 5.抖音文案转小红书文案
xhs_title, xhs_intro, xhs_tags = douyin_to_xhs_text(douyin_text)
logger.info(
f"抖音文案转小红书文案成功: {xhs_title}, {xhs_intro}, {xhs_tags}"
)
# 6. 根据文案生成图片
+ img_paths = generate_images_by_text(
+ xhs_title, xhs_intro, num_images=IMAGE_NUM_DEFAULT
+ )
+ logger.info(f"根据文案生成图片成功: {img_paths}")
except Exception as e:
# 捕获并记录主流程执行过程中的任何异常错误
logger.error(f"主流程执行出错: {e}")
# 检查当前脚本是否作为主程序直接运行(而不是被其他模块导入)
if __name__ == "__main__":
# 如果作为主程序运行,则调用主函数开始执行
main()
13.去掉图片水印 #
本节介绍如何用AI算法自动去除图片右下角的"AI生成"水印,让图片更美观。
13.1. config.py #
config.py
# 导入操作系统相关的模块,用于处理文件和目录等操作
import os
# 从dotenv库中导入load_dotenv函数,用于加载.env文件中的环境变量
from dotenv import load_dotenv
# 加载.env文件中的所有环境变量到系统环境变量中
load_dotenv()
# ================== 常量配置区 ==================
# 获取环境变量"DOUYIN_SAVE_DIR"的值,如果没有设置则默认使用"douyin_videos"
+DOUYIN_SAVE_DIR = os.environ.get("DOUYIN_SAVE_DIR", "douyin_videos")
# 设置用于请求抖音网页的User-Agent字符串,模拟浏览器访问
DOUYIN_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36"
# 腾讯云配置
# 获取腾讯云访问密钥ID,用于身份验证
TENCENT_SECRET_ID = os.environ.get("TENCENT_SECRET_ID")
# 获取腾讯云访问密钥,用于身份验证
TENCENT_SECRET_KEY = os.environ.get("TENCENT_SECRET_KEY")
# 获取腾讯云服务区域,默认为北京
TENCENT_REGION = os.environ.get("TENCENT_REGION", "ap-beijing")
# 获取腾讯云存储桶名称,默认为小红书相关桶
TENCENT_BUCKET = os.environ.get("TENCENT_BUCKET", "xiaohongshu-1258145019")
# 腾讯云临时访问令牌,初始为空
TENCENT_TOKEN = None
# 腾讯云服务协议,使用HTTPS
TENCENT_SCHEME = "https"
# 火山引擎配置
# 获取火山引擎应用ID
VOLC_APPID = os.environ.get("VOLC_APPID")
# 获取火山引擎访问令牌
VOLC_TOKEN = os.environ.get("VOLC_TOKEN")
# 音频采样率,设置为16kHz
AUDIO_SAMPLE_RATE = 16000
# 音频位深度,设置为16位
AUDIO_BITS = 16
# 音频声道数,设置为单声道
AUDIO_CHANNEL = 1
# 音频文件格式,设置为MP3
AUDIO_FORMAT = "mp3"
# 音频编解码器,设置为原始格式
AUDIO_CODEC = "raw"
# 获取OpenAI API密钥,用于身份验证和访问OpenAI服务
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
# 获取OpenAI服务的基础URL地址,用于指定API请求的目标服务器
OPENAI_BASE_URL = os.environ.get("OPENAI_BASE_URL")
# 设置图片尺寸,默认为1024x1024
IMAGE_SIZE = "1024x1024"
# 设置图片保存目录,默认为"images"
IMAGE_SAVE_DIR = os.environ.get("IMAGE_SAVE_DIR", "images")
# 设置默认的图片生成数量,默认为3张
IMAGE_NUM_DEFAULT = int(os.environ.get("IMAGE_NUM_DEFAULT", "3"))
13.2. image_utils.py #
image_utils.py
# 导入OpenAI客户端库,用于调用AI图片生成服务
from openai import OpenAI
# 从common模块导入session会话对象和safe_filename安全文件名生成函数
from common import session, safe_filename
# 从config模块导入OpenAI相关配置参数
from config import (
OPENAI_API_KEY,
OPENAI_BASE_URL,
IMAGE_SIZE,
IMAGE_SAVE_DIR,
IMAGE_NUM_DEFAULT,
)
# 导入操作系统相关功能模块
import os
+import cv2
+import numpy as np
# 从common模块导入日志记录器
from common import get_logger
# 为当前模块创建专用的日志记录器实例
logger = get_logger(__name__)
# 定义去除图片水印的函数,接收输入路径、输出路径和水印比例参数
+def remove_watermark(input_path, output_path=None, height_ratio=0.10, width_ratio=0.22):
+ """
+ 去除图片右下角的水印
+ Args:
+ input_path (str): 输入图片路径
+ output_path (str): 输出图片路径,如果为None则自动生成
+ height_ratio (float): 水印高度占图片高度的比例,默认0.10
+ width_ratio (float): 水印宽度占图片宽度的比例,默认0.22
+ Returns:
+ str: 输出图片路径
+ """
# 使用OpenCV读取输入图片文件
+ img = cv2.imread(input_path)
# 检查图片是否成功读取,如果失败则抛出异常
+ if img is None:
+ raise ValueError(f"无法读取图片:{input_path}")
# 获取图片的高度和宽度
+ h, w = img.shape[:2]
# 根据比例计算水印区域的高度
+ watermark_height = int(h * height_ratio)
# 根据比例计算水印区域的宽度
+ watermark_width = int(w * width_ratio)
# 创建一个与图片大小相同的全零掩码数组
+ mask = np.zeros((h, w), np.uint8)
# 在掩码的右下角区域设置255值,标记水印区域
+ mask[h - watermark_height : h, w - watermark_width : w] = 255
# 使用OpenCV的inpaint算法去除水印,使用TELEA算法
+ result = cv2.inpaint(img, mask, 3, cv2.INPAINT_TELEA)
# 如果没有指定输出路径,则自动生成输出文件名
+ if output_path is None:
# 获取输入文件的基础名称(不含扩展名)
+ base_name = os.path.splitext(input_path)[0]
# 构造去水印后的文件名
+ output_path = f"{base_name}_no_watermark.jpg"
# 将处理后的图片保存到指定路径
+ cv2.imwrite(output_path, result)
# 打印去水印完成的提示信息
+ print(f"去水印完成,已保存为 {output_path}")
# 返回输出图片的路径
+ return output_path
# 定义根据文案生成图片的主函数,接收标题、正文和图片数量参数
def generate_images_by_text(title, intro, num_images=None):
# 记录开始生成图片的日志信息,包含标题和正文内容
logger.info(f"准备根据文案生成图片,标题:{title},正文:{intro}")
# 创建OpenAI客户端实例,使用配置的API密钥和基础URL
client = OpenAI(base_url=OPENAI_BASE_URL, api_key=OPENAI_API_KEY)
# 初始化图片路径列表,用于存储生成的图片文件路径
img_paths = []
# 如果未指定图片数量,则使用默认配置的数量
if num_images is None:
num_images = IMAGE_NUM_DEFAULT
# 检查图片保存目录是否存在,如果不存在则创建
if not os.path.exists(IMAGE_SAVE_DIR):
os.makedirs(IMAGE_SAVE_DIR)
# 循环生成指定数量的图片
for i in range(num_images):
# 调用OpenAI图片生成API,使用豆包模型生成图片
response = client.images.generate(
model="doubao-seedream-3-0-t2i-250415",
prompt=f"{title}\n{intro}",
size=IMAGE_SIZE,
response_format="url",
)
# 从API响应中提取图片URL
url = response.data[0].url
# 记录图片生成成功的日志信息
logger.info(f"生成图片{i+1}:{url}")
# 使用安全文件名生成函数创建文件名
filename = safe_filename(i + 1, title, ".jpg")
# 构建完整的图片保存路径
img_path = os.path.join(IMAGE_SAVE_DIR, filename)
# 以二进制写入模式打开文件,下载并保存图片内容
with open(img_path, "wb") as f:
f.write(session.get(url, timeout=10).content)
# 调用去水印函数处理图片
+ img_path_no_watermark = remove_watermark(img_path)
# 将去水印后的图片路径添加到结果列表中
+ img_paths.append(img_path_no_watermark)
# 返回所有生成的图片文件路径列表
return img_paths
14.发布小红书 #
本节讲解如何自动化发布内容到小红书,实现一键发文,省时省力。
14.1. xhs_publisher.py #
xhs_publisher.py
# 导入浏览器实例和日志记录器
from common import browser, get_logger
# 导入键盘按键常量,用于模拟键盘操作
from DrissionPage.common import Keys
# 为当前模块创建专用的日志记录器实例
logger = get_logger(__name__)
# 定义发布到小红书的主函数,接收标题、正文、标签和图片路径参数
def post_to_xiaohongshu(title, intro, tags, img_paths):
# 记录开始发布小红书的日志信息,包含标题和图片路径
logger.info(f"准备自动发到小红书,标题:{title},图片:{img_paths}")
# 打开小红书创作者平台的发布页面
tab = browser.new_tab("https://creator.xiaohongshu.com/publish/publish")
# 等待页面加载完成
tab.wait(2)
# 查找并点击"发布笔记"按钮
publish_btn = tab("tag:span@text()=发布笔记", timeout=60)
publish_btn.click()
# 等待页面响应
tab.wait(2)
# 查找并点击"上传图文"按钮
publish_btn = tab("tag:span@text()=上传图文", timeout=60)
publish_btn.click()
# 等待页面响应
tab.wait(2)
# 设置要上传的图片文件路径,将多个路径用换行符连接
tab.set.upload_files("\n".join(img_paths))
# 查找并点击"上传图片"按钮
upload_img_btn = tab("tag:span@text()=上传图片", timeout=60)
upload_img_btn.click()
# 等待图片上传完成
tab.wait.upload_paths_inputted()
# 等待页面响应
tab.wait(2)
# 检查标题长度是否超过20个字符,如果超过则截取前20个字符
if len(title) > 20:
title = title[:20]
# 查找标题输入框并输入标题
title_input = tab("tag:input@@type=text@@class=d-text", timeout=60)
title_input.input(title)
# 等待页面响应
tab.wait(2)
# 检查正文长度是否超过250个字符,如果超过则截取前250个字符
if len(intro) > 250:
intro = intro[:250]
# 查找富文本编辑器并输入正文内容
editor = tab.ele(".:ql-editor", timeout=60)
editor.input(intro)
# 等待页面响应
tab.wait(2)
# 计算要添加的标签数量,最多10个标签
tag_count = min(len(tags), 10)
# 将光标移动到编辑器末尾
editor.input(Keys.END)
# 按回车键换行
editor.input(Keys.ENTER, clear=False)
# 循环添加标签
for i in range(tag_count):
# 输入标签,格式为"#标签名"
editor.input("#" + tags[i], clear=False)
# 等待输入完成
editor.wait(1)
# 按回车键确认标签
editor.input(Keys.ENTER, clear=False)
# 等待页面响应
editor.wait(1)
# 等待页面响应
tab.wait(2)
# 滚动到页面底部
tab.scroll.to_bottom()
# 等待页面响应
tab.wait(2)
# 查找并点击"发布"按钮
tab("tag:span@text()=发布").click()
# 等待发布完成
tab.wait(2)
# 记录发布成功的日志信息
logger.info("小红书上传成功~~")
14.2. main.py #
main.py
# 导入日志记录器,用于记录程序运行过程中的各种信息
from common import get_logger
# 导入抖音相关工具函数,包括爬取视频和提取音频功能
from douyin_utils import crawl_douyin_videos, extract_audio
# 导入腾讯云对象存储上传工具函数
from cos_utils import upload_to_cos
# 导入语音识别工具函数,用于将音频转换为文字
from asr_utils import audio_to_text
# 导入抖音文案转小红书文案工具函数
from xhs_utils import douyin_to_xhs_text
# 为当前模块创建专用的日志记录器实例
logger = get_logger(__name__)
# 导入根据文案生成图片工具函数
from image_utils import generate_images_by_text
# 导入图片生成配置参数
from config import IMAGE_NUM_DEFAULT
# 导入发布小红书工具函数
+from xhs_publisher import post_to_xiaohongshu
# 定义程序的主入口函数
def main():
# 在程序开始时记录一条信息日志,表示主流程已启动
logger.info("主流程开始")
try:
# 1.使用关键词"脆桃"爬取抖音热门视频,返回视频文件列表
video_files = crawl_douyin_videos("脆桃")
# 遍历每个爬取到的视频文件进行处理
for video_file in video_files:
# 记录当前正在处理的视频文件名称
logger.info(f"处理视频文件: {video_file}")
# 2.将视频文件转换为MP3音频格式
mp3_file = extract_audio(video_file)
# 检查音频转换是否成功,如果失败则跳过当前文件
if not mp3_file:
# 记录警告日志,表示音频转换失败
logger.warning(f"视频转音频失败,跳过: {video_file}")
# 跳过当前文件,继续处理下一个
continue
# 3.将转换后的音频文件上传到腾讯云对象存储
cos_url = upload_to_cos(mp3_file)
# 记录上传成功的日志信息,包含返回的云存储URL
logger.info(f"上传音频到腾讯云成功: {cos_url}")
# 4.使用语音识别服务将音频转换为文字内容
douyin_text = audio_to_text(cos_url)
# 记录语音识别成功的日志信息,包含识别出的文字内容
logger.info(f"音频转文字成功: {douyin_text}")
# 检查语音识别是否成功,如果失败则跳过当前文件
if not douyin_text:
# 记录警告日志,表示语音识别失败
logger.warning(f"音频转文字失败,跳过: {mp3_file}")
# 跳过当前文件,继续处理下一个
continue
# 5.抖音文案转小红书文案
xhs_title, xhs_intro, xhs_tags = douyin_to_xhs_text(douyin_text)
logger.info(
f"抖音文案转小红书文案成功: {xhs_title}, {xhs_intro}, {xhs_tags}"
)
# 6. 根据文案生成图片
img_paths = generate_images_by_text(
xhs_title, xhs_intro, num_images=IMAGE_NUM_DEFAULT
)
logger.info(f"根据文案生成图片成功: {img_paths}")
# 7. 自动发到小红书
+ post_to_xiaohongshu(
+ title=xhs_title, intro=xhs_intro, tags=xhs_tags, img_paths=img_paths
+ )
except Exception as e:
# 捕获并记录主流程执行过程中的任何异常错误
logger.error(f"主流程执行出错: {e}")
# 检查当前脚本是否作为主程序直接运行(而不是被其他模块导入)
if __name__ == "__main__":
# 如果作为主程序运行,则调用主函数开始执行
main()
15.发布知乎 #
本节介绍如何自动化发布内容到知乎专栏,适合多平台内容分发。
15.1. zhihu_publisher.py #
zhihu_publisher.py
# 导入浏览器实例和日志记录器
from common import browser, get_logger
# 导入键盘按键常量,用于模拟键盘操作
from DrissionPage.common import Keys
# 为当前模块创建专用的日志记录器实例
logger = get_logger(__name__)
# 定义发布到知乎的主函数,接收标题、正文、标签和图片路径参数
def post_to_zhihu(title, intro, img_paths):
# 记录开始发布知乎的日志信息,包含标题和图片路径
logger.info(f"准备自动发到知乎,标题:{title},图片:{img_paths}")
# 打开知乎专栏写作页面
tab = browser.new_tab("https://zhuanlan.zhihu.com/write")
# 等待页面加载完成
tab.wait(3)
# 查找标题输入框元素,使用特定的CSS类选择器
title_input = tab("tag:textarea@class:i7cW1UcwT6ThdhTakqFm", timeout=30)
# 检查标题长度是否超过100个字符,如果超过则截取前100个字符
if len(title) > 100:
title = title[:100]
# 在标题输入框中输入标题内容
title_input.input(title)
# 等待输入完成
tab.wait(1)
# 查找正文输入区域元素,使用DraftEditor-root类选择器
intro_input = tab("tag:div@class:DraftEditor-root", timeout=30)
# 在正文输入区域中输入正文内容
intro_input.input(intro)
# 按回车键换行
intro_input.input(Keys.ENTER)
# 等待输入完成
tab.wait(1)
# 查找并点击工具栏中的图片上传按钮
uplload_img_btn = tab("tag:button@aria-label=图片", timeout=10)
# 点击图片上传按钮
uplload_img_btn.click()
# 等待按钮响应
tab.wait(1)
# 设置要上传的图片文件路径,多个路径用换行符分隔
tab.set.upload_files("\n".join(img_paths))
# 查找图片上传确认按钮
img_btn = tab("tag:div@class:css-8x20s2", timeout=10)
# 点击图片上传确认按钮
img_btn.click()
# 等待图片上传完成
tab.wait(3)
# 查找图片上传完成后的确认按钮
img_btn = tab("tag:button@class:css-owamhi", timeout=10)
# 点击图片上传完成确认按钮
img_btn.click()
# 等待按钮响应
tab.wait(1)
# 查找发布按钮
publish_btn = tab("tag:button@text()=发布", timeout=30)
# 点击发布按钮
publish_btn.click()
# 等待发布完成
tab.wait(3)
# 记录发布成功的日志信息
logger.info("知乎专栏上传成功~~")
# 测试函数调用,传入测试用的标题、正文和图片路径
#post_to_zhihu(
# title="标题标题标题标题标题标题",
# intro="正文正文正文正文正文正文",
# img_paths=[
# "D:/aprepare/douyintools3/images/1_jiuming_shanxicuimitaobaozhiwuhe_cuitianfengshen_no_watermark.jpg"
# ],
#)
15.2. main.py #
main.py
# 导入日志记录器,用于记录程序运行过程中的各种信息
from common import get_logger
# 导入抖音相关工具函数,包括爬取视频和提取音频功能
from douyin_utils import crawl_douyin_videos, extract_audio
# 导入腾讯云对象存储上传工具函数
from cos_utils import upload_to_cos
# 导入语音识别工具函数,用于将音频转换为文字
from asr_utils import audio_to_text
# 导入抖音文案转小红书文案工具函数
from xhs_utils import douyin_to_xhs_text
+from zhihu_publisher import post_to_zhihu
# 为当前模块创建专用的日志记录器实例
logger = get_logger(__name__)
# 导入根据文案生成图片工具函数
from image_utils import generate_images_by_text
# 导入图片生成配置参数
from config import IMAGE_NUM_DEFAULT
# 导入发布小红书工具函数
from xhs_publisher import post_to_xiaohongshu
# 定义程序的主入口函数
def main():
# 在程序开始时记录一条信息日志,表示主流程已启动
logger.info("主流程开始")
try:
# 1.使用关键词"脆桃"爬取抖音热门视频,返回视频文件列表
video_files = crawl_douyin_videos("脆桃")
# 遍历每个爬取到的视频文件进行处理
for video_file in video_files:
# 记录当前正在处理的视频文件名称
logger.info(f"处理视频文件: {video_file}")
# 2.将视频文件转换为MP3音频格式
mp3_file = extract_audio(video_file)
# 检查音频转换是否成功,如果失败则跳过当前文件
if not mp3_file:
# 记录警告日志,表示音频转换失败
logger.warning(f"视频转音频失败,跳过: {video_file}")
# 跳过当前文件,继续处理下一个
continue
# 3.将转换后的音频文件上传到腾讯云对象存储
cos_url = upload_to_cos(mp3_file)
# 记录上传成功的日志信息,包含返回的云存储URL
logger.info(f"上传音频到腾讯云成功: {cos_url}")
# 4.使用语音识别服务将音频转换为文字内容
douyin_text = audio_to_text(cos_url)
# 记录语音识别成功的日志信息,包含识别出的文字内容
logger.info(f"音频转文字成功: {douyin_text}")
# 检查语音识别是否成功,如果失败则跳过当前文件
if not douyin_text:
# 记录警告日志,表示语音识别失败
logger.warning(f"音频转文字失败,跳过: {mp3_file}")
# 跳过当前文件,继续处理下一个
continue
# 5.抖音文案转小红书文案
xhs_title, xhs_intro, xhs_tags = douyin_to_xhs_text(douyin_text)
logger.info(
f"抖音文案转小红书文案成功: {xhs_title}, {xhs_intro}, {xhs_tags}"
)
# 6. 根据文案生成图片
img_paths = generate_images_by_text(
xhs_title, xhs_intro, num_images=IMAGE_NUM_DEFAULT
)
logger.info(f"根据文案生成图片成功: {img_paths}")
# 7. 自动发到小红书
post_to_xiaohongshu(
title=xhs_title, intro=xhs_intro, tags=xhs_tags, img_paths=img_paths
)
# 8. 自动发到知乎
+ post_to_zhihu(
+ title=xhs_title, intro=xhs_intro, tags=xhs_tags, img_paths=img_paths
+ )
except Exception as e:
# 捕获并记录主流程执行过程中的任何异常错误
logger.error(f"主流程执行出错: {e}")
# 检查当前脚本是否作为主程序直接运行(而不是被其他模块导入)
if __name__ == "__main__":
# 如果作为主程序运行,则调用主函数开始执行
main()
16.作业 #
本节为进阶任务,鼓励你尝试多平台发布和用数据库管理内容,提升项目的实用性和可扩展性。
1.增加把此内容发布到今日头条或百度百家号等任意一个平台
2.把相关的内容存入数据库,数据库表名为media,表结构可以参考以下内容:
表结构设计说明
- 每一步的产物(视频、音频、文本、图片、发布)都单独建表,方便追踪和溯源。
- 通过外键关联,保证数据的完整性和可追溯性。
- 发布记录表可记录每次自动发文的结果,便于后续统计和异常排查。
- 标签建议用英文逗号分隔,方便后续检索和处理。
1. 视频信息表(douyin_videos)
| 字段名 | 类型 | 说明 |
|---|---|---|
| id | BIGINT PRIMARY KEY AUTO_INCREMENT | 主键 |
| video_path | VARCHAR(255) | 视频本地路径 |
| title | VARCHAR(255) | 视频标题 |
| create_time | DATETIME | 下载时间 |
2. 音频信息表(audio_files)
| 字段名 | 类型 | 说明 |
|---|---|---|
| id | BIGINT PRIMARY KEY AUTO_INCREMENT | 主键 |
| video_id | BIGINT | 外键,关联视频 |
| audio_path | VARCHAR(255) | 音频本地路径 |
| cos_url | VARCHAR(255) | 腾讯云COS地址 |
| create_time | DATETIME | 创建时间 |
3. 文本内容表(text_contents)
| 字段名 | 类型 | 说明 |
|---|---|---|
| id | BIGINT PRIMARY KEY AUTO_INCREMENT | 主键 |
| audio_id | BIGINT | 外键,关联音频 |
| raw_text | TEXT | 原始识别文本 |
| xhs_title | VARCHAR(100) | 小红书标题 |
| xhs_intro | TEXT | 小红书正文 |
| xhs_tags | VARCHAR(255) | 小红书标签(逗号分隔) |
| create_time | DATETIME | 创建时间 |
4. 图片信息表(images)
| 字段名 | 类型 | 说明 |
|---|---|---|
| id | BIGINT PRIMARY KEY AUTO_INCREMENT | 主键 |
| text_id | BIGINT | 外键,关联文本内容 |
| image_path | VARCHAR(255) | 图片本地路径 |
| create_time | DATETIME | 创建时间 |
5. 发布记录表(publish_records)
| 字段名 | 类型 | 说明 |
|---|---|---|
| id | BIGINT PRIMARY KEY AUTO_INCREMENT | 主键 |
| text_id | BIGINT | 外键,关联文本内容 |
| platform | VARCHAR(50) | 平台(如"知乎"、"小红书") |
| status | VARCHAR(20) | 发布状态(成功/失败) |
| publish_time | DATETIME | 发布时间 |
| extra_info | TEXT | 额外信息(如返回的链接、错误信息等) |