Pythonスキルの習得

【Python Requests】使用方法まとめ – get、post、put、delete、例外処理、Basic認証まで網羅 –

Python Requests: A Comprehensive Guide - Including get, post, put, delete, Exception Handling, and Basic Authentication -

こんにちは、Zero-Cheeseです。

本記事では、PythonのHTTP通信ライブラリの定番である、requestsパッケージの使用方法を、まとめました。

requestsパッケージを使用する事により、

  • サイトから画像・情報を収集したり、
  • 認証を必要とする処理(例:株等の自動取引等)まで、

簡単に実装する事が可能になります。

本記事は、

  • Python入門者レベル以上の方を

対象にした内容となっています。

実例として、requestsを使用した仮想通貨の自動取引システムの作り方を、記事にしています。

ご興味がありましたら、併せてどうぞ。

bitFlyerのAPIを使用して、Pythonにより自動取引システムを作る
bitFlyerのAPIを使用して、Pythonにより自動取引システムを作るbitFlyerのAPIを使用して、Pythonにより自動取引システムを作り方を、わかりやすく紹介した記事です。...

本記事では、頻繁に使用される使い方に絞って、網羅してみました。

下記もくじから、必要部分のみ、リンクで飛んで頂ければと思います。(各章は、単独で見ても、理解できる構成となっています。)

本記事のコードで紹介している、「url先や、パラメータ値、実行結果」は、あくまでも一例です。

ご自身の使用ケースに応じて、変更して頂ければと思います。

また本記事のコードには、下記importが、必要です。

import requests

インストール方法

pipにて、インストール可能です。

pip install requests

pipも詳細を知りたい方は、こちらまで

【Python】pipの使い型入門 - コマンドライン、Anaconda、PyCharmからの操作方法を解説 -
【Python】pipの使い方入門 - コマンドライン、Anaconda、PyCharmからの操作方法を解説 -Python入門者を対象に、pipの使い型を解説した記事です。 コマンドライン、Anaconda、PyCharmからの操作方法を、わかりやすく解説しました。 ...

基本的な使い方

ここでは、

  • 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リクエストで困ることは、ほとんどないと思います。

本記事が、皆様の役に立つ事ができたら、幸いです。

それではまた、お会いしましょう!