0

さまざまな番組ホストからの BBC ポッドキャストのコレクション全体を DL するためのスクリプトを作成しています。私のスクリプトでは、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応答が '404' であるか '200' であるかに応じて、またはを返しますFalse(実際には、Mechanize は、'200' 以外の場合は例外をスローし、例外処理を行います)。

main()私は基本的に、BS4 でスクレイピングした URL のリストから多数の URL を渡すこの関数をループしています。関数が戻っTrueたら、MP3 のダウンロードに進みますwget

しかし。私の問題は次のとおりです。

  • br.open(<URL>)URL はリモート サーバー上のポッドキャスト MP3 ファイルへの直接パスであり、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 を取得します。そうでない場合は、Mechanize と同じように簡単にエラーが発生します。これにより、各 URL に 2 回アクセスすることを回避できます。

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は、ほぼ正確にあなたが望むことを行います。

于 2013-11-28T23:50:22.090 に答える