欢迎光临
我们一直在努力

Python打造智能天气语音播报系统

 

📌 引言

想不想让你的电脑每天自动播报天气预报?用Python调用高德地图天气API获取实时数据,再通过百度语音合成把它“念”出来,最后用PyAudio播放——这就是一个完整的信息获取→处理→输出的物联网小项目。 本教程将从零开始,手把手教你完成:(我会把我的代码放到最后面)

  • 🔑 注册并获取高德地图与百度智能云API密钥

  • 📡 调用高德天气API获取实时天气

  • 🎤 用百度语音合成API把文字转成语音(POST请求,PCM格式)

  • 🔐 实践中理解hashlib(MD5)和base64编码

  • 🎵 给PCM裸数据添加WAV头,转为播放器可直接打开的wav文件

  • 🔊 使用PyAudio播放生成的天气语音

 


🧰 环境与工具准备

首先确保你的电脑已安装Python(推荐3.7+),然后安装以下第三方库:

bash

pip install requests pyaudio wave

  • requests:发送HTTP请求

  • pyaudio:跨平台音频播放(底层基于PortAudio)

  • wave、struct:Python内置,无需安装,用于WAV文件处理


🔑 第一步:获取API密钥

1. 高德开放平台

  • 访问 高德开放平台 注册并登录

  • 进入控制台 → 应用管理 → 创建新应用

  • 添加Key,服务平台选择 Web服务,即可获取一个API Key(示例代码中的 AMAP_KEY)

点击设置:

把这些配置好往下滑点击提交即可,这样我们就创建好了

  • 天气查询的城市编码可参考 高德城市编码表 ,例如喀什地区编码为 653100

https://lbs.amap.com/api/webservice/guide/api/weatherinfo(这个是相关的api文档网址)

城市编码的获取方式:

 

 

2. 百度智能云

  • 前往 百度智能云控制台 注册并登录

  • 创建应用:在产品服务中找到 语音技术 → 创建应用,勾选“语音合成”

  • 应用创建后你会获得 API Key 和 Secret Key(即示例中的 BAIDU_API_KEY 和 BAIDU_SECRET_KEY)

 


🌤️ 第二步:获取实时天气(高德天气API详解)

高德天气API的调用非常简单,是一个HTTP GET请求。(这个前面说过了)

接口说明

  • 接口地址:https://restapi.amap.com/v3/weather/weatherInfo

  • 请求方式:GET

  • 参数:

    • city:城市编码(如653100)

    • key:你的高德API Key

    • extensions:base返回实时天气,all返回预报,这里用base

代码实现

python

def get_weather():
weather_url = "https://restapi.amap.com/v3/weather/weatherInfo"
params = {
"city": CITY_CODE,
"key": AMAP_KEY,
"extensions": "base"
}
resp = requests.get(weather_url, params=params)
data = resp.json()

if data.get("status") != "1":
raise Exception(f"天气API错误: {data}")

live = data["lives"][0]
city = live["city"]
weather = live["weather"]
temperature = live["temperature"]
wind_direction = live["winddirection"]
wind_power = live["windpower"]
humidity = live.get("humidity", "未知")

text = (f"{city}当前天气{weather},温度{temperature}摄氏度,"
f"{wind_direction}风{wind_power}级,空气湿度{humidity}%。")
return text

返回的 text 就是我们后续要合成语音的播报内容,例如: “喀什地区当前天气晴,温度25摄氏度,西北风3级,空气湿度40%。”


🤖 第三步:百度语音合成——从文字到声音

百度语音合成采用 OAuth 2.0 客户端模式 鉴权,需要先拿 access_token,再调用合成接口。这恰好是我们学习 POST、hashlib、base64 的好机会。

3.1 获取 access_token

 

 

接口详情:

  • 地址:https://aip.baidubce.com/oauth/2.0/token

  • 方式:POST

  • 参数:

    • grant_type:固定为 client_credentials

    • client_id:即百度API Key

    • client_secret:即百度Secret Key

python

def get_baidu_access_token():
token_url = "https://aip.baidubce.com/oauth/2.0/token"
params = {
"grant_type": "client_credentials",
"client_id": BAIDU_API_KEY,
"client_secret": BAIDU_SECRET_KEY
}
resp = requests.post(token_url, params=params)
token_data = resp.json()
if "access_token" not in token_data:
raise Exception(f"获取token失败: {token_data}")
# 知识点演示:base64编码
token_base64 = base64.b64encode(token_data["access_token"].encode()).decode()
print("base64示例:", token_base64[:50])
return token_data["access_token"]

这里我们故意把 access_token 做了 base64 编码输出,让你直观感受编码过程(实际上API无需此步骤,仅为教学展示)。base64 是一种用64个字符表示二进制数据的方法,常用于网络传输。

3.2 文本转语音(POST请求)

  • 合成接口:https://tsn.baidu.com/text2audio

  • 方式:POST,表单提交(Content-Type: application/x-www-form-urlencoded)

  • 必填参数:

    • tex:要合成的文本(需UTF-8编码)

    • tok:上一步获取的 access_token

    • cuid:用户唯一标识,随便填一个字符串

    • ctp:客户端类型,固定1(web端)

    • lan:语言,中文填 zh

  • 可选调优参数:

    • per:发音人,4=度丫丫(可爱女声),0/1为普通女/男声

    • spd:语速0-9,5为中速

    • pit:音调0-9,5正常

    • vol:音量0-15,9较大

    • format:返回格式,我们填 pcm 以便演示转换

代码中,我们还顺便展示了 hashlib.md5 的使用,计算播报文本的MD5摘要,增加趣味性。

python

def text_to_speech(text, access_token):
# MD5演示
text_md5 = hashlib.md5(text.encode('utf-8')).hexdigest()
print("文本MD5:", text_md5)

data = {
"tex": text,
"lan": "zh",
"ctp": "1",
"tok": access_token,
"cuid": "PythonClient_Weather",
"per": "4",
"spd": "5",
"vol": "9",
"pit": "5",
"format": "pcm"
}
resp = requests.post(TTS_URL, data=data)
# 如果返回JSON说明出错
if resp.headers.get('Content-Type', '').startswith('application/json'):
error_info = resp.json()
raise Exception(f"语音合成错误: {error_info}")
audio_data = resp.content
return audio_data

成功调用后,audio_data 就是纯PCM音频的二进制数据,无文件头,不能直接双击播放。


🎚️ 第四步:PCM转WAV(深入理解WAV文件头)

PCM(脉冲编码调制)是纯粹的音频采样数据,缺少描述采样率、声道数等元信息的文件头。而WAV格式就是在PCM数据前加一个44字节的标准头,结构如下:

偏移字段大小说明
0 ChunkID 4 “RIFF”
4 ChunkSize 4 文件总长-8
8 Format 4 “WAVE”
12 Subchunk1ID 4 “fmt ”
16 Subchunk1Size 4 16 (PCM)
20 AudioFormat 2 1 = PCM
22 NumChannels 2 声道数,1为单声道
24 SampleRate 4 采样率,百度默认16000
28 ByteRate 4 每秒字节数
32 BlockAlign 2 每个采样帧的字节数
34 BitsPerSample 2 位深度,16bit→2字节
36 Subchunk2ID 4 “data”
40 Subchunk2Size 4 实际音频数据长度
44 data   PCM数据

我们用 struct.pack 按小端格式将这些值打包写入文件即可。

python

def pcm_to_wav(pcm_data, wav_path, sample_rate=16000, channels=1, sample_width=2):
num_samples = len(pcm_data) // sample_width
byte_rate = sample_rate * channels * sample_width
block_align = channels * sample_width

with open(wav_path, 'wb') as f:
f.write(b'RIFF')
f.write(struct.pack('<I', 36 + len(pcm_data))) # ChunkSize
f.write(b'WAVE')
f.write(b'fmt ')
f.write(struct.pack('<I', 16)) # Subchunk1Size
f.write(struct.pack('<H', 1)) # PCM format
f.write(struct.pack('<H', channels))
f.write(struct.pack('<I', sample_rate))
f.write(struct.pack('<I', byte_rate))
f.write(struct.pack('<H', block_align))
f.write(struct.pack('<H', sample_width * 8))
f.write(b'data')
f.write(struct.pack('<I', len(pcm_data)))
f.write(pcm_data)

生成的WAV文件可以用任何音乐播放器打开,甚至能直接拖进剪辑软件。


🔊 第五步:PyAudio播放语音

pyaudio 库使用起来非常简单:

  • 用 wave.open 读取WAV文件,获取参数(声道数、采样宽度、帧速率)

  • 用 pyaudio.PyAudio() 实例化一个音频对象

  • 打开一个输出流,设定格式与WAV一致

  • 循环读出音频帧并写入流

  • 关闭流并终止PyAudio

  • python

    def play_wav(wav_path):
    wf = wave.open(wav_path, 'rb')
    p = pyaudio.PyAudio()
    stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
    channels=wf.getnchannels(),
    rate=wf.getframerate(),
    output=True)
    data = wf.readframes(1024)
    while data:
    stream.write(data)
    data = wf.readframes(1024)
    stream.stop_stream()
    stream.close()
    p.terminate()
    wf.close()


    🧩 完整主流程串联

    python

    def main():
    text = get_weather() # 1.获取天气文本
    token = get_baidu_access_token() # 2.拿token
    pcm_audio = text_to_speech(text, token) # 3.文本→PCM
    with open(SAVE_PCM_PATH, 'wb') as f:
    f.write(pcm_audio) # 保存原始PCM(学习用)
    pcm_to_wav(pcm_audio, SAVE_WAV_PATH) # 4.PCM→WAV
    play_wav(SAVE_WAV_PATH) # 5.播放

    运行后,你就能听到用甜美的度丫丫语音播报的真实天气了!全程仅需几秒,还自动生成了PCM和WAV文件。

     

     

    下面我给你们提供我的完整的代码:

    # -*- coding: utf-8 -*-
    """
    实时天气播报(使用高德地图 + 百度语音合成)
    实现功能:
    1. 获取实时天气数据(地区、温度、湿度、风力、天气状况等)
    2. 使用百度语音合成API,采用POST请求,获取PCM音频数据
    3. 演示hashlib(MD5)和base64编码概念
    4. PCM转WAV文件(添加WAV头)
    5. 使用pyaudio库播放合成语音
    6. 保存音频文件
    """

    import requests
    import json
    import hashlib
    import base64
    import time
    import pyaudio
    import wave
    import struct
    from datetime import datetime

    # ====================== 配置 ======================
    AMAP_KEY = "2a151bfbe125ff1eb35167690125a672" # 高德地图API Key
    CITY_CODE = "653100" # 喀什地区编码
    SAVE_PCM_PATH = r"F:\\物联网媒体技术\\保存录音文件\\喀什天气播报.pcm"#文件保存路径填写实时路径
    SAVE_WAV_PATH = r"F:\\物联网媒体技术\\保存录音文件\\喀什天气播报.wav"#文件保存路径填写实时路径

    BAIDU_API_KEY = "5djvuCHLL5Sa3Rb1RwsYap7b" # 百度API Key
    BAIDU_SECRET_KEY = "aTEYYHQVGJdlSMc8BsVenYHleGBTw8Nh" # 百度Secret Key

    # 百度语音合成参数
    TTS_URL = "https://tsn.baidu.com/text2audio"
    # ==================================================

    def get_weather():
    """
    步骤1:使用高德地图API获取实时天气数据
    原理:发送HTTP GET请求,参数包含城市编码和API Key,返回JSON格式天气信息
    知识点:requests库、JSON解析、HTTP GET请求
    """
    weather_url = "https://restapi.amap.com/v3/weather/weatherInfo"
    params = {
    "city": CITY_CODE,
    "key": AMAP_KEY,
    "extensions": "base" # base表示实时天气,all表示天气预报
    }
    resp = requests.get(weather_url, params=params)
    data = resp.json()

    if data.get("status") != "1":
    raise Exception(f"天气API错误: {data}")

    live = data["lives"][0]
    # 提取所需信息:城市、天气、温度、风向、风力、湿度(高德返回的湿度字段为humidity)
    city = live["city"]
    weather = live["weather"]
    temperature = live["temperature"]
    wind_direction = live["winddirection"]
    wind_power = live["windpower"]
    humidity = live.get("humidity", "未知") # 有些版本可能没有湿度

    # 构造播报文本
    text = (f"{city}当前天气{weather},温度{temperature}摄氏度,"
    f"{wind_direction}风{wind_power}级,空气湿度{humidity}%。")

    print("✅ 天气数据获取成功")
    print(f"📅 当前时间戳: {int(time.time())} (秒) | {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    print(f"📢 播报内容:{text}")
    return text

    def get_baidu_access_token():
    """
    步骤2:获取百度API访问令牌(access_token)
    原理:使用client_credentials授权模式,通过API Key和Secret Key换取token
    知识点:OAuth 2.0 客户端凭证模式、POST请求
    """
    token_url = "https://aip.baidubce.com/oauth/2.0/token"
    params = {
    "grant_type": "client_credentials",
    "client_id": BAIDU_API_KEY,
    "client_secret": BAIDU_SECRET_KEY
    }
    resp = requests.post(token_url, params=params) # 使用POST方法(符合实验要求)
    token_data = resp.json()

    if "access_token" not in token_data:
    raise Exception(f"获取token失败: {token_data}")

    print("✅ 已获取百度access_token")
    # 演示base64编码:将access_token进行base64编码(知识点展示)
    token_base64 = base64.b64encode(token_data["access_token"].encode()).decode()
    print("🔐 演示base64编码(access_token编码后前50字符):", token_base64[:50], "…")
    return token_data["access_token"]

    def text_to_speech(text, access_token):
    """
    步骤3:调用百度语音合成API,获取PCM音频数据(POST请求)
    参数说明:
    tex: 要合成的文本
    lan: 语言,zh中文
    ctp: 客户端类型,1为web端
    tok: access_token
    cuid: 用户标识(可自定义)
    per: 发音人选择,4=度丫丫
    spd: 语速,0-9,5为中速
    vol: 音量,0-15,9为较大
    pit: 音调,0-9,5为正常
    format: 音频格式,pcm(便于后续演示PCM转WAV)
    其他参数参考百度文档
    知识点:HTTP POST请求、application/x-www-form-urlencoded编码、音频二进制数据处理
    """
    # 演示hashlib MD5:计算文本的MD5值(知识点展示)
    text_md5 = hashlib.md5(text.encode('utf-8')).hexdigest()
    print("🔐 演示MD5编码(播报文本的MD5值):", text_md5)

    # 请求参数(使用POST方式,需放在data中)
    data = {
    "tex": text,
    "lan": "zh",
    "ctp": "1",
    "tok": access_token,
    "cuid": "PythonClient_Weather",
    "per": "4", # 度丫丫(可爱女声)
    "spd": "5",
    "vol": "9",
    "pit": "5",
    "format": "pcm" # 返回原始PCM数据,便于演示格式转换
    }

    # 发送POST请求,Content-Type默认application/x-www-form-urlencoded
    resp = requests.post(TTS_URL, data=data)

    # 检查返回内容:如果content-type包含json说明有错误
    if resp.headers.get('Content-Type', '').startswith('application/json'):
    error_info = resp.json()
    raise Exception(f"语音合成API错误: {error_info}")

    # 正常情况返回二进制音频数据
    audio_data = resp.content
    print(f"✅ 语音合成成功,获取到 {len(audio_data)} 字节的PCM数据")
    return audio_data

    def pcm_to_wav(pcm_data, wav_path, sample_rate=16000, channels=1, sample_width=2):
    """
    步骤4:将PCM原始数据转换为WAV文件(添加WAV头)
    原理:WAV文件是RIFF格式,包含文件头(44字节)描述采样率、位深度、声道数等信息。
    PCM是纯音频数据,需加上头才能被常见播放器识别。
    知识点:WAV文件结构、struct.pack打包二进制头、字节操作

    参数:
    pcm_data: bytes, PCM原始音频数据
    wav_path: 输出WAV文件路径
    sample_rate: 采样率(百度默认16000)
    channels: 声道数(百度默认1)
    sample_width: 采样位宽(字节数,2表示16位)
    """
    num_samples = len(pcm_data) // sample_width
    byte_rate = sample_rate * channels * sample_width
    block_align = channels * sample_width

    with open(wav_path, 'wb') as wav_file:
    # RIFF头
    wav_file.write(b'RIFF')
    wav_file.write(struct.pack('<I', 36 + len(pcm_data))) # 文件总长度-8
    wav_file.write(b'WAVE')
    # fmt子块
    wav_file.write(b'fmt ')
    wav_file.write(struct.pack('<I', 16)) # fmt块长度(16字节)
    wav_file.write(struct.pack('<H', 1)) # 音频格式(1=PCM)
    wav_file.write(struct.pack('<H', channels))
    wav_file.write(struct.pack('<I', sample_rate))
    wav_file.write(struct.pack('<I', byte_rate))
    wav_file.write(struct.pack('<H', block_align))
    wav_file.write(struct.pack('<H', sample_width * 8))
    # data子块
    wav_file.write(b'data')
    wav_file.write(struct.pack('<I', len(pcm_data)))
    wav_file.write(pcm_data)

    print(f"✅ PCM已转换为WAV文件:{wav_path}")

    def play_wav(wav_path):
    """
    步骤5:使用pyaudio库播放WAV文件
    原理:pyaudio基于PortAudio,提供跨平台的音频I/O。先读取WAV文件头获取参数,
    然后打开音频流,分块写入数据。
    知识点:pyaudio.open、流操作、回调函数或阻塞式写入
    """
    # 打开WAV文件获取参数
    wf = wave.open(wav_path, 'rb')

    # 初始化pyaudio
    p = pyaudio.PyAudio()

    # 打开音频流
    stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
    channels=wf.getnchannels(),
    rate=wf.getframerate(),
    output=True)

    # 读取数据并播放
    chunk_size = 1024
    data = wf.readframes(chunk_size)
    while data:
    stream.write(data)
    data = wf.readframes(chunk_size)

    # 停止并关闭流
    stream.stop_stream()
    stream.close()
    p.terminate()
    wf.close()
    print("✅ 语音播放完成")

    def main():
    """
    主函数:按实验步骤依次执行
    """
    print("=" * 50)
    print("开始实时天气播报程序")
    print("=" * 50)

    try:
    # 第一步:获取天气数据并构造播报文本
    text = get_weather()

    # 第二步:获取百度access_token
    token = get_baidu_access_token()

    # 第三步:语音合成获取PCM音频数据
    pcm_audio = text_to_speech(text, token)

    # 第四步:保存PCM文件(可选,便于调试)
    with open(SAVE_PCM_PATH, 'wb') as f:
    f.write(pcm_audio)
    print(f"💾 PCM文件已保存:{SAVE_PCM_PATH}")

    # 第五步:将PCM转换为WAV格式(满足操作要点“PCM文件和wav文件的转换”)
    pcm_to_wav(pcm_audio, SAVE_WAV_PATH)

    # 第六步:播放WAV音频文件(实现天气播报)
    print("🔊 正在播放天气播报…")
    play_wav(SAVE_WAV_PATH)

    print("🎉 所有步骤执行成功!")

    except Exception as e:
    print(f"❌ 程序出错:{e}")

    if __name__ == "__main__":
    main()

     

     

    赞(0)
    未经允许不得转载:171主机测评 » Python打造智能天气语音播报系统
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址