Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

【今更】Python初心者がrequestsを使ってHTTPクライアントを実装してみた(ヘッダ操作込)

More than 3 years have passed since last update.

今更感満載のネタでリソースを使ってしまって申し訳ありません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行なのですが・・ゴチャゴチャつけてしまいました。。

使い方は以下のイメージです。

  1. まずはURLでインスタンスを生成
  2. URLのデータに http:// とか無い場合なら set_protocolで使うプロトコルを指定出来ます(※1)。
  3. 追加するヘッダがあれば、set_headersrequestsの仕様に従ったdictを入れて下さい。下にサンプルコードもありますので、そっちを参考にしてもいいかもです。
  4. openを使って書き込みモードでファイルを開けておきます。
  5. それを使ってgetを呼び出します。boolで成功(True)、失敗(False)が分かります
  6. 通信が成功した場合はbodyが指定されたファイルに入っています(※2)。
  7. 通信に成功した場合、get_codeでHTTPステータスコードを取得できます。
  8. 通信に成功した場合、get_headersrequestの仕様で定められたdictの形のレスポンスヘッダを取得できます。
  9. 失敗した場合は、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です。

以上です。

GDaigo
リストラと日々戦いながら慣れない言語で遊んでいます。当然ですがアイコンみたいなイケメンではないです。Qiitaは自分向けの備忘とかリファレンス置き場みたいな感じで使わせてもらってます。
http://gdaigo.blog.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away