测试文件是否通过URL可用的最佳方式



我正在写一个脚本,从各个节目主持人那里下载整个BBC播客集。我的脚本使用BS4、机械化和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",则机械化抛出和异常,因此进行异常处理)。

main()中,我基本上是在这个函数上循环传递我用BS4抓取的URL列表中的一些URL。当函数返回True时,我继续下载带有wget的MP3。

但是。我的问题是:

  • URL是指向遥控器上播客MP3文件的直接路径服务器和我注意到,当URL可用时,br.open(<URL>)将挂起。我怀疑这是因为机械化从服务器缓存/下载实际数据。我不想这是因为如果响应代码为"200"。我怎么能不缓存/DL,只测试响应代码呢

我试过使用br.open_novisit(url, data=None),但挂起的问题仍然存在。。。

我认为没有什么好方法可以让机械化做你想做的事。机械化的全部意义在于,它试图模拟浏览器访问URL,而浏览器访问URL会下载页面。如果你不想这样做,就不要使用为之设计的API。

除此之外,无论您使用什么API,通过发送对URL的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是可获取的,它将获取URL;否则,它会给你一个错误——就像机械化一样容易。这样就避免了对每个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,而不仅仅是记下哪些URL是有效的,只需将任务函数更改为从GET获取和保存数据,而不是执行HEAD操作。文档中的ThreadPoolExecutor示例几乎完全符合您的要求。

最新更新