Qwen3-ASR-1.7B语音识别实战:基于Python爬虫的音频数据采集与处理

最近在做一个语音分析的项目,需要处理大量来自网络的音频数据。手动下载、转格式、再识别,这个流程想想就头大。后来发现,把Python爬虫和Qwen3-ASR-1.7B这个语音识别模型结合起来,能实现一条龙的自动化处理,效率提升不是一点半点。

如果你也遇到过类似情况,比如想分析播客内容、整理会议录音,或者做语音数据的研究,这套方法应该能帮上忙。它核心就三步:用爬虫把网上的音频文件抓下来,统一转换成模型能吃的格式,最后批量扔给模型去识别成文字。整个过程写个脚本就能跑起来,特别适合处理成百上千个文件。

接下来,我就带你走一遍这个实战流程,从环境搭建到最终出结果,保证你能跟着做出来。

1. 项目准备与环境搭建

工欲善其事,必先利其器。咱们先把需要的工具和库准备好。

1.1 核心工具选择

这个项目主要用到两类工具:

  • 数据采集端:Python爬虫。我们选择 requests 库来下载文件,用 BeautifulSoup 来解析网页,找到音频文件的链接。这两个库用起来简单直接,社区资源也丰富。
  • 语音识别端:Qwen3-ASR-1.7B模型。这是一个专门为中文场景优化的自动语音识别模型,体积相对小巧(1.7B参数),在保证不错识别率的同时,对硬件要求比较友好,个人电脑也能跑起来。我们将通过 transformers 库来调用它。

1.2 一步步安装依赖

打开你的终端或命令行,创建一个新的项目目录,然后安装必要的Python包。建议先创建一个虚拟环境,避免包版本冲突。

# 创建并激活虚拟环境(以conda为例,你也可以用venv)
conda create -n asr_spider python=3.9
conda activate asr_spider

# 安装核心依赖
pip install requests beautifulsoup4 transformers torch

# 如果需要处理更多音频格式,可以安装ffmpeg和pydub
# 首先确保系统安装了ffmpeg(Ubuntu: sudo apt install ffmpeg, Mac: brew install ffmpeg)
pip install pydub

安装完成后,可以写个简单的测试脚本,看看环境是否正常。

# test_env.py
import requests
from bs4 import BeautifulSoup
import torch
from transformers import pipeline

print(“requests版本:”, requests.__version__)
print(“BeautifulSoup版本:”, BeautifulSoup.__version__)
print(“torch版本:”, torch.__version__)
print(“环境检查通过!”)

运行这个脚本,如果没有报错,说明基础环境OK了。

2. 实战第一步:用Python爬虫抓取音频

假设我们要从一个公开的音频分享网站下载讲座录音。这里的关键是找到网页中音频文件的真实下载地址。

2.1 分析网页与定位音频链接

大多数情况下,音频文件不会直接放在页面的某个链接里,而是通过一个音频播放器来加载。我们需要用浏览器的开发者工具(按F12)查看网络请求,找到那个以 .mp3.wav.m4a 结尾的请求。

找到地址后,爬虫的工作就是模拟这个请求。下面是一个示例函数,用于抓取单个页面的音频。

import requests
from bs4 import BeautifulSoup
import os
import time

def download_audio_from_page(page_url, save_dir=“downloads”):
    “””
    从指定页面下载音频文件。
    Args:
        page_url: 包含音频的网页地址
        save_dir: 本地保存目录
    “””
    headers = {
        ‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36’ 
    }
    
    try:
        # 1. 获取网页内容
        response = requests.get(page_url, headers=headers, timeout=10)
        response.raise_for_status()
        soup = BeautifulSoup(response.content, ‘html.parser’)
        
        # 2. 寻找音频标签 - 这里需要根据目标网站结构调整选择器
        # 常见情况:<audio src=“xxx.mp3”> 或 <a href=“xxx.mp3”>下载</a>
        audio_tag = soup.find(‘audio’)
        if audio_tag and audio_tag.get(‘src’):
            audio_url = audio_tag[‘src’]
        else:
            # 如果不在audio标签里,尝试找包含.mp3等后缀的链接
            for link in soup.find_all(‘a’, href=True):
                href = link[‘href’]
                if href.endswith((‘.mp3’, ‘.wav’, ‘.m4a’, ‘.ogg’)):
                    audio_url = href
                    break
            else:
                print(f”在 {page_url} 中未找到音频链接”)
                return None
        
        # 处理相对路径链接
        if not audio_url.startswith(‘http’):
            from urllib.parse import urljoin
            audio_url = urljoin(page_url, audio_url)
        
        # 3. 下载音频文件
        os.makedirs(save_dir, exist_ok=True)
        # 从链接中提取文件名
        filename = os.path.join(save_dir, audio_url.split(‘/’)[-1].split(‘?’)[0])
        
        print(f”正在下载: {audio_url}“)
        audio_response = requests.get(audio_url, headers=headers, stream=True, timeout=30)
        audio_response.raise_for_status()
        
        with open(filename, ‘wb’) as f:
            for chunk in audio_response.iter_content(chunk_size=8192):
                f.write(chunk)
        
        print(f”下载完成: {filename}“)
        return filename
        
    except Exception as e:
        print(f”处理 {page_url} 时出错: {e}“)
        return None

# 使用示例
if __name__ == “__main__”:
    # 替换成你要抓取的实际页面地址
    test_page = “https://example-audio-site.com/lecture/123”
    downloaded_file = download_audio_from_page(test_page)

2.2 实现批量爬取

单个页面不够,我们通常需要抓取一个列表页下的所有音频。思路是先爬取列表页,解析出每个音频的详情页链接,再逐个调用上面的下载函数。

def batch_download_from_list(list_url, max_items=5):
    “””
    从列表页批量下载音频。
    Args:
        list_url: 音频列表页地址
        max_items: 最大下载数量(用于测试)
    “””
    headers = {‘User-Agent’: ‘Mozilla/5.0 ...’}
    
    try:
        resp = requests.get(list_url, headers=headers)
        soup = BeautifulSoup(resp.content, ‘html.parser’)
        
        # 假设每个音频条目在一个class为‘audio-item’的div里,包含一个到详情页的链接
        # 你需要根据实际网站结构调整选择器
        items = soup.find_all(‘div’, class_=‘audio-item’)[:max_items]
        
        downloaded_files = []
        for item in items:
            link_tag = item.find(‘a’, href=True)
            if link_tag:
                detail_page_url = urljoin(list_url, link_tag[‘href’])
                print(f”\n处理详情页: {detail_page_url}“)
                file_path = download_audio_from_page(detail_page_url)
                if file_path:
                    downloaded_files.append(file_path)
                # 礼貌爬取,避免给服务器太大压力
                time.sleep(1)
        
        print(f”\n批量下载完成,共获取 {len(downloaded_files)} 个文件。”)
        return downloaded_files
        
    except Exception as e:
        print(f”批量下载失败: {e}“)
        return []

跑完这部分,你的 downloads 文件夹里应该就有了一堆原始音频文件。接下来,我们要把它们变成模型认识的格式。

3. 实战第二步:音频预处理与格式统一

从网上抓下来的音频,格式五花八门,采样率也可能不同。Qwen3-ASR模型对输入音频有一定的要求(通常是16kHz采样率的单声道WAV文件),所以预处理这一步不能省。

3.1 用pydub进行格式转换

pydub 库底层依赖 ffmpeg,能非常方便地处理音频格式转换、采样率调整等操作。

from pydub import AudioSegment
import os

def convert_to_wav(input_path, output_dir=“processed_audio”):
    “””
    将任意格式音频文件转换为16kHz单声道WAV格式。
    Args:
        input_path: 输入音频文件路径
        output_dir: 输出目录
    Returns:
        转换后的WAV文件路径
    “””
    os.makedirs(output_dir, exist_ok=True)
    
    # 生成输出文件名
    base_name = os.path.splitext(os.path.basename(input_path))[0]
    output_path = os.path.join(output_dir, f”{base_name}_processed.wav”)
    
    try:
        # 加载音频文件
        audio = AudioSegment.from_file(input_path)
        
        # 统一转换为单声道、16kHz采样率
        audio = audio.set_channels(1)  # 单声道
        audio = audio.set_frame_rate(16000)  # 16kHz
        
        # 导出为WAV格式
        audio.export(output_path, format=“wav”)
        print(f”转换成功: {input_path} -> {output_path}“)
        return output_path
        
    except Exception as e:
        print(f”转换失败 {input_path}: {e}“)
        return None

# 批量处理下载文件夹中的所有音频
def batch_process_audio(input_dir=“downloads”, output_dir=“processed_audio”):
    processed_files = []
    for filename in os.listdir(input_dir):
        if filename.lower().endswith((‘.mp3’, ‘.wav’, ‘.m4a’, ‘.flac’, ‘.ogg’)):
            input_path = os.path.join(input_dir, filename)
            output_path = convert_to_wav(input_path, output_dir)
            if output_path:
                processed_files.append(output_path)
    return processed_files

3.2 处理长音频的拆分问题

语音识别模型通常对单次输入的音频长度有限制。如果遇到很长的讲座录音(比如超过30分钟),直接识别效果可能不好,也容易内存溢出。一个实用的技巧是把长音频切成较短(例如10分钟一段)的片段。

def split_long_audio(input_wav_path, segment_length_ms=600000): # 10分钟 = 600000毫秒
    “””
    将长音频切分为固定长度的片段。
    Args:
        input_wav_path: 输入WAV文件路径
        segment_length_ms: 每个片段的毫秒数
    Returns:
        切分后的音频文件路径列表
    “””
    audio = AudioSegment.from_wav(input_wav_path)
    duration_ms = len(audio)
    base_name = os.path.splitext(os.path.basename(input_wav_path))[0]
    output_dir = os.path.join(os.path.dirname(input_wav_path), “segments”)
    os.makedirs(output_dir, exist_ok=True)
    
    segments = []
    for i, start_ms in enumerate(range(0, duration_ms, segment_length_ms)):
        end_ms = min(start_ms + segment_length_ms, duration_ms)
        segment = audio[start_ms:end_ms]
        segment_path = os.path.join(output_dir, f”{base_name}_part{i+1:03d}.wav”)
        segment.export(segment_path, format=“wav”)
        segments.append(segment_path)
        print(f”切分片段: {segment_path} ({len(segment)/1000:.1f}s)”)
    
    return segments

预处理完成后,我们就得到了一批干净、格式统一的WAV文件,可以喂给模型了。

4. 实战第三步:调用Qwen3-ASR进行批量识别

这是最核心的一步,我们用 transformers 库加载Qwen3-ASR-1.7B模型,对处理好的音频进行识别。

4.1 初始化识别管道

第一次运行时会下载模型,需要一点时间和网络。

from transformers import pipeline
import torch

def init_asr_pipeline(model_name=“Qwen/Qwen3-ASR-1.7B”):
    “””
    初始化语音识别管道。
    Note: 模型较大,首次运行需下载,请保持网络通畅。
    “””
    print(f”正在加载模型 {model_name},首次使用可能需要几分钟下载...”)
    # 根据你的硬件情况,可以决定是否使用GPU
    device = 0 if torch.cuda.is_available() else -1
    try:
        # 创建自动语音识别管道
        asr_pipe = pipeline(
            “automatic-speech-recognition”,
            model=model_name,
            device=device
        )
        print(“模型加载成功!”)
        return asr_pipe
    except Exception as e:
        print(f”模型加载失败: {e}“)
        # 如果网络问题,可以尝试从本地路径加载(如果你提前下载了模型)
        # asr_pipe = pipeline(“automatic-speech-recognition”, model=“./local_qwen_asr_model”)
        return None

4.2 执行批量识别并保存结果

加载好管道后,我们就可以遍历所有处理过的音频文件,进行识别,并把结果保存到文本文件或结构化的数据(如JSON)中。

import json

def batch_transcribe(audio_file_list, asr_pipe, output_json=“transcription_results.json”):
    “””
    批量识别音频文件。
    Args:
        audio_file_list: 音频文件路径列表
        asr_pipe: 初始化好的ASR管道
        output_json: 结果输出文件
    “””
    results = []
    
    for audio_path in audio_file_list:
        print(f”\n识别中: {os.path.basename(audio_path)}“)
        try:
            # 调用模型进行识别
            # generate_kwargs 可以传递一些生成参数,比如beam search的大小
            transcription = asr_pipe(
                audio_path,
                generate_kwargs={“num_beams”: 5}  # 使用束搜索,可能提升准确率
            )
            text = transcription[‘text’].strip()
            
            result = {
                “audio_file”: os.path.basename(audio_path),
                “file_path”: audio_path,
                “transcription”: text,
                “duration”: get_audio_duration(audio_path) # 需要实现这个辅助函数
            }
            results.append(result)
            print(f”识别结果: {text[:100]}...“) # 打印前100字符预览
            
        except Exception as e:
            print(f”识别失败 {audio_path}: {e}“)
            results.append({
                “audio_file”: os.path.basename(audio_path),
                “error”: str(e)
            })
    
    # 将结果保存到JSON文件
    with open(output_json, ‘w’, encoding=‘utf-8’) as f:
        json.dump(results, f, ensure_ascii=False, indent=2)
    print(f”\n所有识别完成!结果已保存至 {output_json}“)
    return results

def get_audio_duration(audio_path):
    “””获取音频文件时长(秒)。“””
    try:
        audio = AudioSegment.from_wav(audio_path)
        return len(audio) / 1000.0  # 毫秒转秒
    except:
        return 0

4.3 串联整个流程

最后,我们写一个主函数,把爬取、处理、识别这三个步骤串起来,形成一个完整的自动化脚本。

def main_pipeline(list_url, max_downloads=3):
    “””
    从音频列表页开始,执行完整的采集、处理、识别流程。
    Args:
        list_url: 起始列表页URL
        max_downloads: 最大下载数量(用于演示)
    “””
    print(“=== 步骤1: 批量下载音频 ===”)
    raw_files = batch_download_from_list(list_url, max_items=max_downloads)
    
    print(“\n=== 步骤2: 音频预处理与格式转换 ===”)
    processed_files = batch_process_audio(“downloads”, “processed_audio”)
    
    # 可选:处理长音频拆分
    final_audio_list = []
    for p_file in processed_files:
        # 如果音频超过15分钟,进行切分
        if get_audio_duration(p_file) > 900:
            segments = split_long_audio(p_file)
            final_audio_list.extend(segments)
        else:
            final_audio_list.append(p_file)
    
    print(f”\n待识别音频文件数: {len(final_audio_list)}“)
    
    print(“\n=== 步骤3: 加载语音识别模型 ===”)
    asr_pipe = init_asr_pipeline()
    if not asr_pipe:
        print(“模型加载失败,流程终止。”)
        return
    
    print(“\n=== 步骤4: 批量语音识别 ===”)
    results = batch_transcribe(final_audio_list, asr_pipe)
    
    print(“\n=== 流程全部完成 ===")
    # 这里可以添加一些简单的结果分析,比如统计总时长、平均识别速度等
    total_duration = sum(r.get(‘duration’, 0) for r in results if ‘duration’ in r)
    print(f”处理音频总时长: {total_duration/60:.2f} 分钟”)
    
# 运行示例(请替换为真实的列表页URL)
if __name__ == “__main__”:
    # 请务必遵守目标网站的robots.txt协议,并用于合法合规的学习研究目的
    target_list_url = “https://example.com/audio-lectures”
    main_pipeline(target_list_url, max_downloads=2)

跑完这个脚本,你会在当前目录下得到一个 transcription_results.json 文件,里面就是所有音频识别出来的文字内容,结构清晰,方便你后续做分析、搜索或者存档。

5. 总结

走完这一整套流程,你会发现,把Python爬虫和Qwen3-ASR模型结合起来,处理网络音频数据其实没那么复杂。爬虫负责把散落在各处的音频资源自动化收集起来,模型则负责把声音转化为可编辑、可分析的文字。这套方法特别适合需要处理大量语音资料的场景,比如媒体内容分析、在线教育课程整理、会议纪要生成等等。

实际用下来,Qwen3-ASR-1.7B在中文语音识别上的表现挺扎实的,对于发音清晰的讲座、播客内容,准确率很有保障。当然,如果音频背景噪音比较大,或者有很重的口音,效果可能会打折扣,这是目前所有语音识别模型都面临的挑战。

有几个小建议给想尝试的朋友:一是爬取数据时一定要有节制,遵守网站的规则,别把别人服务器搞挂了;二是对于非常重要的识别任务,最好能加入一个人工复查的环节,机器识别完再快速过一遍,确保关键信息无误;三是可以尝试把识别后的文本,进一步用大语言模型做摘要、提炼要点,这样数据的价值就被层层挖掘出来了。

希望这个实战指南能帮你打开思路。自动化工具的意义就是把人从重复劳动里解放出来,让我们能更专注于那些真正需要创造力和判断力的工作。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

更多推荐