こんにちは、Zero-Cheeseです。
本記事では、PythonのHTTP通信ライブラリの定番である、requestsパッケージの使用方法を、まとめました。
requestsパッケージを使用する事により、
- サイトから画像・情報を収集したり、
- 認証を必要とする処理(例:株等の自動取引等)まで、
簡単に実装する事が可能になります。
本記事は、
- Python入門者レベル以上の方を
対象にした内容となっています。
実例として、requestsを使用した仮想通貨の自動取引システムの作り方を、記事にしています。
ご興味がありましたら、併せてどうぞ。
本記事では、頻繁に使用される使い方に絞って、網羅してみました。
下記もくじから、必要部分のみ、リンクで飛んで頂ければと思います。(各章は、単独で見ても、理解できる構成となっています。)
本記事のコードで紹介している、「url先や、パラメータ値、実行結果」は、あくまでも一例です。
ご自身の使用ケースに応じて、変更して頂ければと思います。
また本記事のコードには、下記importが、必要です。
import requests
インストール方法
pipにて、インストール可能です。
pip install requests
pipも詳細を知りたい方は、こちらまで
基本的な使い方
ここでは、
- Googleのサイト(https://www.google.co.jp/)にアクセスして
- HTMLを取得
する方法を事例に、基本的な使い方を、見ていきます。
コード
import requests
url = 'https://www.google.co.jp/'
response = requests.get(url)
print(response.text)
HTTP GETメソッドの場合、
- 取得したいURLを引数にして、requests.getメソッドを実行する事で、
- 戻り値(オブジェクト)のtext属性に、
取得したい情報が代入されます。
上記コードの、実行結果
<!doctype html>
<html itemscope="" itemtype="http://schema.org/WebPage" lang="ja">
<head><meta content="世界中のあらゆる情報を検索するためのツールを提供しています。さまざまな検索機能を活用して、お探しの情報を見つけてください。" name="description">
<meta content="noodp" name="robots">
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
<meta content="/images/branding/googleg/1x/googleg_standard_color_128dp.png" itemprop="image"><title>Google</title>
-- 途中省略 --
</body>
</html>
戻り値(Responseオブジェクト)の使用方法
request.getメソッドや、postメソッド(後述)を呼出した結果、戻り値(Responseオブジェクト)について、解説します。
下記メソッドを呼出した際の、変数「response」に代入される、オブジェクトの解説になります。
response = requests.get('https://www.google.co.jp/')
HTTPステータスコード を取得
HTTPステータスコードとは
- 100番台 → 案内
- 200番台 → 正常処理
- 300番台 → リダイレクト(転送)処理
- 400番台 → クライアント側のエラー
- 500番台 → サーバー側のエラー
といった、レスポンスの意味を数字で返したものです。
よく、404 Not Found (そんなの、無いよ!)を、目にしているかとおもいますが、あれもステータスコードになります。
HTTPステータスコードの詳細は、こちら
print(response.status_code)
# ⬆︎ 実行結果: 200
リダイレクトされた場合、最終ページの情報のみ、表示されます。
この場合、「response.history」を使えば、リダイレクト履歴を、リスト(要素は、Responseオブジェクト)で取得できます。
コード例をご紹介します。(URL先で、リダイレクト1回実施された事例です。)
url = 'https://www.udemy.com/ja'
response = requests.get(url, headers=headers)
print(response.history)
# ⬆︎ 実行結果: [<Response [301]>]
# Responseオブジェクトのリストになっている
print(response.history[0].status_code)
# ⬆︎ 実行結果: 301
レスポンスヘッダを取得
レスポンス内容の付加情報が記された「レスポンスヘッダ」を取得するコードです。
print(response.headers)
# ⬆︎ 実行結果: {'Date': 'Thu, 15 Sep 2022 11:43:49 GMT',
# 'Expires': '-1',
# ・・・以下、省略
辞書型で取得できるので、キーを指定して、以下のように取得できます。
print(response.headers['Content-Type'])
レスポンスタイムを取得
応答時間を取得するコードです。
print(response.elapsed)
# ⬆︎ 実行結果: 0:00:00.385989
エンコーディングを取得
レスポンスは、当然、バイト列で送られてきます。
それを人間が読める文字列に変換するのに使用した、「文字エンコード」を取得するコードです。
print(response.encoding)
# ⬆︎ 実行結果: Shift_JIS
レスポンス内容を文字列で取得
上述のエンコーディングで、デコードしたレスポンス内容を、取得するコードです。
print(response.text)
# ⬆︎ 実行結果: <!doctype html><html itemscope=""
# ・・・以下省略
文字化けする場合:
エンコーティングの設定が、適切ではありません。
エンコーディングの設定は、HTTPレスポンスヘッダ内、content-typeに含まれる、charsetの情報を読みにいきます。
記述されていない場合、デフォルト値(ISO-8859-1)になります。
【対応策】
requestsモジュールは、文字コードを推定してくれる機能があります。
コードは、以下となります。
response.encoding = response.apparent_encoding
# 上記コマンドを実施した後に、下記のように、デコードした内容を取得する
print(response.text)
戻り値が、JSONデータの場合(処理方法)
Webから取得するJsonデータは、「Unicodeエスケープシーケンス(\u30b0\u30a4\u30f3 とか \uで始まるもの)」等の文字列がまざっており、処理が少し面倒です。
requests.json()メソッドを使えば、それらの問題を解決し、Pythonの辞書型、もしくは辞書のリスト型に変換してくれます。
# BitFlyerさんより、ビットコイン価格を取得する場合
url = 'https://api.bitflyer.com/v1/ticker'
params = {'product_code': 'btc_jpy'}
response = requests.get(url, params=params)
# JSONを変換
print(response.json())
# ⬆︎実行結果: {'product_code': 'BTC_JPY', ・・・・ 以下省略
ちなみに、JSONデータが送られて来ているかどうかの確認には、レスポンスヘッダのContent-Type
を確認します。
print(response.headers['Content-Type'])
# ⬆︎実行結果: application/json; charset=utf-8
ファイル保存したい(処理方法)
例えば 取得したデータがZipファイル等の場合、ファイルとして保存したい場合があると思います。
戻り値 (Responseオブジェクト)の「content」に、バイナリデータが保存されており、そちらを利用します。
# 下記URL先は、市町村情報が記載されているCSVを、ZIPファイルで、提供している。
url = 'http://zipcloud.ibsnet.co.jp/zipcodedata/download?di=1661933424166'
response = requests.get(url)
# 下記メソッドの第一引数は、ファイルパスを指定
with open('./ken.zip', 'wb') as f:
f.write(response.content)
print(response.headers)
# ⬆︎実行結果: {'Content-Type': 'application/octet-stream; charset=UTF-8',
# 'Content-Disposition': 'attachment; filename=ken-all202208.zip',
# 以下省略
参考までに、この場合の、レスポンスヘッダ情報を記載します。
上記レスポンスヘッダの注釈:
- application/octet-stream:任意のバイナリ形式である(ファイル形式が不明な場合に使われる)
- DLしようとしているファイル名は、’Content-Disposition’ を見れば、取得可能
ファイル情報を取得→保存する処理の間に、ウイルスチェックする事を、強くオススメします。
ケース別 HTTP GETメソッドの呼出し
URLのみを指定する場合
既に記しましたが、再度、コードを紹介します。
url = 'https://www.google.co.jp/' # Googleの事例
response = requests.get(url)
URLパラメータを指定する場合
HTTP GETメソッドで、パラメータを送信するケースです。
下記のようなURLの場合、& 以下で表示されている部分が、パラメータになります。
https://www.google.com/?gl=us&hl=en&gws_rd=cr&pws=0
# 上記の場合、 gl=us&hl=en&gws_rd=cr&pws=0 がパラメータ部分
パラメータを、辞書型で設定します。
url = 'https://www.google.co.jp/'
params = {'q': 'Python',
'oe': 'utf-8'}
response = requests.get(url, params=params)
ケース別 HTTP POSTメソッドの呼出し
送信データが、文字列の場合
送信データが、文字列の場合です。
url = 'https://www.google.co.jp/'
data = {'key1': 'value1'}
response = requests.post(url, data=data)
requests.getの際は、params引数に、送信データを辞書型で、設定しました。
この場合URLに、パラメータを文字列で付加した形で、送られます。
一方、data引数に設定した際は、リクエストボディで送信されます。
postメソッドでも params引数で、データを送る事が可能ですが、POSTの特性上、あまり必要性がないかと思われます。
送信データが、JSONデータの場合
JSONデータを送信する場合、エンコードが必要です。
import json
url = 'https://www.google.co.jp/'
data = {'key1': 'value1'}
data_encode = json.dumps(data)
response = requests.post(url, data=data_encode)
送信データが、ファイルの場合
ファイルを送る際は、openメソッドを使用します。
url = 'https://www.google.co.jp/'
# 画像ファイルの場合
img_data = open('image.jpg', 'rb')
files = {'file': img_data}
response = requests.post(url, files=files)
ちなみに、Googleサイトに画像ファイルを送っても、意味がありません(笑)
413レスポンス(Payload Too Large)が、返られてくると思います。
ケース別 HTTP PUTメソッドの呼出し
PUTは、既存リソースの「置き換え」が主担当のメソッドです。
よって、リクエスト送信時に、識別子を送るのが一般的です。
送信データが、文字列の場合
url = 'https://www.google.co.jp/'
data = {'key1': 'value1'}
response = requests.put(url, data=data)
送信データが、JSONの場合
import json
url = 'https://www.google.co.jp/'
data = {'key1': 'value1'}
data_encode = json.dumps(data)
response = requests.put(url, data=data_encode)
ケース別 HTTP DELETEメソッドの呼出し
DELETEは、リソースの「削除」が主担当のメソッドです。
こちらも、リクエスト送信時に、識別子を送るのが一般的です。
送信データが、文字列の場合
url = 'https://www.google.co.jp/'
data = {'key1': 'value1'}
response = requests.delete(url, data=data)
送信データが、JSONの場合
import json
url = 'https://www.google.co.jp/'
data = {'key1': 'value1'}
data_encode = json.dumps(data)
response = requests.delete(url, data=data_encode)
全メソッドに共通する処理
リクエストに、タイムアウトを指定する場合(推奨)
設定した場合、時間内に相手先からの応答がない場合、
- requests.exceptions.Timeout 例外
が発生します。
デフォルトではNoneとなっており、相手先から応答するまで、ずっと待っている状態になります。
公式ドキュメントでも、設定が推奨されています。
response = requests.get(url, timeout=3)
# 上記の場合、3sec で設定
リクエストヘッダを指定する場合
例えば、GETリクエストで、ユーザーエージェントを送信する事例で、紹介します。
ヘッダーを、辞書型で設定します。
url = 'https://www.google.co.jp/'
headers = {'User-Agent': 'something'}
response = requests.get(url, headers=headers)
Basic認証付きの、リクエストを送信する場合
Basic認証の、コードをご紹介します。
ユーザ名、パスワードを必要とする、最もベーシックな方法です。
下記コードは、GETとPOST送信のケースをご紹介しています。
from requests.auth import HTTPBasicAuth
# 下記は、Basic認証の接続テストができるサイトです。
url = 'http://leggiero.sakura.ne.jp/xxxxbasic_auth_testxxxx/secret/kaiin_page_top.htm'
# ユーザー名を指定
username = 'kaiin'
# パスワードを指定
password = 'naisho'
# GET送信のケース
response = requests.get(url,
auth=requests.auth.HTTPBasicAuth(username, password))
# POST送信のケース
data = {'key1': 'value1'}
response = requests.post(url, data=data,
auth=requests.auth.HTTPBasicAuth(username, password))
requestsパッケージの例外処理
HTTPリクエストは、
- 接続エラー
- タイムアウトエラー
等が発生する可能性があるので、例外処理が必須です。
requestsによるHTTP通信で発生する例外は、全て
- requests.exceptions.RequestException オブジェクト
- もしくは、当クラスを継承したオブジェクト
になります。
requests関係で、よく使用される例外を、以下に記します。
(全て、requests.exceptions.RequestException を継承しています。)
- ConnectionError:DNSエラーや、接続が切断時等に発生
- Timeout:タイムアウト時に発生
- SSLError:SSL接続エラー
- HttpError:不正なHTTPレスポンスがあった再、発生
TooManyRedirects
:リダイレクトが最大数を超えた時に発生
requestsを使用する際は、基本的にtry-except文で、例外処理できるようにします。
例外を取得できないと、システムが強制終了してしまいます。
基本的な、コードは以下の通りです。
try:
url = 'https://www.google.co.jp/'
response = requests.get(url, timeout=5)
except requests.exceptions.RequestException as e:
# ログ出力したり、例外発生時の処理を記載
print("RequestException: ", e)
HTTPステータスが200番台(正常終了)以外のとき、
- raise_for_status() を使用すると
HttpError例外を発生させられます。
使用方法は、以下の通りです。(4行目)
try:
url = 'https://www.google.co.jp/'
response = requests.get(url, timeout=5)
# HTTPステータスコードが200番台以外の場合、HTTPErrorが発生
response.raise_for_status()
except requests.exceptions.RequestException as e:
print("RequestException: ", e)
例外ごとに、細かく処理したい場合は、例えば以下のように記載します。
except文の中で、親オブジェクトである、requests.exceptions.RequestExceptionを、一番最後に記載します。
try:
url = 'https://www.google.co.jp/'
response = requests.get(url, timeout=5)
# HTTPステータスコードが200番台以外の場合、HTTPErrorが発生
response.raise_for_status()
except requests.exceptions.HTTPError as e:
print("HTTPError:", e)
except requests.exceptions.ConnectionError as e:
print("ConnectionError:", e)
except requests.exceptions.Timeout as e:
print("Timeout:", e)
except requests.exceptions.RequestException as e:
print("RequestException: ", e)
最後に
本記事では、requestsパッケージに関係する処理を、まとめてみました。
PythonからHTTP通信を行うには、
- 標準ライブラリである、urllib
を使う方法がありますが、コードの簡潔さの観点から、requestsパッケージが断然オススメです。
requestsパッケージを使用すれば、スクレイピングや、金融取引 等々、HTTPリクエストで困ることは、ほとんどないと思います。
本記事が、皆様の役に立つ事ができたら、幸いです。
それではまた、お会いしましょう!