Logo

파이썬에서 requests 라이브러리로 원격 API 호출하기

requests는 파이썬으로 HTTP 통신이 필요한 프로그램을 작성할 때 가장 많이 사용되는 라이브러리입니다. 특히 원격에 있는 API를 호출할 때 유용하게 사용할 수 있는데요. 이번 포스팅에서는 requests 라이브러리를 사용하는 방법에 대해서 알아보겠습니다.

패키지 설치

파이썬의 패키지 매니저인 pip를 이용해서 requests 패키지을 설치합니다.

$ pip install requests
Collecting requests
  Downloading requests-2.25.0-py2.py3-none-any.whl (61 kB)
     |████████████████████████████████| 61 kB 3.1 MB/s
Collecting urllib3<1.27,>=1.21.1
  Downloading urllib3-1.26.2-py2.py3-none-any.whl (136 kB)
     |████████████████████████████████| 136 kB 6.1 MB/s
Collecting certifi>=2017.4.17
  Downloading certifi-2020.12.5-py2.py3-none-any.whl (147 kB)
     |████████████████████████████████| 147 kB 4.9 MB/s
Collecting idna<3,>=2.5
  Downloading idna-2.10-py2.py3-none-any.whl (58 kB)
     |████████████████████████████████| 58 kB 8.6 MB/s
Collecting chardet<4,>=3.0.2
  Downloading chardet-3.0.4-py2.py3-none-any.whl (133 kB)
     |████████████████████████████████| 133 kB 6.7 MB/s
Installing collected packages: urllib3, certifi, idna, chardet, requests
Successfully installed certifi-2020.12.5 chardet-3.0.4 idna-2.10 requests-2.25.0 urllib3-1.26.2

설치가 잘 되었는지 파이썬 인터프리터를 실행하여 확인해봅니다.

$ python
Python 3.9.0 (default, Oct 17 2020, 15:32:58)
[Clang 11.0.3 (clang-1103.0.32.62)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import requests
>>> requests.get("https://google.com")
<Response [200]>

requests 라이브러리로 구글에 접속을 해보니 상태 코드 200이 응답이 되는 것을 볼 수 있습니다. 🎉

API

requests 라이브러리는 매우 직관적인 API를 제공하는데요. 어떤 방식(method)의 HTTP 요청을 하느냐에 따라서 해당하는 이름의 함수를 사용하면 됩니다.

  • GET 방식: requests.get()
  • POST 방식: requests.post()
  • PUT 방식: requests.put()
  • DELETE 방식: requests.delete()

응답 상태

온라인 서비스를 HTTP로 호출하면 상태 코드를 응답받게 됩니다. 일반적으로 이 상태 코드를 보고 요청이 잘 처리되었는지 문제가 있는지 알 수가 있습니다.

상태 코드는 응답 객체의 status_code 속성을 통해 간단하게 얻을 수 있습니다.

>>> response = requests.get("https://jsonplaceholder.typicode.com/users/1")
>>> response.status_code
200
>>> response = requests.get("https://jsonplaceholder.typicode.com/users/100")
>>> response.status_code
404
>>> response = requests.post("https://jsonplaceholder.typicode.com/users")
>>> response.status_code
201

응답 전문

요청이 정상적으로 처리가 된 경우, 응답 전문(response body/payload)에 요청한 데이터가 담겨져 옵니다. 응답 전문은 크게 3가지 방식으로 읽어올 수 있습니다.

>>> response = requests.get("https://jsonplaceholder.typicode.com/users/1")

첫 번째는 content 속성을 통해 바이너리 원문을 얻을 수 있습니다.

>>> response.content
b'{\n  "id": 1,\n  "name": "Leanne Graham",\n  "username": "Bret",\n  "email": "Sincere@april.biz",\n  "address": {\n    "street": "Kulas Light",\n    "suite": "Apt. 556",\n    "city": "Gwenborough",\n    "zipcode": "92998-3874",\n    "geo": {\n      "lat": "-37.3159",\n      "lng": "81.1496"\n    }\n  },\n  "phone": "1-770-736-8031 x56442",\n  "website": "hildegard.org",\n  "company": {\n    "name": "Romaguera-Crona",\n    "catchPhrase": "Multi-layered client-server neural-net",\n    "bs": "harness real-time e-markets"\n  }\n}'

두 번째는 text 속성을 통해 UTF-8로 인코딩된 문자열을 얻을 수 있습니다.

>>> response.text
'{\n  "id": 1,\n  "name": "Leanne Graham",\n  "username": "Bret",\n  "email": "Sincere@april.biz",\n  "address": {\n    "street": "Kulas Light",\n    "suite": "Apt. 556",\n    "city": "Gwenborough",\n    "zipcode": "92998-3874",\n    "geo": {\n      "lat": "-37.3159",\n      "lng": "81.1496"\n    }\n  },\n  "phone": "1-770-736-8031 x56442",\n  "website": "hildegard.org",\n  "company": {\n    "name": "Romaguera-Crona",\n    "catchPhrase": "Multi-layered client-server neural-net",\n    "bs": "harness real-time e-markets"\n  }\n}'

마지막으로, 응답 데이터가 JSON 포맷이라면 json() 함수를 통해 사전(dictionary) 객체를 얻을 수 있습니다.

>>> response.json()
{'id': 1, 'name': 'Leanne Graham', 'username': 'Bret', 'email': 'Sincere@april.biz', 'address': {'street': 'Kulas Light', 'suite': 'Apt. 556', 'city': 'Gwenborough', 'zipcode': '92998-3874', 'geo': {'lat': '-37.3159', 'lng': '81.1496'}}, 'phone': '1-770-736-8031 x56442', 'website': 'hildegard.org', 'company': {'name': 'Romaguera-Crona', 'catchPhrase': 'Multi-layered client-server neural-net', 'bs': 'harness real-time e-markets'}}

응답 헤더

응답에 대한 메타 데이터를 담고 있는 응답 헤더는 headers 속성을 통해 사전의 형태로 얻을 수 있습니다.

>>> response = requests.get("https://jsonplaceholder.typicode.com/users/1")
>>> response.headers
{'Date': 'Sat, 12 Dec 2020 21:10:49 GMT', 'Content-Type': 'application/json; charset=utf-8', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Set-Cookie': '__cfduid=d92df672c0d58b06b245dd0b8d317e2141607807449; expires=Mon, 11-Jan-21 21:10:49 GMT; path=/; domain=.typicode.com; HttpOnly; SameSite=Lax', 'X-Powered-By': 'Express', 'X-Ratelimit-Limit': '1000', 'X-Ratelimit-Remaining': '999', 'X-Ratelimit-Reset': '1607798104', 'Vary': 'Origin, Accept-Encoding', 'Access-Control-Allow-Credentials': 'true', 'Cache-Control': 'max-age=43200', 'Pragma': 'no-cache', 'Expires': '-1', 'X-Content-Type-Options': 'nosniff', 'Etag': 'W/"1fd-+2Y3G3w049iSZtw5t1mzSnunngE"', 'Via': '1.1 vegur', 'CF-Cache-Status': 'HIT', 'Age': '9352', 'cf-request-id': '06fa63d142000038668b9a7000000001', 'Expect-CT': 'max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"', 'Report-To': '{"endpoints":[{"url":"https:\\/\\/a.nel.cloudflare.com\\/report?s=Vk2e8Q%2FBK4wOSQc12Cgs0nqvZHpyUb4c0o%2BWCgLzwdqPLQM2HJ5hNHW%2Fmc8fNr73wqQ2LrzEdScfv5bejTYVrXRlUfAyPcGnv1me%2BHlZKc7IKKOi%2BO%2ButGVrdkWS"}],"group":"cf-nel","max_age":604800}', 'NEL': '{"report_to":"cf-nel","max_age":604800}', 'Server': 'cloudflare', 'CF-RAY': '600a6f2edfe23866-IAD', 'Content-Encoding': 'gzip'}
>>> response.headers['Content-Type']
'application/json; charset=utf-8'

요청 쿼리

GET 방식으로 HTTP 요청을 할 때는 쿼리 스트링(query string)을 통해 응답받을 데이터를 필터링하는 경우가 많습니다.

params 옵션을 사용하면 쿼리 스크링을 사전의 형태로 넘길 수 있습니다.

# https://jsonplaceholder.typicode.com/posts?userId=1
>>> response = requests.get("https://jsonplaceholder.typicode.com/posts", params={"userId": "1"})
>>> [post["id"] for post in response.json()]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

요청 전문

POST나 PUT 방식으로 HTTP 요청을 할 때는 보통 요청 전문(request body/payload)에 데이터를 담아서 보내는데요.

data 옵션을 사용하면, HTML 양식(form) 포맷의 데이터를 전송할 수 있으며, 이 때 Content-Type 요청 헤더는 application/x-www-form-urlencoded로 자동 설정됩니다.

>>> requests.post("https://jsonplaceholder.typicode.com/users", data={'name': 'Test User'})
<Response [201]>

json 옵션을 사용하면, REST API로 JSON 포맷의 데이터를 전송할 수 있으며, 이 때 Content-Type 요청 헤더는 application/json로 자동 설정됩니다.

>>> requests.post("https://jsonplaceholder.typicode.com/users", json={'name': 'Test User'})
<Response [201]>

요청 헤더

headers 옵션을 사용하면 요청 헤더도 직접 설정할 수 있는데요. 인증 토큰을 보낼 때 유용하게 사용할 수 있습니다.

>>> requests.post("https://jsonplaceholder.typicode.com/users", headers={'Authorization': 'Bearer 12345'})
<Response [201]>

전체 코드

본 포스팅에서 제가 작성한 전체 코드는 아래에서 직접 확인하고 실행해보실 수 있습니다.

https://dales.link/wxd

마치면서

이상으로 파이썬의 requests 라이브러리의 기본적인 사용 방법을 살펴보았습니다. 파이썬에 내장된 모듈은 아니지만 HTTP 호출을 할 때 거의 표준처럼 사용되는 라이브러리이기 때문에 사용법을 잘 숙지해두시면 큰 도움이 되실 겁니다.