Python Selenium으로 네이버 로그인 후 쿠키 추출하여 requests에서 재사용하기 (2026년 3월 업데이트)

목차
네이버 관련 크롤링이나 API 호출을 하려면 로그인된 세션이 필요합니다. 하지만 네이버는 봇 감지가 강력하여 단순 자동 로그인이 어렵고, CAPTCHA가 수시로 나타납니다. 이 글에서는 Selenium으로 네이버에 로그인하고, CAPTCHA가 나오면 자동 감지 후 사용자가 해결할 때까지 대기하고, 로그인 성공 후 쿠키를 추출하여 일반 requests 라이브러리에서 재사용하는 전체 흐름을 실제 코드와 함께 설명합니다.
requests로 수행합니다. Chrome 프로필 저장으로 2회차부터는 CAPTCHA 없이 자동 로그인됩니다.전체 흐름 요약
| 단계 | 도구 | 설명 |
|---|---|---|
| 1 | Selenium | Chrome 프로필 로드 → 네이버 로그인 페이지 접속 |
| 2 | Selenium | CAPTCHA 감지 시 사용자 수동 해결 대기 (3초 간격 폴링) |
| 3 | Selenium | 로그인 완료 확인 → 쿠키/세션 Chrome 프로필에 자동 저장 |
| 4 | Selenium | driver.get_cookies()로 쿠키 추출 |
| 5 | requests | 추출한 쿠키를 requests.Session에 주입하여 API 호출 |
NaverLogin 클래스 - 전체 코드
아래 클래스는 네이버 로그인 → CAPTCHA 처리 → 쿠키 추출 → requests 세션 생성까지 모든 과정을 담고 있습니다.
"""
네이버 로그인 및 쿠키 관리 클래스
Selenium으로 로그인 → 쿠키 추출 → requests에서 재사용
"""
import os
import json
import time
from datetime import datetime
from typing import Optional, Dict, Tuple
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from selenium.common.exceptions import NoSuchElementException
import requests
class NaverLogin:
"""
네이버 로그인 후 쿠키를 추출하여 requests에서 재사용하는 클래스
사용 예시:
with NaverLogin() as naver:
# 로그인 (CAPTCHA 나오면 자동 대기)
if naver.login():
# 방법 1: 쿠키 딕셔너리 직접 사용
cookies = naver.get_cookies()
resp = requests.get('https://naver.com', cookies=cookies)
# 방법 2: requests.Session 사용 (권장)
session = naver.get_requests_session()
resp = session.get('https://naver.com')
"""
NAVER_LOGIN_URL = 'https://nid.naver.com/nidlogin.login'
NAVER_MY_URL = 'https://nid.naver.com/user2/help/myInfo'
def __init__(self, profile_dir='chrome_profile', headless=False):
self.profile_dir = os.path.join(os.getcwd(), profile_dir)
self.headless = headless
self.driver = None
self._cookies = None
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.close()
# ── Chrome 드라이버 설정 ──────────────────────────────
def _setup_driver(self):
"""봇 감지 우회 설정이 적용된 Chrome 드라이버 생성"""
opts = Options()
# Chrome 프로필 저장 (쿠키/세션 유지)
if not os.path.exists(self.profile_dir):
os.makedirs(self.profile_dir)
opts.add_argument(f'--user-data-dir={self.profile_dir}')
opts.add_argument('--profile-directory=Default')
if self.headless:
opts.add_argument('--headless')
# 봇 감지 우회 옵션
opts.add_argument('--disable-blink-features=AutomationControlled')
opts.add_argument('--no-sandbox')
opts.add_argument('--disable-dev-shm-usage')
opts.add_argument('--disable-gpu')
opts.add_argument('--window-size=1920,1080')
opts.add_argument(
'user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
'AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/131.0.0.0 Safari/537.36'
)
opts.add_experimental_option('excludeSwitches', ['enable-automation'])
opts.add_experimental_option('useAutomationExtension', False)
driver = webdriver.Chrome(options=opts)
# navigator.webdriver 속성 제거
driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {
'source': '''
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
});
window.chrome = { runtime: {} };
Object.defineProperty(navigator, 'plugins', {
get: () => [1, 2, 3, 4, 5]
});
Object.defineProperty(navigator, 'languages', {
get: () => ['ko-KR', 'ko', 'en-US', 'en']
});
'''
})
self.driver = driver
return driver
# ── CAPTCHA 감지 ──────────────────────────────────────
def _check_captcha(self) -> Tuple[bool, Optional[str]]:
"""페이지에서 CAPTCHA/보안 확인 여부를 감지"""
if not self.driver:
return False, None
try:
page_source = self.driver.page_source.lower()
# 키워드 기반 감지
keywords = [
'보안 확인', '보안확인', 'security check',
'자동입력 방지', 'captcha', 'recaptcha',
'로봇이 아닙니다', '실제 사용자임을 확인'
]
for kw in keywords:
if kw in page_source:
return True, kw
# 페이지 제목 확인
title = self.driver.title.lower()
if any(k in title for k in ['보안', 'security', 'captcha']):
return True, f'title: {title}'
# DOM 요소 확인
xpaths = [
"//iframe[contains(@src, 'recaptcha')]",
"//*[contains(@class, 'captcha')]",
"//*[contains(@id, 'captcha')]",
]
for xp in xpaths:
try:
self.driver.find_element(By.XPATH, xp)
return True, f'element: {xp}'
except NoSuchElementException:
continue
return False, None
except Exception as e:
print(f' CAPTCHA 감지 오류: {e}')
return False, None
# ── CAPTCHA 대기 ──────────────────────────────────────
def _wait_for_captcha(self, keyword: str, timeout: int = 300):
"""CAPTCHA 해결을 3초 간격으로 폴링하며 대기"""
print(f'\n{"="*60}')
print(f'🚨 보안 확인 감지: {keyword}')
print(f'{"="*60}')
print('브라우저에서 CAPTCHA를 해결하면 자동으로 진행됩니다.')
print(f'최대 {timeout}초 대기...\n')
elapsed = 0
while elapsed < timeout:
time.sleep(3)
elapsed += 3
is_blocked, _ = self._check_captcha()
if not is_blocked:
print(f'✅ 보안 확인 해제! ({elapsed}초 소요)')
return True
if elapsed % 30 == 0:
print(f' ⏳ 대기 중... ({elapsed}/{timeout}초)')
print(f'⚠️ 시간 초과 ({timeout}초)')
return False
# ── 로그인 확인 ───────────────────────────────────────
def _is_logged_in(self) -> bool:
"""현재 네이버에 로그인되어 있는지 확인"""
try:
self.driver.get(self.NAVER_MY_URL)
time.sleep(2)
# 로그인 페이지로 리다이렉트되면 미로그인
current = self.driver.current_url
if 'nidlogin' in current or 'login' in current.split('?')[0]:
return False
return True
except:
return False
# ── 로그인 실행 ───────────────────────────────────────
def login(self) -> bool:
"""
네이버 로그인 수행
1. Chrome 프로필에서 기존 세션 확인
2. 미로그인 시 로그인 페이지로 이동 → 사용자 수동 로그인
3. CAPTCHA 감지 시 자동 대기
4. 로그인 성공 시 쿠키 저장
Returns:
bool: 로그인 성공 여부
"""
if not self.driver:
self._setup_driver()
# 1. 기존 세션 확인
print('🔍 기존 로그인 세션 확인 중...')
if self._is_logged_in():
print('✅ 이미 로그인되어 있습니다! (Chrome 프로필에서 복원)')
self._extract_cookies()
return True
# 2. 로그인 페이지 이동
print('🔐 네이버 로그인이 필요합니다.')
print(' 브라우저에서 로그인해주세요...\n')
self.driver.get(self.NAVER_LOGIN_URL)
time.sleep(2)
# 3. 로그인 완료 대기 (폴링)
max_wait = 300
elapsed = 0
while elapsed < max_wait:
time.sleep(3)
elapsed += 3
# CAPTCHA 체크
is_captcha, kw = self._check_captcha()
if is_captcha:
self._wait_for_captcha(kw)
# 로그인 완료 확인
current = self.driver.current_url
if 'nidlogin' not in current and 'login' not in current.split('?')[0]:
# 로그인 페이지를 벗어남 → 로그인 성공
print('✅ 로그인 성공!')
print('💾 Chrome 프로필에 세션이 저장되었습니다.')
self._extract_cookies()
return True
if elapsed % 30 == 0:
print(f' ⏳ 로그인 대기 중... ({elapsed}/{max_wait}초)')
print('⚠️ 로그인 시간 초과')
return False
# ── 쿠키 추출 ─────────────────────────────────────────
def _extract_cookies(self):
"""Selenium 드라이버에서 쿠키를 추출하여 저장"""
if not self.driver:
return
selenium_cookies = self.driver.get_cookies()
self._cookies = {}
for c in selenium_cookies:
self._cookies[c['name']] = c['value']
print(f'🍪 쿠키 {len(self._cookies)}개 추출 완료')
def get_cookies(self) -> Dict[str, str]:
"""
추출한 쿠키를 딕셔너리로 반환
Returns:
Dict[str, str]: {쿠키이름: 쿠키값} 형태
"""
if not self._cookies:
self._extract_cookies()
return self._cookies or {}
def get_requests_session(self) -> requests.Session:
"""
추출한 쿠키가 주입된 requests.Session 반환
User-Agent도 동일하게 설정되어 바로 사용 가능
Returns:
requests.Session: 네이버 로그인 세션
"""
session = requests.Session()
# 쿠키 주입
cookies = self.get_cookies()
for name, value in cookies.items():
session.cookies.set(name, value)
# 동일한 User-Agent 설정
session.headers.update({
'User-Agent': (
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
'AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/131.0.0.0 Safari/537.36'
),
'Referer': 'https://www.naver.com/',
})
return session
def save_cookies(self, filepath: str = 'naver_cookies.json'):
"""쿠키를 JSON 파일로 저장"""
cookies = self.get_cookies()
with open(filepath, 'w', encoding='utf-8') as f:
json.dump(cookies, f, ensure_ascii=False, indent=2)
print(f'💾 쿠키 저장: {filepath}')
@staticmethod
def load_cookies(filepath: str = 'naver_cookies.json') -> Dict[str, str]:
"""JSON 파일에서 쿠키 로드"""
with open(filepath, 'r', encoding='utf-8') as f:
return json.load(f)
def close(self):
"""브라우저 종료"""
if self.driver:
self.driver.quit()
self.driver = None
코드 핵심 설명
1. Chrome 프로필로 쿠키 자동 유지
네이버에 직접 ID/PW를 입력하는 코드를 작성하면 봇으로 탐지됩니다. 대신 Chrome 프로필 디렉토리(chrome_profile/)를 지정하면, Chrome이 쿠키, 세션, 로컬 스토리지를 해당 폴더에 자동 저장합니다.
opts.add_argument(f'--user-data-dir={self.profile_dir}')
opts.add_argument('--profile-directory=Default')
처음 한 번 수동 로그인하면, 이후 실행 시 저장된 세션이 자동으로 복원되어 CAPTCHA 없이 바로 쿠키를 받아올 수 있습니다.
2. 봇 감지 우회
Selenium이 실행한 Chrome에는 navigator.webdriver = true라는 속성이 설정됩니다. 네이버는 이 속성을 확인하여 봇을 탐지합니다. CDP 명령으로 이 속성을 제거합니다:
driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {
'source': '''
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
});
'''
})
3. CAPTCHA 감지 및 폴링 대기
CAPTCHA 감지는 3가지 방법을 조합합니다:
- 키워드 검색: 페이지 소스에서 '보안 확인', 'captcha' 등 탐색
- 페이지 제목: 제목에 '보안', 'security' 포함 여부
- DOM 요소: reCAPTCHA iframe, captcha 관련 클래스/ID 존재 여부
CAPTCHA가 감지되면 input() 대신 3초 간격 자동 폴링으로 해결을 대기합니다. 사용자가 브라우저에서 CAPTCHA를 풀면 자동으로 감지하여 다음 단계로 진행합니다. 이 방식은 GUI 환경(PyQt5 등)에서도 호환됩니다.
4. 쿠키 추출 - Selenium에서 requests로
로그인 성공 후 driver.get_cookies()가 반환하는 쿠키 리스트를 딕셔너리로 변환합니다:
def _extract_cookies(self):
selenium_cookies = self.driver.get_cookies()
# [{'name': 'NID_AUT', 'value': 'xxx', 'domain': '.naver.com', ...}, ...]
self._cookies = {}
for c in selenium_cookies:
self._cookies[c['name']] = c['value']
# {'NID_AUT': 'xxx', 'NID_SES': 'yyy', ...}
이 딕셔너리를 requests.Session에 주입하면 Selenium 없이도 로그인 상태로 HTTP 요청을 보낼 수 있습니다:
def get_requests_session(self):
session = requests.Session()
for name, value in self.get_cookies().items():
session.cookies.set(name, value)
session.headers.update({
'User-Agent': 'Mozilla/5.0 ...', # Selenium과 동일한 UA
'Referer': 'https://www.naver.com/',
})
return session
사용 예시
기본 사용법
with NaverLogin() as naver:
if naver.login():
# requests.Session으로 네이버 API 호출
session = naver.get_requests_session()
# 예: 네이버 카페 API 호출
resp = session.get('https://cafe.naver.com/ArticleList.nhn', params={
'search.clubid': '12345678',
'search.page': 1
})
print(resp.status_code) # 200
print(resp.text[:500])
쿠키 저장 후 나중에 재사용
# 1. 로그인 후 쿠키를 파일로 저장
with NaverLogin() as naver:
if naver.login():
naver.save_cookies('naver_cookies.json')
# 2. 나중에 Selenium 없이 쿠키만 로드하여 사용
cookies = NaverLogin.load_cookies('naver_cookies.json')
session = requests.Session()
for name, value in cookies.items():
session.cookies.set(name, value)
session.headers['User-Agent'] = 'Mozilla/5.0 ...'
resp = session.get('https://naver.com')
print('로그인 상태:', 'MY' in resp.text) # True면 로그인됨
쿠키 딕셔너리 직접 사용
with NaverLogin() as naver:
if naver.login():
cookies = naver.get_cookies()
# {'NID_AUT': '...', 'NID_SES': '...', 'NID_JKL': '...', ...}
# requests.get에 cookies 파라미터로 직접 전달
resp = requests.get(
'https://mail.naver.com/json/list/',
cookies=cookies,
headers={'User-Agent': 'Mozilla/5.0 ...'}
)
실행 흐름 정리
- 프로그램 실행 → Chrome 브라우저 열림
- 기존 로그인 세션 확인 → 없음
- 네이버 로그인 페이지로 이동
- 사용자가 브라우저에서 수동 로그인 (ID/PW 입력)
- CAPTCHA 나오면 → 자동 감지 → 사용자 해결 대기 (3초 폴링)
- 로그인 성공 → Chrome 프로필에 쿠키 자동 저장
get_cookies()로 쿠키 추출 →requests에서 사용
- 프로그램 실행 → Chrome 프로필 자동 로드
- 기존 로그인 세션 확인 → 이미 로그인됨!
- CAPTCHA 없이 즉시 쿠키 추출
requests에서 바로 사용 가능
자주 묻는 질문
| 질문 | 답변 |
|---|---|
| 쿠키 유효기간은? | 네이버 세션 쿠키(NID_SES)는 보통 수 시간~수일 유효합니다. 만료되면 다시 login()을 호출하면 Chrome 프로필 덕분에 자동 복원됩니다. |
| Chrome 프로필을 삭제하면? | 저장된 세션이 모두 초기화됩니다. 다음 실행 시 수동 로그인이 필요합니다. |
| headless 모드에서 가능한가요? | 최초 로그인은 headless=False로 해야 합니다 (CAPTCHA 수동 해결 필요). 2회차부터는 세션이 유지되므로 headless=True도 가능합니다. |
| 여러 네이버 계정을 사용하려면? | profile_dir를 계정별로 다르게 지정하면 됩니다. 예: NaverLogin(profile_dir='profile_account1') |
| requests 세션이 차단되면? | User-Agent가 Selenium과 다르면 차단될 수 있습니다. get_requests_session()은 동일한 UA를 자동 설정하므로 이 메서드를 사용하세요. |
마치며
이 방식의 핵심은 Selenium은 로그인 전용, 실제 작업은 requests로 분리하는 것입니다. Selenium은 무겁고 느리지만 CAPTCHA 처리가 가능하고, requests는 가볍고 빠르지만 CAPTCHA 처리가 불가능합니다. 두 도구의 장점을 조합하고, Chrome 프로필 저장으로 재로그인 횟수를 최소화하면 안정적이고 효율적인 네이버 크롤링 환경을 구축할 수 있습니다.
pip install selenium requests — ChromeDriver는 Selenium 4.6+에서 자동 관리됩니다.
댓글 0개
등록된 댓글이 없습니다.