urllib批量请求代理异常:单请求正常批量返回404求助
解决Squid代理下urllib批量请求返回404的问题
我来帮你揪出这个问题的根源!
你遇到的核心问题是:处理HTTPS URL时,代理协议设置错误。
看你的代码,不管目标URL是HTTP还是HTTPS,你都固定用req.set_proxy(proxy_host, 'http')来设置代理。但urllib的set_proxy方法第二个参数是用来指定该代理对应哪种请求协议的——如果你的请求目标是HTTPS地址,这个参数必须设为'https',否则urllib不会正确通过Squid代理去请求HTTPS资源,导致请求直接走本地网络(而你的环境强制要求走代理,所以返回404)。
单请求时可能Squid做了兼容处理,侥幸成功了,但批量或多进程请求时,这种协议不匹配的问题就彻底暴露出来了。
给你两个靠谱的修复方案:
方案一:根据URL协议动态匹配代理协议
修改check_url函数,先解析URL的协议部分,再对应设置代理协议:
from multiprocessing import Pool import urllib.error import urllib.request from urllib.parse import urlparse proxy_host = "192.168.1.1:3128" urls = ['https://www.youtube.com/watch?v=XqZsoesa55w', 'https://www.youtube.com/watch?v=GR2o6k8aPlI', 'https://stackoverflow.com/'] def check_url(url): # 解析出URL的协议(http/https) parsed_url = urlparse(url) req = urllib.request.Request( url=url, data=None, headers={'User-Agent': 'Mozilla/5.0'} ) # 按URL协议设置对应的代理协议 req.set_proxy(proxy_host, parsed_url.scheme) try: with urllib.request.urlopen(req) as conn: return conn.getcode() except urllib.error.HTTPError as e: return [str(e), url] except urllib.error.URLError as e: return [str(e), url] except ValueError as e: return [str(e), url] else: return 'Unknown Status!' # 测试循环调用 for url in urls: print(check_url(url)) # 测试多进程调用 p = Pool(processes=20) print(p.map(check_url, urls))
方案二:全局代理处理器(更简洁省心)
直接创建全局的代理处理器,让所有请求自动走代理,不用每个Request单独设置,从根源避免协议匹配错误:
from multiprocessing import Pool import urllib.error import urllib.request proxy_host = "192.168.1.1:3128" urls = ['https://www.youtube.com/watch?v=XqZsoesa55w', 'https://www.youtube.com/watch?v=GR2o6k8aPlI', 'https://stackoverflow.com/'] # 构建代理处理器,同时处理http和https请求 proxy_handler = urllib.request.ProxyHandler({ 'http': f'http://{proxy_host}', 'https': f'http://{proxy_host}' }) # 创建全局opener并安装 opener = urllib.request.build_opener(proxy_handler) urllib.request.install_opener(opener) def check_url(url): req = urllib.request.Request( url=url, data=None, headers={'User-Agent': 'Mozilla/5.0'} ) try: with urllib.request.urlopen(req) as conn: return conn.getcode() except urllib.error.HTTPError as e: return [str(e), url] except urllib.error.URLError as e: return [str(e), url] except ValueError as e: return [str(e), url] else: return 'Unknown Status!' # 测试循环调用 for url in urls: print(check_url(url)) # 测试多进程调用 p = Pool(processes=20) print(p.map(check_url, urls))
这个方案更稳妥,因为它统一处理了HTTP和HTTPS请求的代理配置,而且多进程环境下,每个子进程都会继承全局opener的设置,不会出现冲突问题。
内容的提问来源于stack exchange,提问作者F. JAF
相关产品推荐
相关产品推荐

