使用Python urllib.request请求图片时出现HTTP 500错误的原因
问题背景
使用urllib.request测试下载图片时,部分URL可正常工作,但特定的Cloudinary图片URL触发HTTP 500服务器错误,但浏览器输入该URL能正常显示图片。尝试pycurl请求返回空字符串,改用requests编写代码后仍有疑问,需明确错误原因。
用户测试代码:
urllib版本代码
import urllib.request image_url = 'https://cloudinary.images-iherb.com/image/upload/f_auto%2cq_auto:eco/images/sug/sug00972/l/42.jpg' # this is not working. HTTP 500 error # image_url = 'https://m.media-amazon.com/images/I/81Hxz-Y6imL._AC_SL1500_.jpg' # this is working folder_name = '.' savefile = 'test.jpg' opener = urllib.request.build_opener() opener.addheaders = [('User-Agent', 'MyApp/1.0')] urllib.request.install_opener(opener) urllib.request.urlretrieve(image_url, folder_name+"/"+savefile)
requests版本代码
import requests url = 'http://cloudinary.images-iherb.com/image/upload/f_auto%2cq_auto:eco/images/sug/sug00972/l/42.jpg' try: r = requests.get(url, headers={'Referer': 'https://example.com', 'User-Agent': 'Mozilla/5.0', 'Accept': 'image/webp,*/*'}) r.raise_for_status() image_data = r.content except requests.exceptions.RequestException as e: print("Error: %s" % e) image_data = None # Save the image data to a file if image_data: with open('image.jpg', 'wb') as f: f.write(image_data) else: print("No image data was downloaded.")
错误原因分析
请求头不符合服务器校验规则
Cloudinary这类CDN服务会校验请求的User-Agent、Referer等头信息。你用urllib设置的User-Agent: MyApp/1.0过于简单,偏离浏览器标准请求头格式,服务器可能判定为非合法请求返回500;而浏览器会自动发送完整合规的头信息,因此能正常访问。URL协议不匹配
requests代码中使用了http://协议,但原URL是https://,部分服务器对协议不匹配的请求会返回错误,或重定向流程失败触发500。参数编码的潜在解析问题
URL中的f_auto%2cq_auto:eco是逗号的URL编码形式,虽然语法合法,但部分服务器在请求上下文缺失时,可能对这类编码参数解析失败,进而触发服务器内部错误。
解决办法
模拟完整浏览器请求头
复制浏览器真实请求头(可通过F12开发者工具网络面板查看),在代码中完整设置,尤其是User-Agent、Accept、Referer(建议设置为iHerb官网域名,比example.com更符合真实访问场景)。修改后的
urllib示例代码:import urllib.request image_url = 'https://cloudinary.images-iherb.com/image/upload/f_auto%2cq_auto:eco/images/sug/sug00972/l/42.jpg' savefile = './test.jpg' opener = urllib.request.build_opener() # 模拟Chrome浏览器请求头 opener.addheaders = [ ('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36'), ('Accept', 'image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8'), ('Referer', 'https://www.iherb.com/') ] urllib.request.install_opener(opener) urllib.request.urlretrieve(image_url, savefile)统一使用HTTPS协议
确保请求URL使用https://,避免协议不匹配导致的服务器错误。尝试解码URL参数
将URL中的%2c替换为原始逗号(,),直接使用f_auto,q_auto:eco,部分服务器对未编码的参数解析更稳定:image_url = 'https://cloudinary.images-iherb.com/image/upload/f_auto,q_auto:eco/images/sug/sug00972/l/42.jpg'
内容的提问来源于stack exchange,提问作者EUN WOO LEE

