程序化下载的MIDI文件无法播放,手动下载正常的问题排查
问题原因分析
从你提供的十六进制dump能一眼看出核心问题——你下载的根本不是MIDI文件,而是网页的HTML代码!程序化下载的文件开头是<!DOCTYPE html>(对应十六进制里的3c 21 44 4f 43 54 59 50),而标准MIDI文件的固定开头是MThd(对应十六进制4d 54 68 64),这就是文件无法播放的直接原因。
你的代码逻辑错误在于:循环访问的base_url + str(i)是列表页面的URL(比如http://www.midiworld.com/files/1),而不是实际的MIDI文件下载链接。你直接把这个页面的HTML内容保存成了.mid文件,自然无法被播放器识别。
解决办法
我们需要先解析每个列表页面,提取出页面内的真实MIDI文件下载链接,再去下载正确的文件。修改后的代码如下:
from bs4 import BeautifulSoup import requests import os import urllib.request base_url = "http://www.midiworld.com/files/" base_path = 'path/where/I/will/save/the/downloaded/MIDI/files' # 确保保存目录存在,不存在则创建 save_dir = os.path.join(base_path, 'MIDI Files') os.makedirs(save_dir, exist_ok=True) os.chdir(save_dir) # 模拟浏览器请求头,避免被网站拦截 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' } for i in range(1, 2386): try: # 请求目标列表页面 page_url = base_url + str(i) response = requests.get(page_url, headers=headers) response.raise_for_status() # 检查请求是否成功,失败则抛出异常 soup = BeautifulSoup(response.text, "html.parser") # 筛选出页面中指向.mid文件的下载链接 midi_links = soup.select("div ul li a[href$='.mid']") if not midi_links: print(f"页面 {i} 未找到有效MIDI链接,跳过") continue # 获取第一个MIDI链接(通常每个页面对应一个MIDI文件) midi_href = midi_links[0]['href'] # 拼接完整的下载URL midi_url = base_url + midi_href if midi_href.startswith('/') else midi_href # 从链接中提取原始文件名,和手动下载的命名保持一致 filename = os.path.basename(midi_href) # 开始下载文件 print(f"正在下载: {filename}") urllib.request.urlretrieve(midi_url, filename) except Exception as e: print(f"处理页面 {i} 时出错: {str(e)}") continue
关键修改点说明
- 提取真实下载链接:通过
soup.select("div ul li a[href$='.mid']")精准筛选出指向MIDI文件的链接,确保下载的是真正的音频文件而非网页。 - 模拟浏览器请求:添加
User-Agent请求头,避免网站把脚本识别为爬虫而拦截请求。 - 合理命名文件:从链接中提取原始文件名,既避免了数字命名的混乱,也和手动下载的文件命名保持一致。
- 异常处理机制:添加
try-except块,处理页面请求失败、链接不存在等异常情况,让脚本运行更稳定。 - 目录预检查:用
os.makedirs(save_dir, exist_ok=True)确保保存目录存在,避免因目录缺失导致的报错。
验证方法
修改后下载的文件,你可以再次检查十六进制开头,应该会以MThd(十六进制4d 54 68 64)开头,和手动下载的文件格式完全一致,此时播放器就能正常识别并播放了。
内容的提问来源于stack exchange,提问作者Kristada673




