로그인 세션 및 쿠키 영구화
업데이트: 2026-10-02
회원 전용 도매몰 가격, 사내 인트라넷 게시판, 또는 SMS OTP 등 2단계 인증이 걸려 있는 웹사이트의 데이터를 수집할 때 매번 스크립트에서 아이디와 비밀번호를 입력하고 로그인하는 것은 매우 비효율적이며 보안상으로도 위험합니다.
Playwright의 storage_state 세션 상태 보존 기능을 활용하면, 1회 인증으로 획득한 세션 쿠키와 localStorage 토큰 토큰을 DashCloud의 영구 디스크에 저장해 두고, 서버가 재시작되어도 로그인 상태를 유지하며 즉각 수집을 재개할 수 있습니다.
세션 영구화의 핵심 동작 메커니즘
[ 1회성 초기 인증 (내 로컬 PC) ]
개발자가 브라우저를 열고 로그인 (SMS/OTP 직접 입력)
│
▼
context.storage_state(path="session.json") 호출
│ (쿠키 + localStorage 토큰이 JSON 파일로 추출됨)
▼
대시보드 또는 CLI로 DashCloud 영구 볼륨(/app/data/session.json)에 업로드
─────────────────────────────────────────────────────────────
[ 24/7 무중단 수집 (DashCloud 런타임) ]
browser.new_context(storage_state="/app/data/session.json")
│ (로그인 페이지를 거치지 않고 인증 완료 상태로 즉시 브라우저 로드)
▼
회원 전용 마이페이지 또는 특가 페이지로 다이렉트 이동1단계: 로컬에서 1회성 세션 파일 생성하기
내 로컬 컴퓨터에서 브라우저 창(headless=False)을 띄우고 사람이 직접 로그인을 완료한 뒤 세션 파일을 추출하는 1회용 파이썬 스크립트입니다.
from pathlib import Path
from playwright.sync_api import sync_playwright
SESSION_FILE = Path("session.json")
def create_initial_session():
with sync_playwright() as p:
# 사람이 직접 로그인할 수 있도록 화면에 브라우저 표시
browser = p.chromium.launch(headless=False)
context = browser.new_context()
page = context.new_page()
print("로그인 페이지로 이동합니다. 브라우저에서 직접 로그인을 완료하세요...")
page.goto("https://target-service.com/login")
# 로그인 완료 후 이동하는 메인 페이지 URL 또는 특정 요소가 뜰 때까지 대기
# 예: 마이페이지 링크나 로그아웃 버튼이 보일 때까지 대기 (최대 120초)
page.wait_for_selector("a[href='/logout']", timeout=120000)
print("로그인이 감지되었습니다! 세션 상태를 저장합니다.")
# [핵심] 쿠키와 로컬스토리지 전체를 session.json으로 덤프
context.storage_state(path=str(SESSION_FILE))
print(f"세션 파일 저장 완료: {SESSION_FILE.resolve()}")
context.close()
browser.close()
if __name__ == "__main__":
create_initial_session()생성된 session.json 파일을 DashCloud 프로젝트의 /app/data/session.json 위치에 업로드합니다 (웹 대시보드의 파일 메뉴에서 드래그앤드롭 가능).
2단계: DashCloud에서 세션 주입하여 24시간 수집하기
저장된 session.json 파일이 존재할 경우 자동으로 브라우저 컨텍스트에 주입하여 로그인 과정을 건너뛰고 바로 타깃 페이지를 수집하는 프로덕션 코드입니다.
import os
import logging
from pathlib import Path
from playwright.sync_api import sync_playwright
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("AuthCrawler")
SESSION_PATH = Path("/app/data/session.json")
def run_authenticated_crawler():
if not SESSION_PATH.exists():
logger.error(f"세션 파일({SESSION_PATH})이 존재하지 않습니다! 먼저 세션을 업로드하세요.")
return
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
# [핵심] 저장된 세션 상태를 주입하여 컨텍스트 생성
context = browser.new_context(
storage_state=str(SESSION_PATH),
viewport={"width": 1920, "height": 1080}
)
page = context.new_page()
try:
logger.info("회원 전용 페이지로 직접 이동합니다...")
page.goto("https://target-service.com/wholesale/products", timeout=30000)
# 1. 세션 만료 여부 검증 (로그아웃 버튼 존재 확인)
if not page.is_visible("a[href='/logout']"):
logger.warning("⚠️ 세션이 만료되어 비로그인 상태로 리다이렉트되었습니다!")
handle_session_expired()
return
# 2. 회원 전용 데이터 수집 수행
items = page.query_selector_all(".wholesale-item")
logger.info(f"성공: {len(items)}개 도매 상품 정보를 수집했습니다.")
except Exception as e:
logger.error(f"크롤링 도중 예외 발생: {e}")
finally:
context.close()
browser.close()
def handle_session_expired():
# 텔레그램이나 디스코드로 관리자에게 세션 만료 알림 전송
logger.critical("관리자 텔레그램으로 재로그인 요청 알림을 발송합니다.")
if __name__ == "__main__":
run_authenticated_crawler()3단계: 세션 자동 갱신 파이프라인
일반적인 웹사이트는 마지막 접속 후 7일~30일이 경과하면 보안 정책상 세션을 강제 만료시킵니다.
세션 만료를 방지하고 최신 쿠키로 유지하려면, 주기적으로 메인 페이지를 방문하고 갱신된 쿠키를 다시 storage_state로 덮어쓰는 Keep-Alive 루프를 구성해야 합니다.
def refresh_and_save_session(page, context, session_path: Path):
"""주기적으로 페이지를 방문하여 갱신된 세션 토큰을 영구 디스크에 저장"""
try:
page.goto("https://target-service.com/my-account", timeout=20000)
# 최신 세션 상태를 다시 디스크에 덮어쓰기
context.storage_state(path=str(session_path))
logger.info("세션 상태가 성공적으로 갱신되었습니다.")
except Exception as e:
logger.warning(f"세션 갱신 실패: {e}")보안 주의사항
session.json파일에는 내 계정의 실제 로그인 쿠키가 포함되어 있으므로 절대 깃허브 공개 저장소에 커밋하지 마세요.- 반드시 프로젝트의
.gitignore파일에data/및*.json을 추가하세요. - DashCloud는
/app/data디렉터리를 외부와 격리된 전용 물리 볼륨에 안전하게 저장하므로 안전성이 보장됩니다.