メインコンテンツへスキップ
見出し画像

Pythonライブラリ(HTTP):Requests

    KIYO

    1.概要

     RequestsはHTTPクライアント自分でも詳しく意味がわかっていないですが用ライブラリです。ざっくりしたイメージではWebブラウザにChromeとかFireFox|URLを入れてEnterを押した時のような処理をしてくれます(※ブラウザの働きで言うと図は違うのでイメージ専用図です)。

    画像

     このライブラリを使用することで下記が可能となります。

    【Requestsの用途】※詳細は4・5章参照
    ●スクレイピングしたいサイトから情報を取得する
    ●サイト上の画像を取得
    ●APIで情報を取得したり与えたりする。

    2.前提知識:HTTPメソッド

     HTTPクライアントを処理する時に使用するメソッドは計8つあります。ただし上記用途であれば覚えるのは2つだけGETとPOSTで十分です。

    【HTTPメソッド】※ハイフンは通常使用しないため不明な箇所
    ●データ取得(GET/READ):requests.get('URL')
    ●データ作成(POST/CREATE):requests.post('URL')
    ●データ更新(PUT/UPDATE):requests.put('URL')
    ●データ削除(DELETE):requests.delete('URL')
    ●-(HEAD):requests.head('URL')
    ●-(OPTIONS):requests.options('URL')
    ●-(TRACE): -
    ●-(CONNECT): -

     下記は参考記事です(CRUDはデータベース用ですが理解には適してます)。

    3.GETメソッド:基礎1(パラメータ無し)

     HTTPクライアントが簡単に試すことができるJsonPlaceholderというサービスを利用してRequestsの基本操作を練習します。JsonPlaceholderで提供しているエンドポイントのURLAPIを利用するための専用URLは下記サイトから取得しました。

    (別サービスでhttpbinというサイトでも似たような練習は可能です。)

    3-1.データ取得(requests.get(url))

     Requestsを利用して私のnoteのページにアクセスします。下記の通り、戻り値が200であれば問題なく接続できています。

    [In]
    import requests
    
    url = 'https://jsonplaceholder.typicode.com/posts'
    res = requests.get(url)
    print(res.status_code) # 200なら通信成功
    
    
    [Out]
    200

    【HTTPレスポンスコード】
     HTTPクライアントやスクレイピングをしているとエラーが出てきてstatusコードの戻り値が400や401などが返ってきます。これらの値はすべて規格化されているためエラーの数値を確認することで適切な対応が判断できます。

    https://developer.mozilla.org/ja/docs/Web/HTTP/Status

    3-2.戻り値の表示:res.text、res.json()

     戻り値を表示する場合、テキストデータならres.text, JSON形式ならres.json()で表示できます。今回の戻り値はJSON形式のためコードは下記の通りです。
     結果としてuserId, id, title, bodyの辞書型データを含むリストを戻り値として取得しました。

    [In]
    import requests
    url = 'https://jsonplaceholder.typicode.com/posts'
    
    res = requests.get(url)
    res.json()
    [Out]
    [{'userId': 1,
      'id': 1,
      'title': 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit',
      'body': 'quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto'},
     {'userId': 1,
      'id': 2,
      'title': 'qui est esse',
      'body': 'est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla'},
     {'userId': 1,
      'id': 3,
      'title': 'ea molestias quasi exercitationem repellat qui ipsa sit aut',
      'body': 'et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et velit aut'},
    
    以下省略
    
     {'userId': 10,
      'id': 100,
      'title': 'at nam consequatur ea labore ea harum',
      'body': 'cupiditate quo est a modi nesciunt soluta\nipsa voluptas error itaque dicta in\nautem qui minus magnam et distinctio eum\naccusamus ratione error aut'}]

    3-3.ヘッダーの表示:res.request.headers

     ヘッダー情報を取得する場合は"res.request.headers"を使用します。

    [IN]
    import requests
    url = 'https://jsonplaceholder.typicode.com/posts'
    
    res = requests.get(url)
    print(res.request.headers)
    
    [OUT]
    {'User-Agent': 'python-requests/2.26.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}

    3-4.エンコーディング(文字化け対応)

     レスポンスの文字コードを確認する場合は"res.encoding"を使用します。

    [IN]
    print(res.encoding)
    
    [OUT]
    utf-8

     もし文字化けが生じた場合は"ISO-8859-1"という文字列が返ってくるため、"res.encoding = res.apparent_encoding"を渡すと改善されます。

    [IN]
    url = <文字化けするサイト>
    res = requests.get(url)
    
    print(res.encoding) #文字コードを確認
    res.encoding = res.apparent_encoding #文字コードを自動で変換
    print(res.encoding) #文字コードを確認
    
    [OUT]
    ISO-8859-1
    UTF-8-SIG

    4.GETメソッド:基礎2(クエリパラメータ)

     HTTPメソッドでは変数を渡すことができます。ここではid変数にデータを与えてほしい情報を抽出します。

    4-1.URLを用いた変数の渡し方:クエリパラメータ

     「美女」でググるとURLは下記の通りになり「google.com/search」の後ろは「?q=美女」となっています。

    画像

    「?q=」は「検索変数qに美女という値をいれます」という意味であり、検索時にパラメータを与えているということになります。このようなパラメータの渡し方をクエリパラメータといいます。

    4-2.パラメータ追加1:手動

     パラメータを手動で追加する場合はurlに直接パラメータを書き込みます。

    [In]
    url = 'https://jsonplaceholder.typicode.com/posts/?id=1'
    
    res = requests.get(url)
    res.json()
    
    [Out]
    [{'userId': 1,
      'id': 1,
      'title': 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit',
      'body': 'quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto'}]

     複数のパラメータを与えたい場合は&でつなぎます。

    [In]
    url = 'https://jsonplaceholder.typicode.com/posts/?id=1&id=5'
    
    res = requests.get(url)
    res.json()
    
    [Out]
    [{'userId': 1,
      'id': 1,
      'title': 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit',
      'body': 'quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto'},
     {'userId': 1,
      'id': 5,
      'title': 'nesciunt quas odio',
      'body': 'repudiandae veniam quaerat sunt sed\nalias aut fugiat sit autem sed est\nvoluptatem omnis possimus esse voluptatibus quis\nest aut tenetur dolor neque'}]

    4-3.パラメータ追加2:requests.get(url, params=p)

     Requestsの引数としてパラメータを与える場合は下記の通りです。

    [In]
    url = 'https://jsonplaceholder.typicode.com/posts'
    params = {'id':1}
    
    res = requests.get(url, params=params)
    res.json()
    
    [Out]
    [{'userId': 1,
      'id': 1,
      'title': 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit',
      'body': 'quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto'}]

     複数の場合は下記の通りです。なお記載方法に注意が必要であり「params = {'id':1, 'id':5} 」と書くと値はid=5の物しか返ってきません。

    [In]
    url = 'https://jsonplaceholder.typicode.com/posts'
    params = {'id':[1,5]}
    
    res = requests.get(url, params=params)
    res.json()
    
    [Out]
    [{'userId': 1,
      'id': 1,
      'title': 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit',
      'body': 'quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto'},
     {'userId': 1,
      'id': 5,
      'title': 'nesciunt quas odio',
      'body': 'repudiandae veniam quaerat sunt sed\nalias aut fugiat sit autem sed est\nvoluptatem omnis possimus esse voluptatibus quis\nest aut tenetur dolor neque'}]

    5.POSTメソッド

     基本的なAPIはGETメソッドとほぼ同じです。get->post、params->dataに変更するだけです。裏側で処理されている内容は異なります。

    [In]
    import requests
    
    url = 'https://jsonplaceholder.typicode.com/posts'
    data = {'id':1}
    
    res = requests.post(url, data=data)
    res.json()
    
    [Out]
    {'id': 101}

    6.Requestsの引数

    6-1.プロキシサーバー経由:proxies

     大企業などではプロキシサーバーが使用されているため家でできても社内からできないことがあります。その場合はproxies引数にプロキシサーバーのURLを与えます。

    [In]※プロキシサーバーのURL:http://190.000.0.10:10000 と仮定
    import requests
    
    url = 'https://jsonplaceholder.typicode.com/posts'
    proxies ={
        'http':'190.000.0.10:10000',
        'https':'190.000.0.10:10000'
    }
    res = requests.get(url, proxies=proxies)
    print(res.status_code) # 200なら通信成功
    
    [Out]
    200

    6-2.Requestsの応用:画像取得

     Requestsを利用して画像を取得してみます。取得する画像は下記サイトに埋め込みしている猫の画像です。リンクはサイトの画像を右クリックして「リンクのアドレスをコピー」で取得しました。

    画像

     処理は通常通りrequests.get(url)で処理しますがそのままだとバイナリーデータ機械しか理解できない値が返ってきます。そのバイナリーデータをそのまま画像ファイルとして書き込むと画像が生成されます。

    [In]
    url_cat = 'https://assets.st-note.com/production/uploads/images/65617808/picture_pc_190dd8c991f9f5dc7391815450ab2fdd.png'
    res = requests.get(url_cat)
    
    with open('cat.png', 'wb') as f:
        f.write(res.content)
    画像

     もしURLのルールが決まっているのであればFor文処理でサイト内の動画をまとめて取得できます。

    7.Requestsの応用:Session

     Requestsライブラリの応用編としてセッション管理について紹介します。

    7-1.Cookie管理:requests.Session()

     訪問したサイトでCookieを取得したい場合はrequests.Session()を使用します。Cookieに関しては下記記事をご確認ください。

    [IN #セッションを使用してサイトにアクセスしてCookiesを取得する]
    session = requests.Session() #セッションを作成
    
    session.get('https://httpbin.org/cookies/set/sessioncookie/123456789') # cookieを取得
    res = session.get('https://httpbin.org/cookies') # cookieがある場合は表示するサイトにアクセス
    print(res.status_code)
    print(res.text)
    
    [OUT]
    200
    {
      "cookies": {
        "sessioncookie": "123456789"
      }
    }
    [IN #Cookieを取得せずにアクセスする]
    session = requests.Session() #セッションを作成
    res = session.get('https://httpbin.org/cookies') # cookieがある場合は表示するサイトにアクセス
    print(res.status_code)
    print(res.text)
    
    [OUT]
    200
    {
      "cookies": {}
    }

    7-2.サンプルコード

     noteでは非公式ですがAPIが実装されております。本APIを使用して

    1. サインイン用のエンドポイントにログイン情報をPOST

    2. ログイン後の情報からcookies取得

    3. cookies情報と合わせてAPIにGETを投げる

     まず駄目なパターンとしてエンドポイントにそのままGETでHTTPメソッドを実行します。エラーは出ませんが結果は欲しいものではありません。

    [IN]
    import requests
    import json
    
    url = 'https://note.com/api/v1/stats/pv?filter=all&page=1&sort=pv'
    res = requests.get(url)
    print(f'status code: {res.status_code}')
    print(res.text)
    [OUT]
    status code: 200
    {"error":{"code":"auth","message":"not_login"}}

     下記の通りrequestsのSessionを使用するとログインした状態で情報を抽出できるようになります。

    [IN]
    import requests
    import json
    
    login_url = 'https://note.com/api/v1/sessions/sign_in'
    login_data = {
        'login': <noteのログインI>,
        'password': <noteのログインパスワード> 
    }
    headers = {'Content-Type': 'application/json'} # ヘッダーの指定
    
    # ログイン処理
    session = requests.Session()
    res = session.post(login_url, 
                       headers=headers, 
                       data=json.dumps(login_data))
    
    print(f'Status code: {res.status_code}')
    
    # API呼び出し
    # ログイン成功、cookiesを取得
    cookies = session.cookies
    url = 'https://note.com/api/v1/stats/pv?filter=all&page=1&sort=pv'
    res = session.get(url, cookies=cookies)
    print(f'Status code: {res.status_code}')
    data_json = json.loads(res.text)
    
    
    print(cookies)
    [OUT]
    Status code: 201
    Status code: 200
    <RequestsCookieJar[<Cookie _note_session_v5=xxxxxxxxxxxxx for .note.com/>]>

    8.応用の練習編

    8-1.Pitapaへログイン

     今回はSeleniumを使用せずRequestだけでPitapaにログインしました。要領は下記の通りです。

    【処理プロセス】
    1.「サイトにアクセス×検証ツール」または「ログインサイトの情報をスクレイピング」して①inputタグのname、②formタグのactionなどを確認※
    2.コードを記載する。
    ※他サイトではCookieやTokenの情報が必要な場合もあります

     8-1-1.要素情報の取得

     初めにログインサイトに移動してログイン時に必要な情報を確認します。まずはIDとパスワードのinputタグにあるname属性の値を確認します。
     次にそのままポストしてもエラーが出たためformタグにあるactionの値も取得しました。
     要素の取得はスクレイピングでもできますが構造を理解するためにサイトから検証ツールを使用する方が個人的には好きです。

    画像
    [IN]
    import requests
    from bs4 import BeautifulSoup
    
    url = 'https://www2.pitapa.com/login.html'
    res = requests.get(url)
    res.encoding = res.apparent_encoding #文字コードを自動で変換
    soup = BeautifulSoup(res.text, "html.parser")
    print(soup.prettify())
    
    [OUT ※結果は一部抽出]
    <!--共通ナビゲーションメニュー ログイン-->
          <form action="/member/login.do" method="post" name="form1">
           <tr>
            <td class="K010100-idpw" style="text-align:center; padding:25px 0px 30px 0px;">
             <label>
              ID
             </label>
             <input class="s3" maxlength="16" name="id" size="8" style="width:200px; margin-right:30px;" type="text"/>
             <br class="pc-display-none"/>
             <label>
              パスワード
             </label>
             <input class="s3" maxlength="16" name="password" size="4" style="width:200px;" type="password"/>
            </td>
           </tr>
           <tr>
            <td style="text-align:center; padding-bottom:15px;">
             <input alt="ログイン" border="0" height="25" name="login" src="/common/img/login_b2.gif" type="image" width="92"/>
            </td>
           </tr>
          </form>

     8-1-2.Session()で接続してPOST

     上記で確認したIDとパスワードの要素名は変数login_infoのKEYとして渡して値は実際のログイン情報とします。Requestsのsession()で接続して、formタグにあったactionのurlへlogin_infoと合わせてPOSTすればログインできます。

    [IN]
    import requests
    from bs4 import BeautifulSoup
    
    url = 'https://www2.pitapa.com/member/login.do'
    loginID, password = '<username>', '<password>'
    
    #KEYはURLから要素確認して入力
    login_info = {'id':loginID,
                'password':password}
    
    session = requests.session() #セッションを作成
    res = session.post(url, data=login_info)
    
    print(res.cookies)
    print(res.headers, end='\n\n')
    
    
    res.encoding = res.apparent_encoding #文字コードを自動で変換
    soup = BeautifulSoup(res.text, "html.parser")
    print(soup.prettify())
    
    [OUT]
    <RequestsCookieJar[<Cookie pitapa=f4b12d2fa5f for www2.pitapa.com/>]>
    {'Date': 'Sun, 28 Aug 2022 08:45:20 GMT', 'Server': 'Apache', 'X-Frame-Options': 'SAMEORIGIN', 'Cache-Control': 'no-cache', 'Pragma': 'no-cache', 'Expires': 'Wed, 31 Dec 1969 15:00:00 GMT', 'Last-Modified': 'Sun, 28 Aug 2022 08:45:20 GMT', 'Content-Language': 'ja-JP', 'Set-Cookie': 'pitapa=f4b12d2bc7NzY6MjFhNDczNmUxMTpjNGYxNjVkOTU1OjgyZjY5YmUzMzc=:MTY2MTY3NjMyMDY1NQ==3381f71605c1736ddafa5f; path=/; secure; SameSite=None; Secure', 'Keep-Alive': 'timeout=15, max=97', 'Connection': 'Keep-Alive', 'Transfer-Encoding': 'chunked', 'Content-Type': 'text/html; charset=UTF-8'}
    
    <!-- 11be73022e3ac89e08c5e69954a1b6298fc9e3d6 -->
    <html lang="ja">
     <head>
      <meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
      <meta content="text/javascript" http-equiv="Content-Script-Type"/>
      <meta content="text/css" http-equiv="Content-Style-Type"/>
      <meta content="width=device-width, user-scalable=yes, initial-scale=1, minimum-scale=0.5, maximum-scale=2" name="viewport"/>
      <title>
       PiTaPa.com[ポストペイでらくらく決済。PiTaPaで新しい生活はじめよう。]
      </title>

    9.HTTPクライアントでできること

     とりあえず現状では私はよく下記に利用しています。

    9-1.APIの利用 

     APIを利用して様々なサービスを高速で利用できます。またFAST APIなどによる自作APIを使用すれば自分で作成したプログラムもAPIで利用できます。

    9-2.Webスクレイピング(Beautiful Soup)

     Webスクレイピングはサイト内のほしい情報を抽出する処理です。スクレイピングの有名なライブラリとしてBeautiful Soupがあります。

     実際の処理方法としては①Requestsでサイト内のHTMLデータを取得、②Beuatiful SoupでHTMLデータを解析・ほしいデータを取得します。

    参考資料


    あとがき

     学習時はかなり苦労したような気がするけど、覚える内容はこんなものだったかな・・・・・とりあえず思い出したら追記予定。

     
     
     

    KIYO

     
     
    普段は製造業で企画/開発/設計しております。記事はプログラミング・機械学習、IoT関係の記事をメインで作成し、なるべく1つの記事で知りたいことを網羅していきます。内容は学術的より実装・アウトプット(ほしくなるもの)を重視して作成しています。 面白そうな仕事があればやりたいです!

    あなたへのおすすめ