본문 바로가기

일상

웹 자동화(Playwright) 헤드리스가 클라우드플레어(Cloudflare)에 막힐 때 (화면 밖 헤드풀 + 크롬 프로필 재사용)

반응형

잘 되던 자동 조회 스크립트가 헤드리스로만 돌리면 "Just a moment..." 봇 차단 페이지에 막힐 때 해결하는 방법입니다.


1. 문제: 브라우저로는 되는데 헤드리스만 막힌다
로그인해야 보이는 사용량 페이지를 주기적으로 자동 조회하는 스크립트를 만들었습니다. 창을 띄워서(헤드풀) 돌리면 잘 되는데, 백그라운드로 돌리려고 headless=True로 바꾸는 순간 클라우드플레어(Cloudflare)의 "Just a moment..." 페이지에 막혔습니다. JSON을 기대한 API 호출에 HTML이 돌아옵니다.


- 같은 코드가 헤드풀에서는 통과, 헤드리스에서는 차단
- JSON 자리에 차단 페이지 HTML이 옴
- 몇 분마다 도는 모니터링이라 매번 창을 띄울 수도 없음


2. 차단인지부터 코드로 판별한다
먼저 "차단당했다"를 코드가 스스로 알게 만듭니다. JSON API 응답이 200이 아니거나, 본문이 HTML로 시작하거나, "just a moment" 문구가 보이면 차단입니다. 이 판별이 있어야 JSON 파싱 에러로 뻗는 대신 폴백 전략으로 넘어갈 수 있습니다.



- 상태코드 + 본문 앞부분만 보면 판별 충분
- 파싱 에러로 죽지 않고 "차단" 신호로 다음 단계 진행


3. 준비: persistent 프로필로 로그인과 쿠키를 유지한다
매번 새 브라우저를 띄우면 로그인부터 다시 해야 해서 차단 확률도 올라갑니다. launch_persistent_context로 크롬 프로필 폴더를 지정해 두면 로그인 세션과 쿠키가 폴더에 남습니다. 처음 한 번만 사람이 직접 로그인해 주면, 이후엔 통과 이력 쿠키(cf_clearance)까지 프로필에 쌓여서 헤드리스로도 통과되는 경우가 많습니다.


- 프로필 폴더 = 로그인 세션 + 통과 쿠키 저장소
- 최초 1회만 수동 로그인, 이후 재사용
- 주의: 같은 프로필은 한 프로세스만 열 수 있음(락) - 주기 조회 프로세스는 하나만 두고, 결과는 파일로 공유


4. 그래도 막히면: 헤드풀 창을 화면 밖으로 보낸다
쿠키가 만료되면 헤드리스는 다시 막힙니다. 차단 로직이 주로 헤드리스 신호를 보기 때문에 헤드풀로 띄우면 통과되는데, 몇 분마다 창이 번쩍이면 일하는 데 방해가 됩니다. 절충안이 "화면 밖 헤드풀"입니다. 창 위치를 모니터 밖 좌표로 밀어 버리면, 브라우저는 헤드풀로 동작하는데 눈에는 아무것도 안 보입니다.



- 1차는 헤드리스로 짧게, 차단 감지되면 2차로 화면 밖 헤드풀 재시도
- --window-position=-32000,-32000 으로 창을 화면 밖에 배치
- 헤드풀이라 차단은 통과, 화면은 조용함


5. 요청은 같은 origin 안에서 fetch로 보낸다
차단을 통과했어도 API를 스크립트 밖에서 따로 호출하면(requests 등) 쿠키와 요청 모양이 달라 다시 막히기 쉽습니다. 사이트를 먼저 열어 같은 origin을 확보한 뒤, 페이지 안에서 fetch를 실행하면 실제 웹앱이 보내는 요청과 똑같아집니다. 챌린지가 풀리는 데 몇 초 걸릴 수 있으니 짧게 기다리며 재시도합니다.



- 페이지 안 fetch = 쿠키·헤더·지문이 실제 사용과 동일
- 챌린지 풀릴 시간을 주며 몇 차례 재시도
- 성공 판정도 앞서 만든 차단 감지 함수를 재사용


6. 정리
헤드리스 차단은 "봇처럼 보이는 신호"의 문제라서, 사람처럼 보이는 조건을 하나씩 되찾아 주면 풀립니다. 로그인·쿠키는 persistent 프로필로 유지하고, 요청은 같은 origin의 fetch로 보내고, 그래도 막히면 헤드풀을 화면 밖에 띄우는 것까지 가면 백그라운드 자동 조회가 안정적으로 돕니다.


- JSON 자리에 HTML -> 차단 감지 함수로 판별
- 로그인·쿠키 유지 -> launch_persistent_context
- 헤드리스 차단 -> 화면 밖 헤드풀(--window-position) 폴백
- API 호출 -> 페이지 안 same-origin fetch


함께 보면 좋은 글:
- 플레이라이트(Playwright)로 매번 새 브라우저 띄우지 말고, 디버그 Chrome 세션 재사용하기 (CDP attach) - 세션 재사용 편
- 웹 자동화(Playwright)에서 클릭·입력이 안 먹을 때 (React/Vue input 이벤트 + dispatchEvent 클릭) - 클릭·입력 편
- 웹 자동화(Playwright) 중간중간 화면 캡처가 느리거나 멈출 때 - CDP Page.captureScreenshot로 즉시 찍기 - CDP 캡처 편
- 밤새 돌리는 클로드(Claude) 자동화, 사용량 한도에 걸려 죽지 않게 (외부 모니터 + 게이트 파일 설계) - 사용량 게이트 설계 편
- 웹 자동화(Playwright) 스크립트가 끝나도 브라우저 살려두기 (크롬 독립 실행 + CDP 재사용) - 크롬 독립 실행 편


여기까지 헤드리스가 봇 차단에 막힐 때 화면 밖 헤드풀과 프로필 재사용으로 통과하는 방법에 대해서 작성해봤습니다. 여기까지 읽어주셔서 감사합니다!

반응형