トップ 差分 一覧 ソース 検索 ヘルプ PDF RSS ログイン

新urllib.py

[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 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)