今更感満載のネタでリソースを使ってしまって申し訳ありませんQiit様。
会社の業務系でWebAPIをいろいろ変更しながら叩く必要があり、じゃあPythonでもやってみるかーと思いました。以前にsocketオブジェクトを使った通信は少しやったので、まー何とかなるだろうと。
で、socketベースでHTTPクライアント作りつつ、いろいろググレカスしてみると、どうもそういうのは違うっぽいと知りました。更に調べてみますと requestsを利用するのが良いのかなーという結論に至りました。
そこで、とりあえずGETするだけの物を作ってみました。
特徴
- Pythonやる際に良く使う要素を用もなくブッ込んでみました。
- なので普段Pythonやらない人もこれ見ると、基本的な書き方を思い出せると思います(こんなん私しか必要ないという気もしますが、要は備忘で書いたということで)
- URL指定は http:// 系が無くてもある程度対応可能にしてみました。
- ヘッダ操作(入れ込み、受け取り)も分かるように記述してみました。
- ボディは指定されたファイルに入れるようにしてあります。
- HTTP処理に関してexception処理を入れてますので、通信失敗込みで連続処理とかやりたい人には参考になるかもしれません。。
requests について
requestに関する情報
今回ぐらいのケースなら上記のドキュメントに大体記載されてます。
セットアップ
requestsはpipでインストールが必要です。私の場合はWindows10のCygwin(32bit)で確認をしました。
(参考)Cygwinでpipを使う
このサイトの情報が大変役に立ちました。tanao様ありがとうございます。
上のサイトを見ますと、Cygwinでのpip周りの扱いはいろいろあったようですが、2016/7/18現在、Windows10/Cygwin32bit、Python2.7という環境であれば以下でいけるみたいです。
- Cygwinで追加するモジュールは上記記事のママ
- 2.7であれば、easy_install-2.7が使えますので、上記記事を参考にpipをインストールします。
- ついで定番の
pip install requests
で。
HTTPクライアントクラスのコード
とりあえずクラスの書き方を思い出すためという情けない理由も込みでクラスにしてみました。
import requests
class SampleHTTPclient:
def __init__(self, url):
self.url = url
self.protocol = ""
self.error_message = ""
self.request_headers = None
self.response_headers = None
self.status_code = None
def check_protocol(self):
# ex
# if self.protocol = "http://" , self.uri = "hoge.org":
# self.url = "http://hoge.org"
if self.url.find("://") == -1 and len(self.protocol) > 3:
self.url = self.protocol + self.url
def set_protocol(self, protocol):
self.protocol = protocol
self.check_protocol()
def set_headers(self, headers):
self.request_headers = headers
def get(self, fp):
try:
if self.request_headers is None:
response = requests.get(self.url)
else:
response = requests.get(self.url, headers=self.request_headers)
fp.write(response.content)
except Exception as ex:
self.error_message = str(ex)
return False
else:
self.status_code = response.status_code
self.response_headers = response.headers
return True
def get_code(self):
return self.status_code
def get_headers(self):
return self.response_headers
def get_error_message(self):
return self.error_message
実体は2行なのですが・・ゴチャゴチャつけてしまいました。。
使い方は以下のイメージです。
- まずはURLでインスタンスを生成
- URLのデータに http:// とか無い場合なら __set_protocol__で使うプロトコルを指定出来ます(※1)。
- 追加するヘッダがあれば、__set_headers__でrequestsの仕様に従ったdictを入れて下さい。下にサンプルコードもありますので、そっちを参考にしてもいいかもです。
- openを使って書き込みモードでファイルを開けておきます。
- それを使って__get__を呼び出します。boolで成功(True)、失敗(False)が分かります
- 通信が成功した場合はbodyが指定されたファイルに入っています(※2)。
- 通信に成功した場合、__get_code__でHTTPステータスコードを取得できます。
- 通信に成功した場合、__get_headers__でrequestの仕様で定められたdictの形のレスポンスヘッダを取得できます。
- 失敗した場合は、get_error_message でエラーメッセージを取得できます。
※1 http:// などのプロコトル込みのURL文字列を指定してSampleHTTPclientを生成した後、set_protcolでプロトコルの文字列を指定しても問題はありません。この場合はset_protocolの設定が無視されます。
※2 例えばHTTP 404のエラーとかは、get関数的には成功の扱いになります。そのためget_codeなどで通信結果を合わせて確認して下さい。また現状ではこの場合でもボディをファイルに書き込む仕様となっています。それが不都合な方は、お手数おかけして申し訳ございませんが改造願います。
実際にGETするコード例
上の説明をコード化して、SampleHTTPclientを使った例を以下に示します。
print "sample httpc program."
url = "<<ここに取得するリソースのURLを>>"
headers = {"X-gdaigo_para1": "fujiko", "X-gdaigo-para2":"7890"}
filename = "test.html"
print url, " -> " , filename
httpc = SampleHTTPclient(url);
httpc.set_protocol("http://")
httpc.set_headers(headers)
fp = open(filename, "w")
success = httpc.get(fp)
fp.close()
if success == True:
headers = httpc.get_headers()
print "response code=", httpc.get_code()
for key, value in headers.iteritems():
print key, ":" , value
print "success."
else:
print "httpc:read error\n" , httpc.get_error_message()
print "error."
print "complete."
上記の例はURLを元にリソースを取得して、そのデータを test.html として取得する例です。(無意味ではありますが)ヘッダを設定し、取得結果の表示も合わせて行っています。GETはこんな感じで大丈夫そうです。
という事でrequestsを使う事で割とあっさり出来ました。
ライセンス
以下使わせて戴きました。素晴らしいソフトウェアを提供して下さり、ありがとうございます。
- (一応書きます…)上記のコードはパブリックドメインとします。当然ですが使用した際の損害は誰も請け負ってくれません。そこだけ注意で。
- Python自体はPSF (Python Software Foundation)ライセンスです。
- ↑の情報はWikipediaのPythonがソースです。
- requestsはここにある通り Apache2 Licenseです。
以上です。