Python批量下载六级词汇英式发音MP3,打造离线听力库

发布时间:2026/10/12 18:04:49
Python批量下载六级词汇英式发音MP3,打造离线听力库 背单词这件事很多人卡在同一个地方眼睛认识耳朵不认识。翻开词汇书看到ambiguous心里默念一遍觉得自己记住了结果听力里一放出来完全反应不过来是哪个词。这个问题的根源在于我们记单词的时候只调用了视觉通道没有同步建立听觉印象。而六级考试里听力占的分值不低光靠看是远远不够的。所以我就琢磨着做一个小工具用 Python 把六级核心词汇的标准英式发音 MP3 批量抓下来做成一套可以离线听的音频库。这样通勤路上、跑步的时候都能磨耳朵把视觉记忆和听觉记忆绑在一起。这个项目的核心就是给定一个单词列表自动获取每个词的标准英式发音音频文件按规则命名保存到本地。适合有一定 Python 基础、想练听力或者想做类似音频采集工具的人参考。下面我把整个思路、实现细节和踩过的坑完整拆一遍。1. 整体方案设计与技术选型1.1 需求拆解我们到底要做什么先把需求说清楚不然后面选型容易跑偏。这个工具要干的事情拆开来看是这么几步有一份六级词汇列表通常是一个 txt 或者 csv 文件每行一个单词对每个单词去某个提供标准英式发音的在线词典获取音频文件把音频下载到本地用单词名命名方便后续检索和播放处理异常情况单词查不到、网络超时、音频格式不对等等最好能记录进度中断了可以续传不用从头再来。看起来简单但真正动手你会发现难点不在下载这个动作本身而在于音源的选择和批量处理的健壮性。下载一个文件谁都会但要稳定地下载几千个文件还要保证发音是英式而不是美式这就需要一些设计了。1.2 音源选型为什么英式发音这么难搞这是整个项目最关键的一个决策点。市面上提供单词发音的在线词典不少但大部分默认给的是美式发音英式发音要么没有要么藏在另一个字段里。我对比过几个常见的音源说一下各自的坑音源类型英式发音支持稳定性备注综合型在线词典 A有独立字段较高音频地址规律适合批量综合型在线词典 B部分词有中等英式缺失时需回退纯发音接口服务需指定口音参数高有频率限制开源发音数据集完整极高需提前下载体积大我最终选择的是综合型在线词典的英式发音字段这条路子原因是它的音频地址有比较明显的规律而且英式发音是独立存在的不会和美式混在一起。具体来说这类词典的页面里英式发音通常对应一个特定的音频链接链接里往往带有区分口音的标识比如路径里带uk字样。我们要做的就是解析出这个链接然后下载。注意不同词典的页面结构会变所以解析逻辑不能写死。我的做法是把从页面提取英式音频链接封装成一个独立函数将来页面变了只改这一个函数就行。1.3 技术栈选择为什么是 requests BeautifulSoup工具本身不复杂不需要上重型框架。我的选型是这样的requests发 HTTP 请求处理会话、超时、重试都很方便比 urllib 好用太多BeautifulSoup解析 HTML找音频链接。虽然也可以用正则但 HTML 结构一旦复杂正则就是灾难BS4 更稳os / pathlib处理文件路径和目录创建csv / 内置文件读写管理单词列表和进度记录time / random控制请求间隔避免请求过密。有人可能会问为什么不用多线程或者异步来加速我的建议是先别急着上并发。原因有两个一是很多音源对高频请求敏感并发太猛容易被限二是这个任务是一次性的几千个词慢慢跑一两个小时也就完了没必要为了快那几十分钟去引入并发带来的复杂度和风险。等你把单线程版本跑通了确认稳定了再考虑加个线程池也不迟。2. 核心细节解析与实操要点2.1 单词列表的准备与清洗六级词汇列表网上能找到不少版本但质量参差不齐。我拿到的原始列表里有一堆问题有的带音标、有的带词性、有的混进了短语、还有重复项。所以在下载之前必须先清洗。清洗的目标是得到一个干净的单词列表每行一个纯单词。我写了个小脚本处理import re def clean_word_list(raw_path, out_path): seen set() cleaned [] with open(raw_path, r, encodingutf-8) as f: for line in f: line line.strip() if not line: continue # 只保留字母和连字符处理像 well-known 这样的词 word re.sub(r[^a-zA-Z\-], , line.split()[0]) if not word or len(word) 2: continue word_lower word.lower() if word_lower in seen: continue seen.add(word_lower) cleaned.append(word_lower) with open(out_path, w, encodingutf-8) as f: f.write(\n.join(cleaned)) print(f清洗完成共 {len(cleaned)} 个单词)这里有几个细节值得说去重用 set 记录已经处理过的词避免重复下载浪费时间和请求过滤非字母字符音标、词性标记这些都要去掉只留单词本身统一小写避免 Apple 和 apple 被当成两个词保留连字符像 well-known 这种词连字符是单词的一部分不能删。实操心得清洗完一定要人工抽查几十个看看有没有把正常的词误删了。我有一次正则写得太狠把所有带撇号的词比如 dont都截断了结果下载了一堆残缺的词。2.2 音频链接的提取逻辑这是整个项目的技术核心。以我用的那类词典为例页面里英式发音的音频通常长这样一个audio标签或者一个带>import requests from bs4 import BeautifulSoup HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36 } def get_uk_audio_url(word, session): url fhttps://example-dict.com/word/{word} try: resp session.get(url, headersHEADERS, timeout10) resp.raise_for_status() except requests.RequestException as e: print(f[请求失败] {word}: {e}) return None soup BeautifulSoup(resp.text, html.parser) # 找英式发音对应的音频元素 # 具体选择器要根据实际页面结构调整 for audio in soup.find_all(audio): src audio.get(src) or audio.get(data-src) if src and uk in src.lower(): return src # 回退找带 uk 标识的 source 标签 for source in soup.find_all(source): src source.get(src) if src and uk in src.lower(): return src return None这里的关键点在于选择器的定位。不同词典的 HTML 结构不一样你需要打开一个单词页面用浏览器的开发者工具F12去看音频元素到底长什么样。我一般会先手动查几个词确认英式音频的链接特征再写选择器。注意不要用绝对路径的选择器比如div div:nth-child(3) audio这种一旦页面改版就全废了。尽量用带语义的定位比如根据class名或者属性里包含的口音标识来找。2.3 请求频率控制与反爬应对批量请求最怕的就是被限流。我踩过的坑是一开始没加延时跑了几百个词之后请求全部返回异常IP 被临时限制了。后来加了随机延时就稳多了。import time import random def polite_sleep(): # 随机延时 0.5 到 1.5 秒模拟人类浏览节奏 time.sleep(random.uniform(0.5, 1.5))除了延时还有几个技巧复用 session用requests.Session()保持连接比每次新建连接效率高也更像正常浏览器行为设置合理的 User-Agent别用默认的 python-requests容易被识别遇到 429 或 403 要退避不要硬刚等一段时间再试或者直接跳过记录到失败列表。实操心得我一般会把延时设成随机的而不是固定值。固定延时反而容易被识别出是脚本随机延时更自然。另外跑大批量任务最好选在晚上或者周末对目标服务器压力小也不容易触发风控。3. 完整实操流程与核心环节实现3.1 环境准备与依赖安装先把环境搭起来。我用的 Python 3.8依赖就三个pip install requests beautifulsoup4不需要额外的音频处理库因为我们只是下载文件不做转码。如果你后续想统一音频格式或者调整音量可以再装pydub和ffmpeg但那是后话。目录结构我建议这样组织six_level_audio/ ├── words.txt # 清洗后的单词列表 ├── download.py # 主脚本 ├── audio/ # 音频存放目录 │ ├── abandon.mp3 │ ├── ambiguous.mp3 │ └── ... └── progress.txt # 进度记录记录已下载的词3.2 主流程代码实现把前面的模块拼起来主流程大概是这样import os import csv import time import random import requests from bs4 import BeautifulSoup HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36 } AUDIO_DIR audio PROGRESS_FILE progress.txt FAILED_FILE failed.txt def load_progress(): if not os.path.exists(PROGRESS_FILE): return set() with open(PROGRESS_FILE, r, encodingutf-8) as f: return set(line.strip() for line in f if line.strip()) def save_progress(word): with open(PROGRESS_FILE, a, encodingutf-8) as f: f.write(word \n) def save_failed(word, reason): with open(FAILED_FILE, a, encodingutf-8) as f: f.write(f{word}\t{reason}\n) def get_uk_audio_url(word, session): url fhttps://example-dict.com/word/{word} try: resp session.get(url, headersHEADERS, timeout10) resp.raise_for_status() except requests.RequestException as e: return None, str(e) soup BeautifulSoup(resp.text, html.parser) for audio in soup.find_all(audio): src audio.get(src) or audio.get(data-src) if src and uk in src.lower(): return src, None for source in soup.find_all(source): src source.get(src) if src and uk in src.lower(): return src, None return None, no_uk_audio def download_audio(audio_url, word, session): filepath os.path.join(AUDIO_DIR, f{word}.mp3) if os.path.exists(filepath): return True, exists try: resp session.get(audio_url, headersHEADERS, timeout15, streamTrue) resp.raise_for_status() with open(filepath, wb) as f: for chunk in resp.iter_content(chunk_size8192): if chunk: f.write(chunk) return True, None except requests.RequestException as e: return False, str(e) def main(): os.makedirs(AUDIO_DIR, exist_okTrue) done load_progress() session requests.Session() with open(words.txt, r, encodingutf-8) as f: words [line.strip() for line in f if line.strip()] total len(words) for idx, word in enumerate(words, 1): if word in done: continue print(f[{idx}/{total}] 处理: {word}) audio_url, err get_uk_audio_url(word, session) if not audio_url: save_failed(word, err or unknown) print(f 跳过原因: {err}) time.sleep(random.uniform(0.5, 1.5)) continue ok, derr download_audio(audio_url, word, session) if ok: save_progress(word) print(f 完成) else: save_failed(word, derr or download_failed) print(f 下载失败: {derr}) time.sleep(random.uniform(0.5, 1.5)) print(全部处理完毕) if __name__ __main__: main()这段代码有几个设计点值得展开说进度记录机制。用progress.txt记录已经成功下载的词每次启动先加载这个集合已经处理过的直接跳过。这样即使中途断了重跑也不会重复下载。这个设计对于几千个词的任务来说太重要了我一开始没做结果断了一次从头再来白白浪费了一个多小时。失败单独记录。下载失败的词写到failed.txt带上失败原因。跑完之后可以针对这个文件单独重试不用把整个列表再跑一遍。文件存在性检查。download_audio里先判断文件是否已存在存在就直接返回成功。这是双保险防止进度文件丢失时重复下载。3.3 音频文件的命名与校验命名规则我建议直接用单词本身比如abandon.mp3。这样后续想找某个词的发音直接按名字找就行不用维护额外的映射表。但这里有个坑有些单词包含特殊字符比如连字符、撇号直接当文件名在某些系统上会出问题。我的处理是把文件名里的非法字符替换掉import re def safe_filename(word): # 把不适合做文件名的字符替换成下划线 return re.sub(r[\\/:*?|], _, word)下载完之后最好做一次校验确认文件不是空的或者损坏的。最简单的办法是检查文件大小def validate_audio(filepath, min_size1024): if not os.path.exists(filepath): return False return os.path.getsize(filepath) min_size正常的单词发音 MP3 一般有几 KB 到几十 KB如果文件小于 1KB很可能是下载到了错误页面比如 404 页面被保存成了 mp3。我踩过这个坑一开始没校验结果发现有些音频用播放器打不开一看大小只有几百字节其实是错误响应。实操心得批量下载完一定要抽查一批文件用播放器实际听一下确认发音是英式而不是美式也确认音频没有损坏。我抽查的时候发现有几个词的英式音频链接其实指向的是美式这种只能手动标记出来单独处理。4. 常见问题与排查技巧实录4.1 请求被限制怎么办这是批量采集最常见的拦路虎。表现是跑着跑着请求开始大量失败返回 403、429 或者直接超时。排查思路是这样的先确认是不是被限了手动用浏览器访问同一个页面如果正常说明是脚本行为被识别了检查请求头User-Agent 是不是太假有没有缺 Referer 之类的常见头降低频率把延时调大从 0.5 秒调到 2 秒甚至 3 秒换时间段如果还是不行停几个小时再跑。我整理了一个速查表现象可能原因解决方向大量 403请求头被识别完善 User-Agent、加 Referer大量 429频率过高加大延时、加退避逻辑连接超时网络或目标限流重试、换时间返回空页面被重定向到验证页降低频率、检查 session音频链接 404音源本身缺失记录失败后续单独处理4.2 英式发音缺失或错误不是每个词都有英式发音。有些生僻词、专有名词词典里可能只有美式。这种情况我的处理是记录到失败列表不强行用美式替代。因为我们的目标是英式发音混进美式会破坏整个音频库的一致性。还有一种情况是链接里带了uk标识但实际音频是美式。这种只能靠人工抽查发现。我的做法是随机抽 5% 的文件听一遍发现问题的词单独标记。4.3 断点续传与进度丢失前面提到的进度记录机制就是为这个准备的。但有个细节要注意进度写入要及时。我一开始是攒一批再写结果程序崩溃时最后一批的进度丢了。后来改成每成功一个就立即写入虽然多了点 IO但安全。另外progress.txt和audio/目录要配套。如果手动删了音频文件但没删进度记录重跑时会跳过这些词导致缺失。所以要么两个一起清要么在下载前做文件存在性检查我在代码里已经加了。4.4 音频格式与播放兼容性下载下来的文件基本都是 MP3兼容性没问题。但如果你后续想合并成一个长音频或者转成其他格式可能会遇到采样率不一致的问题。不同来源的音频采样率可能不同合并前最好用工具统一一下。如果只是自己听其实不用折腾格式。我建议按字母或者按词频分成几个文件夹每个文件夹几十到一百个词做成一个播放列表这样听起来有节奏感也不会一个文件太长听到崩溃。5. 音频库的后续利用与扩展思路5.1 按主题或词频分组下载完之后一堆 MP3 躺在文件夹里其实不好用。我的做法是按词频或者主题分组。比如把高频词放一个文件夹低频词放另一个或者按字母顺序分。这样每次听的时候目标明确不会漫无目的地听。分组可以用脚本自动做读单词列表按规则移动到对应子目录。这个逻辑很简单就不展开写了。5.2 生成播放列表文件如果用的是本地播放器可以生成一个 m3u 播放列表文件把所有音频路径写进去播放器就能按顺序播放。格式很简单就是每行一个文件路径def generate_m3u(audio_dir, out_file): files sorted(f for f in os.listdir(audio_dir) if f.endswith(.mp3)) with open(out_file, w, encodingutf-8) as f: f.write(#EXTM3U\n) for name in files: f.write(os.path.join(audio_dir, name) \n)这样通勤的时候打开播放器直接加载这个列表就能从头听到尾。5.3 扩展到其他词表或语言这套逻辑其实不限于六级词汇。换成考研词汇、雅思词汇甚至换成其他语言的单词只要目标音源支持改一下单词列表和音源解析逻辑就行。核心的下载、进度管理、失败重试这些模块都是通用的。我后来把这套代码稍微改了改用来抓日语单词的发音只换了音源解析函数其他部分原封不动跑得也很顺。所以这个项目的价值不只是一个六级音频库而是一套可复用的单词发音采集方案。5.4 一个容易被忽略的细节音频去重有些单词在不同词表里重复出现或者同一个词有多个发音版本。下载的时候要注意去重避免同一个词存了好几份。我在清洗阶段就做了去重下载阶段又用文件存在性检查兜底基本不会出现重复。另外有些词形变化比如名词复数和动词第三人称单数发音规则不同如果词表里有这些变形要确认音源给的是不是对应形式的发音。这个比较细一般词表里都是原形问题不大但如果你自己扩展词表就要留意。最后分享一个我自己的使用习惯我一般会把下载好的音频按每 50 个词切成一组每组做成一个播放列表每天早上听一组一周循环一遍。配合着看单词书视觉和听觉一起上记单词的效率确实比单纯看书高不少。这个工具本身不复杂但把获取标准英式发音这件事自动化之后省下来的时间可以真正花在听和记上这才是它最大的价值。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询