0

我正在编写一个脚本来 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 抛出和异常,因此是异常处理)。

main()我基本上循环遍历这个函数,从我用 BS4 抓取的 URL 列表中传入一些 URL。当函数返回时,True我继续下载 MP3 文件wget

然而。我的问题是:

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

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

4

1 回答 1

1

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

最重要的是,无论您使用什么 API,通过发送GET对 URL 的请求,您都是在要求服务器向您发送整个响应。为什么这样做只是为了尽快挂断电话?使用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,而不是仅仅记录哪些是有效的,只需将任务函数更改为从 a 获取和保存数据的东西,GET而不是执行该操作HEAD。文档中的ThreadPoolExecutor示例几乎完全符合您的要求。

于 2013-11-28T23:50:22.090 回答