摘要:本文介绍如何利用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(

    level=logging.INFO,

    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

版权声明:本文为技术分享文章,代码示例可自由使用。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐