测试文件是否可通过URL获得的最佳方法?

时间:2013-11-28 23:37:19

标签: python mechanize-python

我正在为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字符串传递给它。它返回TrueFalse,具体取决于响应是'404'还是'200'(实际上,如果它不是'200',那么Mechanize会抛出异常,因此Exception处理)。

main()中我基本上循环遍历此函数,从我用BS4抓取的URL列表中传递了许多URL。当函数返回True时,我继续使用wget下载MP3。

然而。我的问题是:

  • 网址是遥控器上播客MP3文件的直接路径 服务器,我注意到当URL可用时, br.open(<URL>)会挂起。我怀疑这是因为Mechanize是 从服务器缓存/下载实际数据。我不想 这是因为如果响应代码是,我只想返回True '200'。我怎么能不缓存/ DL并只测试响应代码?

我已尝试使用br.open_novisit(url, data=None),但挂起仍然存在......

1 个答案:

答案 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几乎完全符合您的要求。