Python2とPython3でHTTP POST+Cookie処理の比較

Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)

Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)


Python2系でurllibとurllib2に分かれていたHTTP関係のコードは、Python3でurllibモジュールに統合されました。

Pthon3でHTTP POSTをする場合にurllibをどう使えばいいのかについて、はてなにログインするスクリプトを例にして比較したいと思います。GETは簡単なんでパス。


全体的な流れとして

  1. データをURLエンコードして送信
  2. cookieはCookieProcesssorでCookieJarオブジェクトを処理
  3. 接続するとレスポンスオブジェクトが返るので、readメソッドで内容を読む

というのは変わりません。実際、urllib2に配置されていた関数などがurllib.requestに、cookielibがhttp.cookiejarに移動したぐらいで、使い方はほぼ一緒です。ただし、別モジュールに配置された関数や引数の型がstrだったりbytesだったりしてつまずきそうな箇所があります。

Python2

  • URLエンコードにurllib.urlencodeを使います。
  • OpenDirector, HTTPCookieProcessorはurllib2にあります。
  • CookieJarはcookielibにあります。
#! /usr/bin/python
import urllib
import urllib2
import cookielib


u, p = 'usernmae', '********'

opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookielib.CookieJar()))

post = {
    'name': u,
    'password': p
}
data = urllib.urlencode(post)
conn = opener.open('http://www.hatena.ne.jp/login', data)

ofs = open('out.html', 'w')
ofs.write(conn.read())
ofs.close()


conn = opener.open('http://d.hatena.ne.jp/%s/edit' % u)

ofs = open('out2.html', 'w')
ofs.write(conn.read())
ofs.close()

Python3

  • URLエンコードにurllib.parse.urlencodeを使います。
  • OpenDirector, HTTPCookieProcessorはurllib.requestにあります。
  • CookieJarはhttp.cookiejarにあります。
  • Python2のunicodeクラスはPython3でstrクラスに改名され、それに伴いstrはbytesに改名されました。urllib.request.urlopenなどで渡すデータが受け付けるのはbytesです。そのため、URLエンコードした結果得られたstrクラスのインスタンスをencodeメソッドでbytesに変換して引数に指定します。
  • open関数でエンコーディングが指定できるようになっています。使い方を見ている限り、codecs.openに置き換えられた感じ。
#! /usr/bin/python3.2
# python3 sample script: http post; logging in hatena
# ref: http://docs.python.org/py3k/library/urllib.request.html
# ref: http://diveintopython3.org/files.html
import urllib
import urllib.request # opener
import urllib.parse # urlencode
import http
import http.cookiejar

opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(http.cookiejar.CookieJar()))

u, p = 'usernmae','********'
post = {
    'name': u,
    'password': p
}
data = urllib.parse.urlencode(post).encode('utf-8')

conn = opener.open('http://www.hatena.ne.jp/login', data)
ofs = open('out.html', 'w', encoding='utf-8')
ofs.write(conn.read().decode('utf-8'))
ofs.close()

conn = opener.open('http://d.hatena.ne.jp/%s/edit' % u)
ofs = open('out2.html', 'w', encoding='euc-jp')
ofs.write(conn.read().decode('euc-jp'))
ofs.close()

ログインできました。