# 11.4 `urllib` -- URL による任意のリソースへのアクセス

このモジュールはワールドワイドウェブ (World Wide Web) を介してデータを 取り寄せるための高レベルのインタフェースを提供する。特に、関数 `urlopen()` は組み込み関数 `open()` と同様に動作し、 ファイル名の代わりにファイルユニバーサルリソースロケータ (URL) を 指定することができます。いくつかの制限はあります -- URL は読み出し 専用でしか開けませんし、seek 操作を行うことはできません。

このモジュールでは、以下の public な関数を定義します。

`urlopen`( | url[, data[, proxies]])

  URL で表されるネットワーク上のオブジェクトを読み込み用に開きます。 URL がスキーム識別子を持たないか、スキーム識別子が file: である場合、ローカルシステムのファイルが (広範囲の改行サポート なしで) 開かれます。それ以外の場合は ネットワーク上のどこかにあるサーバへのソケットを開きます。 接続を作ることができないか、サーバがエラーコードを返した場合、 例外 `IOError` が送出されます。全ての処理がうまくいけば、 ファイル類似のオブジェクトが返されます。このオブジェクトは以下の メソッド: `read()` 、 `readline()` 、 `readlines()` 、 `fileno()` 、 `close()` 、 `info()` そして `geturl()` をサポートします。 また、イテレータプロトコルも正しくサポートしています。 注意: `read()`の引数を省略または負の値を指定しても、データスト リームの最後まで読みこむ訳ではありません。ソケットからすべてのストリーム を読み込んだことを決定する一般的な方法は存在しません。

  `info()` および `geturl()` メソッドを除き、 これらのメソッドはファイルオブジェクトと同じインタフェースを持って います -- このマニュアルの 2.3.8 セクションを 参照してください。 (ですが、このオブジェクトは組み込みのファイル オブジェクトではないので、まれに真の組み込みファイルオブジェクトが 必要な場所では使うことができません)

  `info()` メソッドは開いた URL に関連付けられたメタ情報 を含む `mimetools.Message` クラスのインスタンスを返します。 URL へのアクセスメソッドが HTTP である場合、メタ情報中の ヘッダ情報はサーバが HTML ページを返すときに先頭に付加するヘッダ 情報です (Content-Length および Content-Type を含みます) 。 アクセスメソッドが FTP の場合、ファイル取得リクエストに応答 してサーバがファイルの長さを返したときには (これは現在では普通に なりましたが) Content-Length ヘッダがメタ情報に含められます。 Content-type ヘッダは MIME タイプが推測可能なときにメタ情報に 含められます。アクセスメソッドがローカルファイルの場合、 返されるヘッダ情報にはファイルの最終更新日時を表す Date エントリ、 ファイルのサイズを示す Content-Length エントリ、そして推測される ファイル形式の Content-Type エントリが含まれます。 `mimetools` モジュールを 参照してください。

  `geturl()` メソッドはページの実際の URL を返します。場合に よっては、HTTP サーバはクライアントの要求を他の URL に振り向け (redirect 、リダイレクト ) します。 関数 `urlopen()` はユーザに対してリダイレクトを透過的に 行いますが、呼び出し側にとってクライアントがどの URL にリダイレクト されたかを知りたいときがあります。`geturl()` メソッドを 使うと、このリダイレクトされた URL を取得できます。

  url に http: スキーム識別子を使う場合、data 引数を 与えて `POST` 形式のリクエストを行うことができます (通常リクエストの 形式は `GET` です)。引数 data は標準の application/x-www-form-urlencoded 形式でなければなりません; 以下の `urlencode()` 関数を参照してください。

  `urlopen()` 関数は認証を必要としないプロキシ (proxy) に対して 透過的に動作します。Unix または Windows 環境では、 Python を起動 する前に、環境変数 http_proxy、 ftp_proxy 、および gopher_proxy にそれぞれのプロキシサーバを指定する URL を 設定してください。 例えば ("`%`" はコマンドプロンプトです):

      % http_proxy="http://www.someproxy.com:3128"
      % export http_proxy
      % python
      ...

  Windows 環境では、プロキシを指定する環境変数が設定されていない場合、 プロキシの設定値はレジストリの Internet Settings セクションから取得 されます。

  Macintosh 環境では、`urlopen()` は 「インターネットの設定」 (Internet Config) からプロキシ情報を取得します。

  別の方法として、オプション引数 proxies を使って明示的にプロキシを 設定することができます。この引数はスキーム名をプロキシの URL にマップする 辞書型のオブジェクトでなくてはなりません。空の辞書を指定するとプロキシを 使いません。`None` (デフォルトの値です) を指定すると、上で述べた ように環境変数で指定されたプロキシ設定を使います。例えば:

      # http://www.someproxy.com:3128 を http プロキシに使う
      proxies = proxies={'http': 'http://www.someproxy.com:3128'}
      filehandle = urllib.urlopen(some_url, proxies=proxies)
      # プロキシを使わない
      filehandle = urllib.urlopen(some_url, proxies={})
      # 環境変数からプロキシを使う - 両方の表記とも同じ意味です。
      filehandle = urllib.urlopen(some_url, proxies=None)
      filehandle = urllib.urlopen(some_url)

  (訳注: 上記と矛盾する内容です。おそらく旧バージョンのドキュメントです) 関数 `urlopen()` は明示的なプロキシ指定をサポートしていません。 環境変数のプロキシ設定を上書きしたい場合には `URLopener` を使う か、`FancyURLopener` などのサブクラスを使ってください。

  認証を必要とするプロキシは現在のところサポートされていません。 これは実装上の制限 (implementation limitation) と考えています。

  バージョン2.3 以降で変更された 仕様: proxies のサポートを追加しました。

`urlretrieve`( | url[, filename[, reporthook[, data]]])

  URL で表されるネットワーク上のオブジェクトを、必要に応じてローカルな ファイルにコピーします。URL がローカルなファイルを指定していたり、 オブジェクトのコピーが正しくキャッシュされていれば、そのオブジェクトは コピーされません。タプル `(filename, headers)` を 返し、filename はローカルで見つかったオブジェクトに対する ファイル名で、headers は `urlopen()` が返した (おそらくキャッシュされているリモートの) オブジェクトに `info()` を適用して得られるものになります。 `urlopen()` と同じ例外を送出します。

  2 つめの引数がある場合、オブジェクトのコピー先となるファイルの位置を 指定します (もしなければ、ファイルの場所は一時ファイル (tmpfile) の 置き場になり、名前は適当につけられます)。 3 つめの引数がある場合、ネットワークとの接続が確立された際に一度 呼び出され、以降データのブロックが読み出されるたびに呼び出されるフック 関数 (hook function) を指定します。フック関数には 3 つの引数が渡され ます; これまで転送されたブロック数のカウント、バイト単位で表された ブロックサイズ、ファイルの総サイズです。3 つ目のファイルの総サイズ は、ファイル取得の際の応答時にファイルサイズを返さない古い FTP サーバ では `-1` になります。

  url が http: スキーム識別子を使っていた場合、オプション 引数 data を与えることで `POST` リクエストを行うよう 指定することができます (通常リクエストの形式は `GET` です)。 data 引数は標準の application/x-www-form-urlencoded 形式でなくてはなりません; 以下の `urlencode()` 関数を参照して ください。

`_urlopener`
  パブリック関数 `urlopen()` および `urlretrieve()` は `FancyURLopener` クラスのインスタンスを生成します。 インスタンスは要求された動作に応じて使用されます。 この機能をオーバライドするために、プログラマは `URLopener` または `FancyURLopener` のサブクラスを作り、そのクラスから 生成したインスタンスを変数 `urllib._urlopener` に代入した 後、呼び出したい関数を呼ぶことができます。 例えば、アプリケーションが `URLopener` が定義しているのとは 異なった User-Agent: ヘッダを指定したい場合があるかも しれません。この機能は以下のコードで実現できます:

      import urllib

      class AppURLopener(urllib.FancyURLopener):
          def __init__(self, *args):
              self.version = "App/1.7"
              urllib.FancyURLopener.__init__(self, *args)

      urllib._urlopener = AppURLopener()

`urlcleanup`( | )

  以前の `urlretrieve()` で生成された可能性のあるキャッシュを 消去します。

`quote`( | string[, safe])

  string に含まれる特殊文字を "`%xx`" エスケープで置換 （quote）します。 アルファベット、数字、および文字 "`_.-`" は quote 処理 を行いません。オプションのパラメタ safe は quote 処理しない 追加の文字を指定します -- デフォルトの値は `'/'` です。

  例: `quote('/~connolly/')` は `'/%7econnolly/'` になります。

`quote_plus`( | string[, safe])

  `quote()` と似ていますが、加えて空白文字をプラス記号 (``+'') に 置き換えます。これは HTML フォームの値を quote 処理する際に 必要な機能です。もとの文字列におけるプラス記号は safe に含まれて いない限りエスケープ置換されます。上と同様に、safe の デフォルトの値は `'/'` です。

`unquote`( | string)

  "`%xx`" エスケープをエスケープが表す 1 文字に置き換えます。

  例: `unquote('/%7Econnolly/')` は `'/~connolly/'` になります。

`unquote_plus`( | string)

  `unquote()` と似ていますが、加えてプラス記号を空白文字に置き換 えます。これは quote 処理された HTML フォームの値を元に戻すのに必要な 機能です。

`urlencode`( | query[, doseq])

  マップ型オブジェクト、または 2 つの要素をもったタプルからなる配列 を、 ``URL にエンコードされた (url-encoded)'' に変換して、 上述の `urlopen()` のオプション引数 data に適した 形式にします。この関数はフォームのフィールド値でできた辞書を `POST` 型のリクエストに渡すときに便利です。 返される文字列は `key=value` のペアを "`&`" で区切った配列で、key と value の双方は上の `quote_plus()` で quote 処理されます。 オプションのパラメタ doseq が与えられていて、その評価結果が真 であった場合、配列 doseq の個々の要素について `key=value` のペアが生成されます。 2 つの要素をもったタプルからなる配列が引数 query として使われた 場合、各タプルの最初の値が key で、2 番目の値が value になります。 このときエンコードされた文字列中のパラメタの順番は配列中のタプルの順番 と同じになります。 `cgi` モジュールでは、関数 `parse_qs()` および `parse_qsl()` を提供しており、クエリ文字列を解析して Python のデータ構造にするのに利用できます。

`pathname2url`( | path)

  ローカルシステムにおける記法で表されたパス名 path を、URL に おけるパス部分の形式に変換します。この関数は完全な URL を生成するわけ ではありません。返される値は常に `quote()` を使って quote 処理 されたものになります。

`url2pathname`( | path)

  URL のパスの部分 path をエンコードされた URL の形式からローカル システムにおけるパス記法に変換します。この関数は path をデコード するために `unquote()` を使います。

class `URLopener`( | [proxies[, **x509]])

  URL をオープンし、読み出すためのクラスの基礎クラス (base class)です。 http: 、 ftp: 、gopher: または file: 以外のスキームを使ったオブジェクトのオープンをサポートしたいのでない かぎり、`FancyURLopener` を使おうと思うことになるでしょう。

  デフォルトでは、 `URLopener` クラスは User-Agent: ヘッダとして "`urllib/VVV`" を送信します。ここで VVV は `urllib` のバージョン番号です。アプリケーションで独自の User-Agent: ヘッダを送信したい場合は、`URLopener` かまたは `FancyURLopener` のサブクラスを作成し、`open()` メソッドを呼び出す前にインスタンス属性 `version` を適切な 文字列値に設定することで行うことができます。

  オプションのパラメタ proxies はスキーム名をプロキシの URL に マップする辞書でなくてはなりません。空の辞書はプロキシ機能を完全に オフにします。デフォルトの値は `None` で、この場合、 `urlopen()` の定義で述べたように、プロキシを設定する環境変数が 存在するならそれを使います。

  追加のキーワードパラメタは x509 に集められますが、これは https: スキームによる認証に使われます。キーワード引数 key_file および cert_file がサポートされています。 実際に https: 形式の URL からリソースを取得するには両方の 引数が必要です。

class `FancyURLopener`( | ...)

  `FancyURLopener` は `URLopener` のサブクラスで、 以下の HTTP レスポンスコード: 301、302、303、 307、および 401 を取り扱う機能を提供します。 レスポンスコード 30x に対しては、 Location: ヘッダを使って実際の URL を取得します。 レスポンスコード 401 (認証が要求されていることを示す) に対しては、 ベーシック認証 (basic HTTP authintication) が行われます。 レスポンスコード 30x に対しては、最大で maxtries 属性に指定された数だけ再帰呼び出しを行うように なっています。この値はデフォルトで 10 です。

  注意: RFC 2616 によると、 POST 要求に対する 301 および 302 応答はユーザの承認無しに自動的にリダイレクトしてはなりません。 実際は、これらの応答に対して自動リダイレクトを許すブラウザでは POST を GET に変更しており、`urllib` でもこの動作を 再現します。

  コンストラクタに与えるパラメタは `URLopener` と同じです。

  注意: 基本的な HTTP 認証を行う際、 `FancyURLopener` インスタンスは `prompt_user_passwd()` メソッドを呼び出します。このメソッドは デフォルトでは実行を制御している端末上で認証に必要な情報を要求する ように実装されています。必要ならば、このクラスのサブクラスにおいて より適切な動作をサポートするために `prompt_user_passwd()` メソッドをオーバライドしてもかまいません。

制限:

- 現在のところ、以下のプロトコルだけがサポートされています: HTTP、 (バージョン 0.9 および 1.0)、 Gopher (Gopher-+ を除く)、 FTP、 およびローカルファイル。

- `urlretrieve()` のキャッシュ機能は、有効期限ヘッダ (Expiration time header) を正しく処理できるようにハックするための 時間を取れるまで、無効にしてあります。

- ある URL がキャッシュにあるかどうか調べるような関数があればと思って います。。

- 後方互換性のため、 URL がローカルシステム上のファイルを指している ように見えるにも関わらずファイルを開くことができなければ、 URL は FTP プロトコルを使って再解釈されます。この機能は時として混乱を招く エラーメッセージを引き起こします。

- 関数 `urlopen()` および `urlretrieve()` は、 ネットワーク接続が確立されるまでの間、一定でない長さの遅延を引き起こす ことがあります。このことは、これらの関数を使ってインタラクティブな Web クライアントを構築するのはスレッドなしには難しいことを意味します。

- `urlopen()` または `urlretrieve()` が返すデータは サーバが返す生のデータです。このデータはバイナリデータ (例えば画像 データ) 、生テキスト (plain text)、または (例えば) HTML でもかまいません。HTTP プロトコルはリプライ ヘッダ (reply header) にデータのタイプに関する情報を返します。 タイプは Content-Type: ヘッダを見ることで推測できます。

  Gopher プロトコルでは、データのタイプに 関する情報は URL にエンコードされます; これを展開することは簡単 ではありません。返されたデータが HTML であれば、 `htmllib` を使ってパースすることが できます。

- このモジュールは認証を必要とするプロキシをサポートしません。 将来実装されるかもしれません。

- `urllib` モジュールは URL 文字列を解釈したり構築したりする (ドキュメント化されていない) ルーチンを含んでいますが、URL を操作するためのインタフェースとしては、 `urlparse` モジュールをお勧めします。