본문 바로가기
목차
Python

[requests] Python의 requests 라이브러리 사용법.

by ds31x 2025. 8. 29.
728x90
반응형

https://www.activestate.com/resources/quick-reads/how-to-pip-install-requests-python-package/

 

requests는 Python에서 HTTP 요청을 간단하고 직관적으로 보낼 수 있게 해주는 가장 널리 쓰이는 라이브러리임.

  • 복잡한 소켓 프로그래밍이나 urllib 모듈보다 훨씬 쉬운 인터페이스를 제공
  • GET/POST/PUT/PATCH/DELETE 등 주요 HTTP 메서드를 한 줄 코드로 처리할 수 있음.
  • 또한 쿼리 파라미터, 헤더, 쿠키, 파일 업로드, 인증, 세션 관리 등 웹 API와 상호작용하는 데 필요한 기능을 모두 지원함.

 

다음의 URL을 한번 살펴보길 꼭 권함:

Official Quick Start: https://requests.readthedocs.io/en/latest/user/quickstart/


1. Pre-requisite: HTTP

HTTP는 클라이언트(브라우저, 프로그램)와 서버가 통신하는 protocol (규약).

클라이언트는 메서드(method), URL, 헤더(headers), 본문(body) 을 포함한 request(요청)을 보내고, 서버는 상태 코드와 response(응답)을 반환함.

 

다음은 HTTP의 주요 메서드임:

  • GET: 조회 (데이터 읽기)
    • 서버의 resource(html 파일 등)를 다운로드하는데 주로 사용됨.
  • POST: 생성·전송 (데이터 추가)
    • 서버에 새로운 resource를 업로드하는데 사용됨: idempotent(멱등성) 미보장.
  • PUT: 전체 갱신 (리소스 교체, idempotent)
    • 서버의 기존 resource를 전체 갱신: idempotent 보장!
  • PATCH: 부분 수정 (필드 일부만 변경)
    • 서버의 기존 resource의 일부만 갱신: idempotent 미보장
  • DELETE: 삭제

다음은 주요 상태 코드임:

  • 200 OK: 성공
  • 201 Created: 새 리소스 생성됨
  • 202 Accepted: 요청이 수락되었으나 완료되지 않았음.
  • 204 No Content: 내용없음
  • 400 Bad Request: 잘못된 요청
  • 401 Unauthorized: 인증 필요
  • 404 Not Found: 리소스 없음
  • 409 Conflict: 충돌
  • 500 Internal Server Error: 서버 오류

2. Response Object (응답 객체)

requests 라이브러리에서 모든 request에 해당하는 함수들(get, post, put, patch 등)의 결과는 Response 객체로 반환됨.

Response 객체는 요청/응답에 대한 다양한 속성과 메서드를 제공하여, requests 라이브러리를 다룰 때 핵심적으로 사용되는 객체임

주요 attributes

  • response.request: 실제 전송된 요청(헤더, URL, 바디 등)
  • response.status_code: HTTP 상태 코드
  • response.raise_for_status(): 상태코드가 4xx/5xx일 때 예외 발생
  • response.json(): JSON 응답을 Python dict로 변환
  • response.content: 응답 원문 (bytes 객체)
  • response.text: 문자열 (encoding 적용됨)
  • response.encoding: 문자열 해석 시 사용할 문자셋 (자동 추정되나 필요시 수동 지정 가능)
  • response.cookies: 서버에서 설정한 쿠키들 (RequestsCookieJar 객체, 딕셔너리처럼 접근 가능)
  • response.headers: 응답 헤더들 (대소문자 구분 없는 dictionary 형태, CaseInsensitiveDict 객체)
import requests

r = requests.get("https://httpbin.org/get", params={"검색어": "파이썬"})

# 요청 객체
print("요청 메서드:", r.request.method)      # GET
print("요청 URL:", r.request.url)           # 최종 요청된 URL
print("요청 헤더:", r.request.headers)      # 보낸 헤더

# 상태 코드
print("응답 코드:", r.status_code)          # 200 등

# 예외 발생 (4xx/5xx일 때)
try:
    r.raise_for_status()
except requests.exceptions.HTTPError as e:
    print("HTTP 오류:", e)

# JSON 응답
print("JSON keys:", list(r.json().keys()))

# 원문 바이트열
print("content 타입:", type(r.content))

# 문자열 변환
print("본문 일부:", r.text[:80], "...")

# 인코딩
print("자동 인코딩:", r.encoding)
# r.encoding = "euc-kr"  # 필요시 수동 지정
  • https://httpbin.org/get은 HTTP GET 요청을 테스트할 수 있는 웹 서비스 URL.
  • 이 URL로 요청을 보내면 헤더 정보, IP 주소, URL 등의 요청 세부사항을 JSON 형태로 반환.
  • 개발자들이 HTTP 클라이언트나 API 요청이 올바르게 작동하는지 확인하는 데 자주 사용되는 도구

3. GET Request (조회)

GET은 서버에서 데이터를 가져올(download) 때 사용.

  • Query Parameters 는 params 파라미터를 사용하여 dict로 지정하면 자동 인코딩됨.
  • 최종 URL은 반환값이 response에서 response.request.url attribute로 확인할 수 있음.
r = requests.get("https://httpbin.org/get", params={"page": 2, "검색어": "python"})

print("최종 URL:", r.request.url)     # 200이면 정상
print("상태 코드:", r.status_code)
print("본문 일부:", r.text[:100], "...")

# JSON 응답일 때는 dict로 파싱
try:
    print("JSON 응답:", r.json())
except ValueError:
    print("JSON 변환 실패(응답이 JSON이 아님)")

다운로드 대상이 image나 pdf등의 특정 file인 경우엔 response.content를 이용한다.

r = requests.get("https://httpbin.org/image/png")
with open("image.png", "wb") as f:
    f.write(r.content)
  • 작은 파일의 경우 r.content로 전체 바이트 데이터를 한번에 읽을 수 있음.

다음과 같이 stream=true 인자를 주면 데이터를 chunk로 나누어서 읽어들이므로 대용량 파일을 다운로드 하는데 적합함.

with requests.get(url, stream=True) as r:
    r.raise_for_status()  # 4xx/5xx 상태코드시 시 exception을 raise
    with open(tarball_path, "wb") as f:
        for chunk in r.iter_content(chunk_size=8192):
            if chunk:  # keep-alive 용으로 보내지는 비어있는 chunk는 if문을 통해 건너뜀.
                f.write(chunk)
  • iter_content()는 응답 스트림을 chunk_size 단위로 잘라서 바이트 덩어리를 yield 함.
  • HTTP/1.1에서는 keep-alive 연결 때문에 중간에 빈 바이트 문자열 (b"")이 전달될 수 있음: keep-alive chunk라고 불림.
  • 이는 연결확인용 신호에 불과하므로 if chunk:로 무시할 수 있음.
  • r.raise_for_status() 는 아래에 나오는 Error Handling 절을 참고할 것.

4. POST Request (생성·전송)

POST는 서버에 데이터를 전송하거나 새 리소스를 만들 때 사용함.

  • form 데이터는 data 파라미터에 대한 인자로 넘겨주고
  • JSON은 json 파라미터에 대한 인자로 설정함.
# Form 전송: 전통적인 웹 로그인/제출 폼과 유사
form = {"username": "kim", "password": "1234"}
r1 = requests.post("https://httpbin.org/post", data=form)
print("Form 전송 결과:", r1.json().get("form"))

# JSON 전송: 현대 REST/JSON API에서 일반적
payload = {"id": 1, "value": "abc"}
r2 = requests.post("https://httpbin.org/post", json=payload)
print("JSON 전송 결과:", r2.json().get("json"))
  • https://httpbin.org/post은 HTTP POST 요청을 테스트할 수 있는 웹 서비스 URL.
  • 클라이언트가 전송한 form data, json, files 등의 내용을 그대로 응답 JSON 안에 에코해 줌: 전송 데이터 확인 및 디버깅에 유용함.

주의할 것은 위의 예제에서 넘겨지는 form에 하나의 키에 list 객체로 여러 값을 지정할 수도 있음.

payload_tuples = [('key1', 'value1'), ('key1', 'value2')]
response_1 = requests.post('https://httpbin.org/post', data=payload_tuples)

payload_dict = {'key1': ['value1', 'value2']}
response_2 = requests.post('https://httpbin.org/post', data=payload_dict)

파일업로드에 POST를 사용하는 경우는 files파라미터에 업로드할 파일들의 이름과 파일들의 경로를 dict로 설정하면 됨: 뒤의 File Upload 절을 참고.


5. PUT Request (전체 갱신)

PUT은 리소스를 전체적으로 교체할 때 사용되는 HTTP 메서드임.
같은 요청을 여러 번 보내도 결과가 동일한 멱등성(idempotent)을 가짐.

# 리소스 전체 상태를 한 번에 대체한다는 가정
full_state = {
    "id": 101,
    "name": "Alice",
    "role": "dentist",
    "active": True
}
r = requests.put("https://httpbin.org/put", json=full_state)

print("상태 코드:", r.status_code)                 # 보통 200 또는 204
print("요청 바디(JSON):", resp.request.body)       # 디버깅: 보낸 페이로드 확인
print("서버가 받은 JSON:", r.json().get("json"))    # httpbin은 에코해 줌
  • https://httpbin.org/put은 HTTP PUT 요청을 테스트하기 위한 엔드포인트 URL.
  • PUT 메서드로 데이터를 전송하면 요청 헤더, 본문 내용, IP 주소 등의 정보를 JSON 형태로 반환함.

requests에서 json 파라미터를 사용하면 헤더의 Content-TypeApplication/json으로 변경됨.


6. PATCH Request (부분 수정)

PATCH는 리소스의 일부 속성만 수정할 때 사용되는 HTTP 메서드임.

  • 보통 바꾸고 싶은 필드만 JSON에 담아 전송함.
  • 단, 파일 변경은 JSON 대신 multipart를 쓰거나 별도 업로드 엔드포인트를 둔다
partial = {"role": "oral_surgeon"}
r = requests.patch("https://httpbin.org/patch", json=partial)

print("상태 코드:", r.status_code) # 보통 200 또는 204
print("서버가 받은 JSON:", r.json().get("json")) # httpbin은 에코
  • https://httpbin.org/patch는 클라이언트가 전송한 데이터를 “수정 요청(PATCH 방식)” 형태로 받아, 그 내용을 다시 JSON으로 돌려주는 에코(echo) 서비스임.

7. File Upload (파일 업로드)

파일 업로드는 post() 함수에서 files 인자를 사용하면 자동으로 multipart/form-data로 인코딩됨.

# 단일 파일
with open("test.txt", "rb") as f:
    files = {"file": f}
    r = requests.post("https://httpbin.org/post", files=files)
    print("업로드된 파일:", r.json().get("files"))

# 복수 파일 + 추가 필드
with open("report.pdf", "rb") as f1, open("photo.png", "rb") as f2:
    files = {
        "doc": ("report.pdf", f1, "application/pdf"),
        "image": ("photo.png", f2, "image/png"),
        # "doc": ("report.pdf", f1),  #content type을 지정하지 않을 수도 있음.
        # "image": ("photo.png", f2), #content type을 지정하지 않을 수도 있음.
    }
    data = {"작성자": "김만용", "설명": "임플란트 자료"}
    r = requests.post("https://httpbin.org/post", files=files, data=data)
    print("서버 form:", r.json().get("form"))      # data 필드
    print("서버 files:", r.json().get("files"))    # 업로드된 파일 미러

8. Error Handling (예외 처리)

반환된 response 객체에서 raise_for_status()메서드를 호출하면 응답의 상태코드를 체크하고,
응답코드가 4xx/5xx인 경우 예외를 발생시킴.

try:
    r = requests.get("https://httpbin.org/status/404")
    r.raise_for_status()
except requests.exceptions.HTTPError as e:
    print("HTTP 오류:", e)

9. Timeout (타임아웃)

무한 대기를 방지하기 위해 timeout을 지정을 할 수도 있음.
timeout 파라미터에 (connect, read) 튜플을 설정하여 처리함.

  • connect : 서버와 연결(TCP소켓연결)되는데 기다리는 최대 대기시간 (sec)
  • read : 서버와 연결된 이후 응답에 대한 read 연산이 완료될 때까지 최대 대기시간 (sec)
    • stream=True로 chunk로 나누어 read될 경우, 각각의 최대 대기시간임.

timeout=10 처럼 단일 값으로도 지정가능한데 이경우 connnectread 모두 10임.

import requests

try:
    # 연결은 2초 안에 맺어져야 하고, 응답 바디는 5초 안에 시작되어야 함
    r = requests.get("https://httpbin.org/delay/10", timeout=(2, 5))
except requests.exceptions.ConnectTimeout:
    print("연결(connect) 타임아웃 발생")
except requests.exceptions.ReadTimeout:
    print("읽기(read) 타임아웃 발생")

10. Headers & Cookies (헤더와 쿠키)

API 서버는 헤더와 쿠키를 통해 사용자와 상태를 구분함.


headerscookies 인자를 이용하여 요청에 추가가 가능하며,
reponse의 headerscookies 속성을 통해 응답된 헤더와 쿠기에 접근 가능함.

import requests

# -------------------
# 1. 사용자 정의 헤더 전송
custom_headers = {"User-Agent": "MyApp/1.0"}
r1 = requests.get("https://httpbin.org/headers", headers=custom_headers)

print("=== 요청에 보낸 헤더 ===")
print(custom_headers)

print("\n=== 서버 응답 헤더 ===")
# 응답 헤더는 dict 비슷한 객체 (대소문자 구분 없음)
print(r1.headers)
print("Content-Type:", r1.headers.get("Content-Type"))

print("\n=== 서버 응답 쿠키 ===")
# 서버가 내려준 쿠키 (RequestsCookieJar 객체)
print(r1.cookies)


# -----------
# 2. 쿠키 전송
custom_cookies = {"session_id": "abc123"}
r2 = requests.get("https://httpbin.org/cookies", cookies=custom_cookies)

print("\n=== 요청에 보낸 쿠키 ===")
print(custom_cookies)

print("\n=== 서버 응답 헤더 ===")
print(r2.headers)

print("\n=== 서버 응답 쿠키 ===")
# 반복문으로 개별 쿠키 접근
for c in r2.cookies:
    print(f"{c.name} = {c.value}")
  • headers=..., cookies=... : 요청에 포함시킨 헤더/쿠키
  • r.headers : 서버가 돌려준 응답 헤더
  • r.cookies : 서버가 내려준 쿠키 (RequestsCookieJar)

11. Authentication & Session (로그인/인증)

일부 resource 접근은 단순 요청만으로 가능하지만, 인증을 요구하기도 함.

requests는 다양한 로그인/인증 방식을 지원하며, 대표적으로 다음을 지원:

  • 세션 기반 로그인,
  • HTTP Basic 인증
  • Bearer 토큰 인증

11-1. 세션 로그인 (쿠키 기반)

웹사이트 로그인은 주로 폼(form) 제출 후 서버가 인증용 쿠키(세션ID를 포함)를 발급하는 방식임.
이 경우 requests.Session()을 사용하여 Session객체를 얻고 이의 post 메서드를 통해 로그인 한다.
이후 해당 Session 객체의 메서드들을 통해 이루어지는 요청들은 인증을 위한 로그인 세션 쿠키가 자동으로 포함됨.

import requests

# 세션 생성
s = requests.Session()

# 로그인 (폼 데이터 전송)
login_data = {"username": "kim", "password": "secret"}
login_resp = s.post("https://example.com/login", data=login_data)
print("로그인 상태 코드:", login_resp.status_code)

# 세션을 유지한 채 프로필 페이지 접근 (쿠키 자동 포함)
profile = s.get("https://example.com/profile")
print("프로필 길이:", len(profile.text))
  • s.post("/login") 했을 때 서버가 Set-Cookie 헤더를 내려주고,
  • 그걸 requests.Session 객체 s가 저장해 두었다가 이후 s.get("/profile")에 자동으로 포함시켜 주는 방식

실제 서비스에선 위와 같이 단순한 경우는 거의 없음.
실전에서는 CSRF, action URL, 헤더, 리다이렉트, 성공 판정, 타임아웃/예외 처리까지 챙겨야 안정적으로 로그인 유지가 됨.
이는 이 문서에서 다룰 범위를 넘어서는 내용임.

 

참고로, Token 기반 인증 (OAuth2/JWT)의 경우엔 로그인 페이지 응답으로 access token을 얻어서 이후 인증에 사용.

import requests

s = requests.Session()

# 예시: 로그인 응답이 {"access_token": "abc123"} 형태라고 가정
# login_data = {"username": "kim", "password": "secret"}
# login_resp = s.post("https://example.com/login", data=login_data)
# token = login_resp.json()["access_token"]
fake_resp = {"access_token": "abc123"}
token = fake_resp["access_token"]

# 세션에 Bearer 토큰 추가
s.headers.update({"Authorization": f"Bearer {token}"})

# httpbin은 토큰 값을 그대로 돌려줌
r = s.get("https://httpbin.org/bearer")
print(r.json())
  • s.get, s.post 등 모든 요청에 Authorization: Bearer <토큰> 헤더가 자동으로 포함됨

로그인 및 인증 동작을 정리하면 다음과 같음:

  1. s.post("/login", data=login_data)
    • 쿠키 기반 인증이라면 서버가 Set-Cookie를 내려줌.
    • Token 기반 인증(OAuth2/JWT)이라면 서버가 {"access_token": "...", ...} 같은 JSON을 내려줌.
  2. token = login_resp.json()["access_token"]
    • 응답 JSON에서 액세스 토큰 문자열을 추출.
  3. s.headers.update({"Authorization": f"Bearer {token}"})
    • 세션 객체의 헤더에 Authorization: Bearer <토큰>을 등록합니다.
  4. 이후 s.get(), s.post() 등 모든 요청에 자동으로 해당 헤더가 포함됨.

11-2. HTTP Basic 인증

Basic 인증은 요청마다 "Authorization: Basic <base64(user:pass)>" 헤더를 붙여 서버에 아이디/비밀번호를 전달하는 방식임.

보안상 반드시 HTTPS와 함께 사용해야 함: 아닌 경우, 패스워드와 같은 민감 정보가 평문(Base64 인코딩)으로 노출될 수 있음.

from requests.auth import HTTPBasicAuth

# Basic Auth 예제 (httpbin은 테스트용 엔드포인트 제공)
r1 = requests.get("https://httpbin.org/basic-auth/user/pass",
                  auth=HTTPBasicAuth("user", "pass"))

print("Basic 인증:", r1.status_code, r1.json())

11-3. Bearer 토큰 인증

Bearer 토큰은 주로 OAuth2나 JWT(JSON Web Token) 기반 인증 시스템에서 사용됨.

서버가 클라이언트에게 토큰 문자열을 발급하면, 이후 요청에서 Authorization 헤더에 "Bearer <토큰값>"을 넣어 인증을 수행합니다.
비밀번호보다 안전하게 설계되었으며, 만료 시간(expiry)을 두어 재발급 절차를 거치게 하는 경우가 많음.

token = "YOUR_TOKEN"

# 단일 요청에만 Bearer 토큰 사용
r2 = requests.get("https://httpbin.org/bearer",
                  headers={"Authorization": f"Bearer {token}"})
print("Bearer 인증:", r2.status_code, r2.json())

여러 요청에서 동일한 토큰을 반복적으로 사용해야 한다면, 앞서 본 것처럼 Session.headers.update()를 이용해 세션 전체에 토큰을 설정할 수 있음.

s = requests.Session()

# 세션에 공통 헤더 등록 (모든 요청에 자동 포함)
s.headers.update({"Authorization": f"Bearer {token}"})

# 이후 요청들은 자동으로 Bearer 토큰을 포함
r3 = s.get("https://httpbin.org/bearer")
print("세션 Bearer 인증:", r3.status_code, r3.json())

r4 = s.get("https://httpbin.org/get")
print("r4 Authorization 헤더:", r4.request.headers["Authorization"])
  • "YOUR_TOKEN" 은 Bearer Token (Access Token)을 의미.

참고: Token (Access Token, Bearer Token)

  • 주로 OAuth2나 JWT(JSON Web Token) 기반 인증에서 사용
  • API 키와 달리 로그인/인증 과정을 거쳐 동적으로 발급됨
  • 짧은 만료 시간(expiry)을 가지고, Refresh Token으로 갱신 가능
  • 반드시 헤더에 Authorization: Bearer <token> 형태로 사용: (RFC 6750, Bearer Token Usage).

Bearer Token은 서비스마다 다른 이름으로 불림.

  • GitHub Personal Access Token : 사실상 API Key처럼 쓰이지만 Authorization: Bearer ...로 헤더에 추가됨.
  • Google OAuth2 Access Token : 전형적인 Bearer Token.

참고: API Key vs. Bearer Token

  • API Key
    • 고정 문자열 (발급 후 장기간 유효하거나 무제한)
    • 사용자/애플리케이션을 식별하는 “정적 인증 수단”
    • 보통 Authorization 헤더나 쿼리 파라미터(?key=...)로 전달
  • Bearer Token
    • 로그인이나 권한 부여 과정을 거쳐 동적으로 발급
    • (짧은) 만료 시간이 있음
    • 반드시 Authorization: Bearer ... 형태로 사용

같이보면 좋은 자료

https://requests.readthedocs.io/en/latest/user/quickstart/

 

2025.08.28 - [Python] - [urllib] request 모듈

 

 

728x90

'Python' 카테고리의 다른 글

Isolation Forest :  (0) 2025.09.17
[Ex] 사칙연산기 (CLI) 간단 구현하기-입력받기.  (0) 2025.09.15
[urllib] request 모듈  (1) 2025.08.28
Exceptions and Debugging Tools  (1) 2025.08.18
CLI Program에서의 arguments - argparse모듈  (1) 2025.08.12