파이썬 requests Session 사용법, s.headers.update와 s.params 기본값 설정, s.close로 소켓 해제까지
🐍 한 번의 설정으로 모든 요청에 공통 헤더·파라미터를 적용하고 안전하게 연결을 종료하는 실전 가이드
프로젝트가 커질수록 매 요청마다 헤더와 쿼리를 반복 입력하는 일은 번거롭고, 실수로 누락되면 장애로 이어질 수 있습니다.
requests의 Session을 사용하면 공통 설정을 한곳에 모아 코드 중복을 줄이고, 쿠키와 연결을 효율적으로 재사용할 수 있습니다.
또한 세션을 닫지 않으면 소켓이 해제되지 않아 리소스가 쌓일 수 있는데, s.close()를 통해 깔끔하게 정리할 수 있습니다.
이 글은 s.headers.update로 공통 헤더를 설정하고, s.params로 기본 쿼리 파라미터를 지정하며, 마지막으로 s.close()로 소켓을 해제하는 필수 패턴을 이해하기 쉽게 정리합니다.
실무에서 바로 복사해 쓸 수 있는 구조와 함께 안정적인 요청 흐름을 만드는 방법을 차근차근 안내합니다.
핵심은 세 가지입니다.
첫째, 공통 헤더는 s.headers.update로 한 번만 정의해 모든 요청에 자동 적용합니다.
둘째, 반복되는 쿼리는 s.params에 기본값으로 등록해 필수 파라미터 누락을 방지합니다.
셋째, 사용이 끝난 세션은 s.close()로 명시적으로 닫아 연결 풀의 소켓을 반환합니다.
이 3단계를 습관처럼 적용하면 코드 가독성이 좋아지고, 네트워크 리소스 사용이 안정화되며, 디버깅 포인트도 줄어듭니다.
아래 목차를 따라 차근히 확인해 보세요.
📋 목차
🔗 requests.Session 개념과 기본 구조
requests의 Session은 여러 HTTP 요청에 공통 설정과 상태를 유지해 주는 컨텍스트입니다.
쿠키, 인증 토큰, 기본 헤더, 기본 쿼리 파라미터를 한 번 지정하면 같은 세션에서 수행하는 모든 요청에 자동으로 반영됩니다.
또한 내부적으로 커넥션 풀을 사용해 TCP 연결을 재사용하므로, 매 요청마다 새 연결을 여닫는 오버헤드를 줄일 수 있습니다.
이 덕분에 성능과 안정성이 개선되고, 코드 중복과 누락 위험도 동시에 낮아집니다.
세션은 독립 객체이기 때문에 목적별로 분리해 사용하면 테스트와 유지보수에도 유리합니다.
세션의 핵심 속성으로는 공통 헤더 관리를 위한 s.headers, 기본 쿼리를 정의하는 s.params, 인증 정보를 담는 s.auth, 프록시 설정을 위한 s.proxies 등이 있습니다.
특히 s.headers.update({…})로 공통 헤더를, s.params = {…}로 기본 쿼리 파라미터를 지정하면 이후 get, post 등 요청 메서드 호출 시 자동으로 병합되어 적용됩니다.
요청 단위에서 동일 키를 다시 지정하면 그 값이 우선합니다.
이 설계는 “기본값은 세션, 특이값은 요청”이라는 명확한 우선순위를 제공합니다.
세션은 네트워크 자원을 보유합니다.
사용이 끝나면 s.close()로 소켓을 해제하고 커넥션 풀을 정리해야 합니다.
명시적으로 닫지 않으면 파일 디스크립터가 쌓이거나, 장시간 실행되는 프로세스에서 리소스 누수가 발생할 수 있습니다.
컨텍스트 매니저(with requests.Session() as s:)를 사용하면 블록을 벗어날 때 자동으로 close()가 호출되어 안전합니다.
장기 실행 서비스에서 세션 수명 주기를 의도적으로 설계하는 관점이 특히 중요합니다.
import requests
# 1) 세션 생성
s = requests.Session()
# 2) 공통 헤더/쿼리 기본값 정의
s.headers.update({
"User-Agent": "my-app/1.0",
"Accept": "application/json",
})
s.params = {
"locale": "ko_KR",
"apikey": "YOUR_API_KEY",
}
# 3) 요청마다 공통 설정이 자동 적용됨
r1 = s.get("https://api.example.com/items") # ?locale=ko_KR&apikey=...
r2 = s.get("https://api.example.com/items", params={"page": 2}) # 기본값 + page 병합
# 4) 세션 종료로 소켓 해제 (중요)
s.close()
💎 핵심 포인트:
세션은 상태와 기본값을 모아 재사용하는 컨테이너이며, s.headers.update와 s.params로 공통 규칙을 정의하고, s.close()로 소켓을 해제해 리소스를 회수하는 것이 안전한 사용의 핵심입니다.
- 🧩공통 헤더는 s.headers.update로 정의해 중복 코드를 제거합니다.
- 🧷반복되는 쿼리는 s.params에 기본값으로 등록해 누락을 방지합니다.
- 🛑세션 수명 종료 시 s.close()로 소켓을 해제해 리소스 누수를 예방합니다.
- 🔒민감한 값은 환경 변수나 시크릿 매니저로 주입하고 코드에 하드코딩하지 않습니다.
💬 세션은 “기본값은 세션, 특이값은 요청” 원칙으로 운용하면 가장 직관적입니다.
동일 키가 충돌하면 요청 인자가 세션 기본값보다 우선합니다.
🧩 s.headers.update로 공통 헤더 설정
HTTP 요청에는 서버가 요청을 구분하거나 인증하기 위한 헤더(Header)가 반드시 포함됩니다.
예를 들어 User-Agent, Authorization, Content-Type 같은 항목들이 대표적이죠.
하지만 모든 요청에 동일한 헤더를 반복 작성한다면 코드가 길어지고 유지보수가 어려워집니다.
이럴 때 s.headers.update()를 이용하면 세션 수준에서 한 번만 설정해도 모든 요청에 자동으로 반영됩니다.
예를 들어 API 호출 시 공통으로 필요한 인증 토큰이나 콘텐츠 타입을 세션 헤더에 등록해 두면, 별도의 인자 없이도 s.get()이나 s.post() 요청마다 자동으로 포함됩니다.
이 방식은 코드 가독성을 높이고, 실수로 누락되는 문제를 방지하는 가장 기본적인 패턴입니다.
추가로 update() 메서드를 통해 기존 헤더를 덮어쓰거나 병합할 수 있으며, 특정 요청에서만 다른 헤더를 지정할 경우 headers= 인자를 사용하면 됩니다.
import requests
s = requests.Session()
# 공통 헤더 설정
s.headers.update({
"User-Agent": "MyPythonApp/1.0",
"Authorization": "Bearer ACCESS_TOKEN",
"Content-Type": "application/json"
})
# 모든 요청에 자동 적용
res = s.get("https://api.example.com/profile")
print(res.status_code)
# 요청 단위에서 개별 헤더 덮어쓰기
res = s.post("https://api.example.com/items",
headers={"Content-Type": "application/xml"})
print(res.request.headers)
위 코드에서 보듯이, 세션에 등록된 공통 헤더는 기본값처럼 작동하며, 필요에 따라 개별 요청에서 자유롭게 수정할 수 있습니다.
이 접근법은 특히 여러 API를 연동하는 마이크로서비스나, 다수의 외부 서버에 인증 요청을 보내는 환경에서 매우 유용합니다.
헤더를 세션에서 통합 관리하면 코드 일관성을 유지하면서, 변경이 생길 때도 단 한 줄만 수정하면 전체 요청에 반영됩니다.
💡 TIP: s.headers.update()는 기존 키를 덮어쓰기 때문에, 잘못된 토큰이나 포맷을 추가할 경우 모든 요청이 영향을 받습니다.
민감한 헤더는 환경 변수에서 읽어오거나 dotenv 같은 라이브러리를 사용해 안전하게 관리하세요.
| 헤더 이름 | 용도 |
|---|---|
| User-Agent | 클라이언트 앱 식별 문자열 |
| Authorization | API 접근을 위한 인증 토큰 |
| Content-Type | 요청 본문의 데이터 형식 지정 |
💬 헤더를 전역에서 통합 관리하면 코드가 훨씬 깔끔해집니다.
하지만 요청 단위에서 반드시 예외 처리가 가능해야 하며, 잘못된 인증 정보가 전체 요청을 망치지 않도록 세심한 구조가 필요합니다.
🧷 s.params 기본값으로 쿼리 공통화
API 요청 시 URL 뒤에 붙는 쿼리 파라미터(query parameters)는 데이터를 필터링하거나 인증 정보를 전달할 때 자주 사용됩니다.
예를 들어 ?apikey=123&lang=ko와 같이 여러 요청에서 동일하게 사용하는 항목들이 있죠.
이럴 때 s.params 속성에 기본값을 설정해두면, 모든 요청에서 자동으로 병합되어 반복 작성할 필요가 없습니다.
이는 requests의 Session 객체만이 제공하는 매우 강력한 기능 중 하나입니다.
예를 들어 REST API를 다루는 서비스에서 지역(locale), API 키, 포맷(format) 등은 항상 동일하게 사용됩니다.
이럴 때 s.params = {...} 형태로 지정하면, 이후 모든 s.get()이나 s.post() 요청에 기본 쿼리가 자동으로 병합되어 URL이 완성됩니다.
만약 특정 요청에서 같은 키를 다시 전달하면, 세션 기본값보다 요청 단위의 값이 우선 적용됩니다.
import requests
s = requests.Session()
# 공통 쿼리 파라미터 기본값 지정
s.params = {
"apikey": "ABC123XYZ",
"lang": "ko",
"format": "json"
}
# 모든 요청에 자동 적용됨
res1 = s.get("https://api.example.com/data")
# URL → https://api.example.com/data?apikey=ABC123XYZ&lang=ko&format=json
# 요청 단위에서 다른 값 추가
res2 = s.get("https://api.example.com/data", params={"page": 2})
# URL → ...?apikey=ABC123XYZ&lang=ko&format=json&page=2
이렇게 설정해 두면, 중복된 파라미터 작성 없이 코드가 간결해지고 유지보수가 쉬워집니다.
또한 기본값이 누락되는 문제를 예방하고, API 요청의 일관성을 확보할 수 있습니다.
대형 프로젝트에서는 공통 파라미터를 세션 생성 함수나 클래스의 초기화 구문에서 정의해 관리하는 것이 좋습니다.
💎 핵심 포인트:
s.params는 모든 요청에 공통으로 포함될 쿼리 문자열을 관리하며, 요청마다 병합되어 최종 URL을 완성합니다.
중복 키가 있을 경우 요청 단위의 파라미터가 세션 기본값을 덮어씁니다.
- 🔑공통 API 키나 언어(locale) 같은 항목은 s.params에 등록합니다.
- 🧮특정 요청에서만 다른 값을 쓰고 싶다면
params={}인자로 덮어씁니다. - ⚙️공통 쿼리는 코드 초기에 정의해 일관성 있게 유지합니다.
- 📡반드시 요청 후 로그를 확인해 실제 전송된 URL을 검증하세요.
💬 세션의 params는 “반복되는 기본값을 한 번만 정의”하는 철학을 따릅니다.
즉, 코드보다 설정 중심으로 관리하는 것이 requests 세션의 장점입니다.
🛑 연결 재사용과 s.close로 소켓 해제
requests의 Session은 내부적으로 urllib3의 커넥션 풀(Connection Pool)을 사용하여 TCP 연결을 재사용합니다.
이 덕분에 같은 서버에 여러 번 요청을 보낼 때, 매번 새로 연결을 맺지 않고 기존 소켓을 재활용하여 속도와 효율을 높입니다.
하지만 세션을 무한히 유지하거나, 닫지 않은 상태에서 프로그램이 종료되면 소켓이 해제되지 않아 리소스 누수가 발생할 수 있습니다.
따라서 세션이 더 이상 필요하지 않을 때는 반드시 s.close()를 호출해야 합니다.
특히 서버와의 통신이 잦은 장기 실행 프로그램(예: 데이터 수집기, API 백엔드 서비스)에서는 연결이 계속 쌓이기 쉬워 시스템 자원을 고갈시킬 수 있습니다.
이 경우 close()를 명시적으로 호출하거나, with requests.Session() as s: 구문을 사용해 컨텍스트 매니저로 세션을 관리하는 것이 가장 안전합니다.
컨텍스트 블록을 벗어나면 s.close()가 자동으로 실행되어 소켓이 정리됩니다.
import requests
# 안전한 세션 관리 방식
with requests.Session() as s:
s.headers.update({"User-Agent": "SessionExample/1.0"})
s.params = {"lang": "ko"}
r = s.get("https://api.example.com/status")
print(r.status_code)
# 블록을 벗어나면 자동으로 s.close() 호출
만약 여러 세션을 병렬로 사용할 경우, 각 세션이 자신의 커넥션 풀을 별도로 유지하므로 close() 호출 시점이 특히 중요합니다.
닫히지 않은 소켓은 운영체제의 파일 디스크립터(fd)를 점유한 채 해제되지 않기 때문에, 결국 “Too many open files” 오류를 일으킬 수 있습니다.
실행 중 세션을 수동으로 닫아야 한다면 try-finally 구문을 이용하는 것이 권장됩니다.
⚠️ 주의: 세션을 닫지 않은 상태에서 프로그램이 장시간 동작하면 커넥션 풀의 소켓이 점차 쌓이며, 결국 메모리 누수나 포트 고갈 문제가 발생할 수 있습니다.
반드시 s.close()를 호출해 리소스를 반환하세요.
- 🧰세션은 커넥션 풀을 유지하므로 종료 시 반드시 s.close() 호출.
- 💡
with requests.Session()구문을 사용하면 자동으로 소켓이 정리됨. - 🚫세션 객체를 전역으로 방치하지 말고, 요청 목적별로 구분하여 사용.
- 🔎디버깅 시
netstat나lsof로 열린 포트를 확인해 누수 여부 점검.
💬 s.close()는 단순히 연결을 끊는 행위가 아니라, OS 자원을 반환하는 “정리 절차”입니다.
명시적으로 호출하는 습관이 장기적으로 안정적인 애플리케이션을 만듭니다.
🧪 실전 패턴과 예제 코드
지금까지 s.headers.update()로 공통 헤더를 정의하고, s.params로 기본 쿼리를 설정하며, s.close()로 소켓을 안전하게 해제하는 법을 살펴봤습니다.
이제 이 모든 요소를 종합한 실전 예제를 통해, 실무에서 세션을 어떻게 구성하면 좋은지 구체적으로 확인해 보겠습니다.
다음 예제는 외부 REST API를 호출하는 클래스 구조입니다.
초기화 시 세션을 만들고, 공통 헤더와 기본 파라미터를 설정한 후, 데이터를 가져오는 메서드를 제공합니다.
사용이 끝나면 close()로 세션을 정리합니다.
이 패턴은 데이터 크롤링, AI 모델 호출, 백엔드 통신 등 다양한 환경에서 재사용할 수 있습니다.
import requests
class ApiClient:
def __init__(self, api_key, base_url="https://api.example.com"):
self.s = requests.Session()
self.s.headers.update({
"User-Agent": "MyClient/1.2",
"Authorization": f"Bearer {api_key}",
"Accept": "application/json"
})
self.s.params = {"lang": "ko", "format": "json"}
self.base_url = base_url
def get_data(self, endpoint, **kwargs):
url = f"{self.base_url}/{endpoint}"
response = self.s.get(url, params=kwargs)
response.raise_for_status()
return response.json()
def close(self):
self.s.close()
# 사용 예시
client = ApiClient(api_key="ABC123XYZ")
data = client.get_data("items", page=1)
print(data)
client.close()
이 클래스는 세션의 장점을 모두 흡수한 구조로, 다음과 같은 이점이 있습니다.
- 🧩헤더와 쿼리 파라미터를 세션 단위로 통합 관리해 중복을 최소화합니다.
- ⚡커넥션 풀을 통해 요청 속도와 효율을 극대화합니다.
- 🔒API 키를 인스턴스 변수로 관리하여 외부 노출을 방지합니다.
- 🧹close() 메서드로 세션 리소스를 안전하게 정리합니다.
💡 TIP: 클래스나 모듈 단위로 세션을 구조화하면, 프로젝트 규모가 커져도 API 호출 로직이 안정적으로 유지됩니다.
테스트 시에는 requests_mock이나 responses 라이브러리를 사용하면 네트워크 없이도 세션 기반 코드를 검증할 수 있습니다.
💬 requests.Session은 단순한 편의 기능이 아니라, 효율적인 네트워크 자원 관리 도구입니다.
공통 설정·성능·안정성 세 가지를 동시에 충족시키는 필수 패턴으로 익혀두세요.
❓ 자주 묻는 질문 (FAQ)
Session을 사용하지 않고 매번 requests.get()만 써도 되나요?
s.headers.update와 요청의 headers 인자가 동시에 있으면 어떻게 되나요?
s.params와 params 인자는 병합되나요?
세션을 닫지 않아도 프로그램 종료 시 자동 해제되나요?
세션을 여러 개 만들어도 괜찮나요?
with 구문을 쓰면 s.close()를 안 써도 되나요?
with requests.Session() 구문을 사용하면 블록이 끝날 때 자동으로 세션이 닫힙니다.
세션에 쿠키도 저장되나요?
멀티스레드 환경에서 한 세션을 공유해도 되나요?
🧭 Session을 활용한 안정적 API 요청 관리 요약
파이썬 requests의 Session 객체는 단순한 요청 편의 기능을 넘어, 효율적인 네트워크 자원 관리와 코드 유지보수를 동시에 가능하게 합니다.
공통 헤더를 s.headers.update()로 지정하면 모든 요청에 자동 반영되고, s.params를 이용하면 기본 쿼리 파라미터를 일괄 관리할 수 있습니다.
또한, 사용이 끝난 후 반드시 s.close()로 소켓을 해제해야 리소스 누수를 방지할 수 있습니다.
이 세 가지는 requests를 안정적으로 운용하기 위한 필수 원칙입니다.
세션을 클래스나 컨텍스트 형태로 구조화하면 실무 코드가 훨씬 명료해지고, API 키나 인증 정보 관리도 체계화됩니다.
반복되는 설정을 한 번에 관리하고, 요청이 실패했을 때 재시도 로직을 추가하는 등 확장도 용이해집니다.
결국 Session은 “한 번 설정으로 여러 번 이득을 보는” requests의 핵심 기능이라 할 수 있습니다.
💎 핵심 요약:
① s.headers.update()로 공통 헤더 정의
② s.params로 기본 쿼리 등록
③ s.close()로 소켓 해제 및 리소스 반환
이 세 가지를 지키면 requests 기반의 모든 네트워크 코드가 더욱 안전하고 깔끔해집니다.
🏷️ 관련 태그 : requests, 파이썬, 세션관리, s.headers.update, s.params, s.close, HTTP요청, API통신, 파이썬프로그래밍, 네트워크관리