摘要:本文介绍如何利用Python技术栈构建一个自动化数据采集与语音合成系统。系统通过分层架构实现数据获取、内容处理、语音生成和定时推送的全流程自动化,适合需要定时信息播报的技术场景。
关键词:Python自动化、语音合成、Edge TTS、数据抓取、定时任务、FFmpeg音频处理
一、项目概述
1.1 技术背景
在物联网和智能家居场景中,定时语音播报是常见需求:
智能家居的定时语音提醒
服务器监控的语音告警
个人知识库的语音播报
数据看板的定时播报
1.2 技术架构
┌─────────────────────────────────────────────────────────────┐
│ 自动化语音播报系统 │
├──────────────┬──────────────┬──────────────┬────────────────┤
│ 数据采集 │ 内容处理 │ 语音合成 │ 定时调度 │
├──────────────┼──────────────┼──────────────┼────────────────┤
│ • REST API │ • 文本清洗 │ • Edge TTS │ • Cron定时 │
│ • Web爬虫 │ • 模板渲染 │ • 分段合成 │ • 消息队列 │
│ • 数据过滤 │ • 格式转换 │ • FFmpeg合并 │ • 推送接口 │
└──────────────┴──────────────┴──────────────┴────────────────┘
二、核心模块设计
2.1 数据采集层
分层降级策略:
第一层:REST API(官方接口,稳定快速)
↓ 备用方案
第二层:Web页面解析(HTML提取)
↓ 备用方案
第三层:浏览器自动化(Selenium/Playwright)
API数据获取示例:
import requests
from typing import List, Dict
class DataCollector:
"""数据采集器"""
def init(self, api_key: str):
self.api_key = api_key
self.session = requests.Session()
self.session.timeout = 10
def fetch_from_api(self, endpoint: str, params: dict) -> List[Dict]:
"""从REST API获取数据"""
try:
response = self.session.get(endpoint, params=params)
response.raise_for_status()
return response.json().get('data', [])
except requests.RequestException as e:
print(f"API请求失败: {e}")
return []
def filter_by_keywords(self, data: List[Dict],
keywords: List[str]) -> List[Dict]:
"""本地关键词过滤(不调用外部服务)"""
filtered = []
for item in data:
title = item.get('title', '')
if any(kw in title for kw in keywords):
filtered.append(item)
return filtered
关键技术点:
本地过滤避免外部依赖,响应时间<100ms
分层降级保证系统稳定性
类型注解提高代码可维护性
2.2 内容处理层
文本处理管道:
import re
from dataclasses import dataclass
@dataclass
class ContentBlock:
"""内容块数据结构"""
title: str
content: str
category: str
timestamp: str
def clean_text(text: str) -> str:
"""文本清洗:去除HTML标签、特殊字符"""
去除HTML标签
text = re.sub(r'<[^\u003e]+>', '', text)
去除多余空白
text = re.sub(r'\s+', ' ', text)
return text.strip()
def generate_script(blocks: List[ContentBlock]) -> str:
"""基于模板生成播报脚本"""
template = """
自动化播报脚本
{sections}
生成时间:{timestamp}
"""
sections = []
for block in blocks:
section = f"""
{block.title}
{block.content}
来源:{block.category} | {block.timestamp}
"""
sections.append(section)
return template.format(
sections='\n'.join(sections),
timestamp=datetime.now().isoformat()
)
2.3 语音合成层
TTS引擎对比:
方案 优点 缺点 适用场景
Edge TTS 免费、中文效果好 需安装 个人项目
pyttsx3 离线、跨平台 机械音 简单提示
gTTS 免费、Google技术 需联网 英文场景
Azure TTS 专业级 付费 商业项目
Edge TTS实现:
import subprocess
import asyncio
from pathlib import Path
class TTSEngine:
"""语音合成引擎"""
def init(self, voice: str = "zh-CN-XiaoxiaoNeural"):
self.voice = voice
self.output_dir = Path("/tmp/tts_output")
self.output_dir.mkdir(exist_ok=True)
async def synthesize(self, text: str, output_file: str) -> str:
"""异步语音合成"""
cmd = [
"edge-tts",
"--text", text,
"--write-media", output_file,
"--voice", self.voice
]
process = await asyncio.create_subprocess_exec(
*cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE
)
stdout, stderr = await process.communicate()
if process.returncode != 0:
raise RuntimeError(f"TTS失败: {stderr.decode()}")
return output_file
async def synthesize_batch(self, texts: List[str]) -> List[str]:
"""批量并行合成"""
tasks = []
for i, text in enumerate(texts):
output_file = str(self.output_dir / f"segment_{i}.mp3")
task = self.synthesize(text, output_file)
tasks.append(task)
return await asyncio.gather(*tasks)
分段策略(解决长文本限制):
def split_text(text: str, max_length: int = 1500) -> List[str]:
"""将长文本按段落分割"""
paragraphs = text.split('\n\n')
segments = []
current_segment = []
current_length = 0
for para in paragraphs:
if current_length + len(para) > max_length:
segments.append('\n\n'.join(current_segment))
current_segment = [para]
current_length = len(para)
else:
current_segment.append(para)
current_length += len(para)
if current_segment:
segments.append('\n\n'.join(current_segment))
return segments
2.4 音频处理层
FFmpeg合并技术:
import subprocess
from typing import List
def merge_audio_files(files: List[str], output: str) -> str:
"""使用FFmpeg无损合并音频"""
生成合并列表文件
list_file = "/tmp/merge_list.txt"
with open(list_file, 'w') as f:
for file in files:
f.write(f"file '{file}'\n")
FFmpeg命令
cmd = [
"ffmpeg",
"-f", "concat",
"-safe", "0",
"-i", list_file,
"-c", "copy", # 不重新编码,无损合并
"-y", # 覆盖输出文件
output
]
subprocess.run(cmd, check=True, capture_output=True)
return output
音频参数配置:
AUDIO_CONFIG = {
"codec": "libmp3lame",
"bitrate": "48k", # 语音足够,文件小
"sample_rate": 24000, # Edge TTS默认
"channels": 1, # 单声道
"format": "mp3"
}
三、系统实现
3.1 完整工作流
import asyncio
from datetime import datetime
class AutoBroadcastSystem:
"""自动化播报系统"""
def init(self):
self.collector = DataCollector(api_key="xxx")
self.tts = TTSEngine()
self.keywords = ["技术", "开源", "Python"] # 过滤关键词
async def run(self):
"""执行完整流程"""
print(f"[{datetime.now()}] 开始执行...")
1. 数据采集
raw_data = self.collector.fetch_from_api(
endpoint="https://api.example.com/data",
params={"limit": 30}
)
2. 数据过滤
filtered = self.collector.filter_by_keywords(
raw_data, self.keywords
)
3. 内容生成
blocks = [self._create_block(item) for item in filtered]
script = generate_script(blocks)
4. 分段处理
segments = split_text(script, max_length=1500)
5. 语音合成(并行)
audio_files = await self.tts.synthesize_batch(segments)
6. 音频合并
final_audio = merge_audio_files(
audio_files,
output=f"broadcast_{datetime.now():%Y%m%d}.mp3"
)
7. 推送
await self.push(final_audio)
print(f"[{datetime.now()}] 执行完成: {final_audio}")
async def push(self, file_path: str):
"""推送到消息平台"""
实现推送逻辑(Webhook/API)
pass
3.2 定时任务配置
Cron表达式:
每天12:00执行
0 12 * * * cd /project && python3 main.py
OpenClaw定时任务配置:
{
"name": "自动化播报任务",
"schedule": {
"type": "cron",
"expression": "0 12 * * *",
"timezone": "Asia/Shanghai"
},
"action": {
"type": "python",
"script": "/project/main.py"
}
}
四、性能优化
4.1 并行化处理
并行TTS合成(14段同时处理)
async def parallel_synthesis(texts: List[str]) -> List[str]:
semaphore = asyncio.Semaphore(14) # 并发限制
async def bounded_synthesize(text, index):
async with semaphore:
return await tts.synthesize(text, f"part_{index}.mp3")
tasks = [bounded_synthesize(t, i) for i, t in enumerate(texts)]
return await asyncio.gather(*tasks)
4.2 缓存机制
from functools import lru_cache
import hashlib
@lru_cache(maxsize=100)
def get_cached_content(content_hash: str):
"""缓存已生成的内容"""
cache_file = f"/tmp/cache/{content_hash}.mp3"
if Path(cache_file).exists():
return cache_file
return None
def generate_hash(content: str) -> str:
"""生成内容哈希"""
return hashlib.md5(content.encode()).hexdigest()
4.3 性能对比
优化项 优化前 优化后 提升
数据过滤 60s (AI调用) <1s (本地) 60x
TTS合成 14分钟 (串行) 3分钟 (并行) 4.7x
音频合并 60s (重编码) 10s (无损) 6x
总耗时 16分钟 4分钟 4x
五、部署与运维
5.1 环境依赖
requirements.txt
requests>=2.28.0
edge-tts>=6.1.0
ffmpeg-python>=0.2.0
aiohttp>=3.8.0
5.2 Docker部署
FROM python:3.11-slim
RUN apt-get update && apt-get install -y ffmpeg
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["python3", "main.py"]
5.3 监控告警
import logging
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('/var/log/broadcast.log'),
logging.StreamHandler()
]
)
logger = logging.getLogger(name)
关键步骤记录
logger.info("数据采集完成: %d条", len(data))
logger.info("语音合成完成: %s", audio_file)
六、总结
本文介绍了一个完整的自动化数据采集与语音播报系统,核心技术点包括:
分层架构:API→Web→自动化的三级降级策略
本地处理:关键词过滤本地化,零外部依赖
并行优化:TTS分段并行合成,提升4.7倍性能
无损合并:FFmpeg直接合并,避免重编码
定时调度:Cron + 异步IO,资源占用低
适用场景:
智能家居语音提醒
服务器监控告警播报
个人知识库语音化
物联网设备语音提示
技术栈:Python + Edge TTS + FFmpeg + Cron
参考文档:
Edge TTS GitHub: https://github.com/rany2/edge-tts
FFmpeg文档: https://ffmpeg.org/documentation.html
Python asyncio: https://docs.python.org/3/library/asyncio.html
版权声明:本文为技术分享文章,代码示例可自由使用。