web-dev-qa-db-ja.com

カスタムヘッダーを含むurllib.urlretrieve

カスタムヘッダーを追加しながら、urlretrieveを使用してファイルを取得しようとしています。

urllib.requestのコードソースを確認しているときに、urlopenが文字列だけでなくRequestオブジェクトをパラメーターに取ることができ、必要なヘッダーを配置できることがわかりました。しかし、urlretrieveで同じことを実行しようとすると、この他の投稿で言及されているように TypeError:予期される文字列またはバイトのようなオブジェクト が返されます。

私がやったことは、自分のurlretrieveを書き換えて、エラーをスローしている行を削除することです(その行は、私のユースケースでは無関係です)。

それは正常に動作しますが、より良い/より良いかどうか疑問に思っています自分のurlretrieveを書き換えるのではなく、それを行う方法。カスタムヘッダーをurlopenに渡すことができる場合、urlretrieve

10
realUser404

数行のコードを追加するだけでよい方法を見つけました...

import urllib.request

opener = urllib.request.build_opener()
opener.addheaders = [('User-agent', 'Mozilla/5.0')]
urllib.request.install_opener(opener)
urllib.request.urlretrieve("type URL here", "path/file_name")

詳細については、pythonドキュメント: https://docs.python.org/3/library/urllib.request.html を参照してください。 =

38
Lost Crotchet

urllib.request.urlretrieve()urllib.request.urlopen()内で使用します(少なくともPython 3で)。したがって、urlopen

urlopen(params)が呼び出されると、実際には最初に特別なグローバル変数_urllib.request._opener_が調べられ、Noneの場合はurlopenがデフォルトのオープナーのセットで変数を設定しますそれ以外の場合はそのままにします。次のステップでは、urllib.request._opener.open(<urlopen_params>)を呼び出します(次のセクションでは、_urllib.request._opener_をopenerとしてのみ参照します)。

opener.open()には、さまざまなプロトコルのハンドラーのリストが含まれています。 opener.open()が呼び出されると、次のアクションが実行されます。

  1. URL _urllib.request.Request_オブジェクトから作成します(または、Requestを直接指定した場合は、それを使用します)。
  2. Requestオブジェクトからプロトコルが抽出されます(URLスキームから推定されます)。
  3. プロトコルに基づいて、ルックアップを試み、次のメソッドを使用します:
    • _protocol_request_(例:_http_request_)-接続が開かれる前にリクエストを前処理するために使用されます。
    • _protocol_open_-実際にリモートサーバーとの接続を作成します
    • _protocol_response_-サーバーからの応答を処理します
    • 他のメソッドについては、 Pythonのドキュメントをご覧ください

あなた自身のオープナーのために、あなたはそれらの3つのステップをしなければなりません:

  1. 独自のハンドラーを作成する
  2. ハンドラーのビルドリストにはカスタムハンドラーが含まれます(関数_urllib.request.build_opener_)
  3. 新しいオープナーを_urllib.request._opener_にインストールします(関数_urllib.request.install_opener_)

_urllib.request.build_opener_は、カスタムハンドラーを含むオープナーを作成し、カスタムハンドラーが継承されたハンドラーを除くデフォルトオープナーを追加します。

したがって、カスタムヘッダーを追加するには、次のように記述します。

_import urllib.request as req

class MyHTTP(req.HTTPHandler):
    def http_request(self, req):
        req.headers["MyHeader"] = "Content of my header"
        return super().http_request(req)

opener = req.build_opener(MyHTTP())
req.install_opener(opener)
_

この時点から、urllib.request.urlretrieve()またはurlopen()を使用しているものを呼び出すと、ハンドラーのHTTP通信に使用されます。デフォルトのハンドラーに戻したい場合は、次のように呼び出すだけです。

_import urllib.request as req   

req.install_opener(req.build_opener())
_

正直なところ、それがあなたのソリューションよりも優れている/よりクリーンなソリューションであるかどうかはわかりませんが、urllibで準備されたメカニズムを使用しています。

6
Qeek