トップ 一覧 検索 ヘルプ RSS ログイン

新urllib.pyの変更点

  • 追加された行はこのように表示されます。
  • 削除された行はこのように表示されます。
{{category Python}}

!!! Python 3のurllib
!! urllib.request
Python 3のurllibでは、オブジェクトやメソッドが定義されている名前空間がurllibではなくて、urllib.request以下になった。

 import urllib.request
 
 opener = urllib.request.build_opener()
 response = opener.open("http://www.foobar.com")
 print(response.read())

urllib.request.build_opener([handlers...,])は、urllib.request.OpenerDirectorのインスタンスを返す。
これは、さまざまなHTTPクライアント機能を持ち、openメソッドを持ったオブジェクトである(機能は引数にハンドラオブジェクトを渡して作成する)。

urllib.request.OpenerDirector.open(url, [data, timeout])は、urllib2.urlopen(url, [data, timeout])と同じ引数を取る。キーワード引数でも指定可能。
したがって、違和感なく使える。
urllib.request.OpenerDirector.open(...)が返すのは、http.client.HTTPResponseオブジェクト。
これはファイルハンドラのようにしてコンテンツを読み出せる。

!! Request / Response
URL Openerはデフォルトのものが用意されている。
もっと直感的にHTTPのRequest / Responseを実現するには、Requestオブジェクトを使う。
 import urllib.request
 
 url_request = urllib.request.Request(url="http://www.yahoo.co.jp")
 http_response = urllib.request.urlopen(url_request)
 binary_contents = http_response.read()

POSTはこんな感じ。
 import urllib.request
 
 PostHeaders = {"Content-Type" : "application/octet-stream"}
 post_data_handle = open("C:\post.jpg", "rb")
 post_request = urllib.request.Request(url="http://post.intranet.com/image", data=post_data_handle.read(), method="POST", headers=PostHeaders)
 post_response = urllib.request.urlopen(post_request)


!! charsetを得ようとする場合

 import urllib.request
 
 content_charset = ""
 url_request = urllib.request.Request(url="http://www.yahoo.co.jp")
 http_response = urllib.request.urlopen(url_request)
 content_charset = http_response.info().get_content_charset()
 if charsets:
 if content_charset:
     print(http_response.read().decode(content_charset))

http.client.HTTPResponse.info()が返すのは、http.client.HTTPMessageオブジェクト。これを使って、戻ってきたHTTPヘッダ内の情報を取り出せる。
http.client.HTTPMessage.get_charsets()はcharsetを表す文字列のリストを返す。HTTPの場合は、取得したページのcharsetとして0番目の値だけを参照すればよい、とのこと(メール等のマルチパートMIMEに対応できるように、リストで返す仕様にしてあるらしい)。
charsetが無い場合には[None](唯一の値がNoneであるリスト)が帰ってくるので注意。リストの要素が文字列だという前提でコーディングしていると、例外が発生する。

!! proxyを使いたい場合
ハンドラオブジェクトを作って渡す。
カスタムのハンドラオブジェクトを使いたい場合には、build_openerを使って、カスタムのURL Openerを作成する必要がある。

 import urllib.request
 
 opener = urllib.request.build_opener(urllib.request.ProxyHandler({"http": "192.168.1.16:8080"}))
 response = opener.open("http://www.foobar.com", timeout=10)

こりゃ簡単だ。

!!! 2.6向けの旧記事
最近の urlopen では、タイムアウト値を設定できるようになったようだ。
少なくとも 2.6 の urllib2 ではできるようになっている。

urlopen(url[, data][, timeout])

dataは、リクエスト以外に追加でサーバーに送りたい文字列がある場合、とのこと。
timeoutは秒数で指定する。

dataは普通指定しない。その場合はNoneでいいので、以下のようになる。

 import urllib2
 
 result = urllib2.urlopen("http://www.yahoo.co.jp", None, 30)