我正在为DL播放来自各个节目主持人的整个BBC播客集。我的脚本使用BS4,Mechanize和wget。
我想知道如何测试URL的请求是否从服务器产生响应代码'404'。我写了以下函数:
def getResponseCode(br, url):
print("Opening: " + url)
try:
response = br.open(url)
print("Response code: " + str(response.code))
return True
except (mechanize.HTTPError, mechanize.URLError) as e:
if isinstance(e,mechanize.HTTPError):
print("Mechanize error: " + str(e.code))
else:
print("Mechanize error: " + str(e.reason.args))
return False
我将Browser()
对象和URL字符串传递给它。它返回True
或False
,具体取决于响应是'404'还是'200'(实际上,如果它不是'200',那么Mechanize会抛出异常,因此Exception处理)。
在main()
中我基本上循环遍历此函数,从我用BS4抓取的URL列表中传递了许多URL。当函数返回True
时,我继续使用wget
下载MP3。
然而。我的问题是:
br.open(<URL>)
会挂起。我怀疑这是因为Mechanize是
从服务器缓存/下载实际数据。我不想
这是因为如果响应代码是,我只想返回True
'200'。我怎么能不缓存/ DL并只测试响应代码?我已尝试使用br.open_novisit(url, data=None)
,但挂起仍然存在......
答案 0 :(得分:1)
我认为没有任何好方法可以让Mechanize做你想做的事。 Mechanize的重点在于它正在尝试模拟访问URL的浏览器,访问URL的浏览器会下载该页面。如果您不想这样做,请不要使用为此设计的API。
除此之外,无论您使用哪种API,通过发送GET
网址请求,您都要求服务器向您发送完整的响应。为什么这样做只是为了尽快挂断它?使用HEAD
请求询问服务器是否可用。 (有时服务器即使应该也不会HEAD
,所以你必须回到GET
。但是如果你来的话,就越过那座桥。)
例如:
req = urllib.request.Request(url, method='HEAD')
resp = urllib.request.urlopen(req)
return 200 <= resp.code < 300
但这提出了一个问题:
当函数返回True时,我继续使用wget下载MP3。
为什么呢?为什么不首先使用wget
?如果URL是gettable,它将获取URL;如果没有,它会给你一个错误 - 就像Mechanize一样容易。这样可以避免两次点击每个URL。
就此而言,为什么要尝试编写wget
脚本,而不是使用stdlib中的内置支持或requests
等第三方模块?
如果您只是想找到一种并行化的方法,那么在Python中很容易做到:
def is_good_url(url):
req = urllib.request.Request(url, method='HEAD')
resp = urllib.request.urlopen(req)
return url, 200 <= resp.code < 300
with futures.ThreadPoolExecutor(max_workers=8) as executor:
fs = [executor.submit(is_good_url, url) for url in urls]
results = (f.result() for f in futures.as_completed(fs))
good_urls = [url for (url, good) in results if good]
要将此更改为实际下载有效的URL而不是仅记录哪些有效,只需将任务功能更改为从GET
获取并保存数据而不是{ {1}}事。文档中的ThreadPoolExecutor
Example几乎完全符合您的要求。