브라우저로 로그인하고 requests로 긁기: 쿠키·토큰 전달법과 한계

로그인이 필요한 사이트를 requests로 긁어오려다가 로그인 폼부터 막혀서 검색하셨다면, 답은 이렇습니다. 브라우저에서 수동으로 로그인한 다음 그 세션의 쿠키나 토큰을 꺼내 requests.Session()에 그대로 넘겨주면 로그인 페이지를 자동화할 필요 없이 로그인된 상태로 요청을 보낼 수 있습니다. 다만 httpOnly 쿠키, TLS 핑거프린팅, 자동 갱신되는 토큰 때문에 이 방법이 안 통하는 사이트도 적지 않아서, 어디까지 되고 어디서부터 막히는지를 같이 … Read more

로컬에선 되는데 서버에선 안 되는 헤드리스 크롤러, 원인 좁히기

결론부터 말씀드리면, 로컬에선 되는데 서버에선 안 되는 크롤러 문제는 거의 항상 “코드가 틀렸다”가 아니라 “환경이 다르다”에서 생깁니다. 브라우저 바이너리에 필요한 리눅스 라이브러리가 없거나, 서버의 데이터센터 IP가 차단당하거나, 화면이 없는 환경에서 폰트·언어 설정이 달라서 셀렉터가 어긋나는 세 가지 경우가 대부분을 차지합니다. 이 글에서는 Playwright와 Puppeteer 기준으로, 로컬과 서버의 차이를 하나씩 좁혀가는 순서를 정리합니다. 로컬 환경과 서버 … Read more

networkidle 대기가 타임아웃으로 끝날 때, 진짜 봐야 할 지점

로그인 여부를 가리려고 page.wait_for_load_state(“networkidle”, timeout=30000)을 걸어 뒀는데, 로그를 열어 보면 거의 매번 30000ms를 꽉 채우고 타임아웃이 떨어졌습니다. 네트워크 탭을 같이 열어 보니 요청이 멈추지 않아서가 아니라, 광고 스크립트 하나가 몇 초 간격으로 계속 비콘을 쏘고 있어서 “500ms 동안 조용한 순간”이 끝까지 오지 않는 상태였습니다. networkidle 대기가 타임아웃으로 끝날 때 정말 기다려야 하는 건 네트워크가 아니라, … Read more

무한 스크롤 페이지를 끝까지 긁기, 스크롤 반복이 항목을 빠뜨리는 이유

무한 스크롤 페이지를 끝까지 긁기 위해 스크롤 반복문을 돌렸는데 전체 항목 수보다 적게 나온다면, 범인은 대부분 document.body.scrollHeight 비교 방식입니다. 서버 응답이 스크립트의 대기 시간보다 늦게 끝나면 스크롤 루프는 “더 이상 늘어날 콘텐츠가 없다”고 착각하고 일찍 종료해 버립니다. 예를 들어 항목이 1,200개인 목록 페이지에서 이 방식을 쓰면 700~800개 선에서 멈추는 현상이 흔하게 나타나는데, 원인은 네트워크가 아니라 … Read more

긁을 때 브라우저를 띄워야 할까? 숨은 JSON API 찾는 순서

“크롤러로 사이트를 긁을 때 브라우저를 띄워야 할까요?” 답은 대부분 아니오입니다. 개발자 도구의 네트워크 탭을 먼저 열어서 페이지가 실제로 호출하는 JSON API를 찾아내면, 셀레니움이나 플레이라이트 같은 브라우저 자동화 없이도 데이터를 훨씬 빠르고 가볍게 가져올 수 있습니다. 다만 모든 사이트에 이 방법이 통하지는 않아서, 확인 순서와 브라우저가 꼭 필요한 예외 상황까지 함께 정리했습니다. 브라우저 렌더링과 API 호출, … Read more

API 키를 깃허브에 올렸을 때, 순서는 삭제가 아니라 무효화입니다

커밋 메시지를 쓰고 푸시 버튼을 누른 다음에야, 방금 올린 코드 안에 .env 파일이나 설정 파일 안에 적어둔 값이 API 키였다는 걸 알아차리신 적 있으신가요. API 키를 깃허브에 올렸을 때 가장 먼저 떠오르는 대응은 보통 “커밋을 지우고 히스토리를 깨끗하게 되돌리자”이지만, 그 순서부터 잘못됐습니다. 키가 한 번이라도 올라갔다면 히스토리를 아무리 정리해도 이미 노출된 값 자체는 사라지지 않기 … Read more

LLM 스트리밍이 60초에 끊기는 이유와 nginx·ALB·gunicorn 타임아웃 잡는 법

이 글을 읽으시면 LLM 스트리밍이 60초에 끊기는 원인이 nginx·ALB·gunicorn 세 군데에 동시에 걸려 있다는 것과, 각 지점을 어떻게 고쳐야 하는지 바로 적용할 수 있는 설정값까지 확인하실 수 있어요. 결론을 먼저 말씀드리면, 토큰이 느리게 나오는 LLM 응답은 중간에 “데이터가 안 들어온다”고 판단되는 순간 끊기는데, 공교롭게도 nginx의 proxy_read_timeout과 ALB의 Idle timeout 기본값이 똑같이 60초라서 거의 동시에 끊기는 … Read more

Prometheus 카디널리티가 터질 때, 레이블은 이렇게 골라야 합니다

레이블 하나를 잘못 넣으면 시계열 개수가 어떻게 늘어나는지 계산부터 해보겠습니다. job 레이블 값이 5개, method 레이블 값이 20개, 여기에 user_id 레이블(값 5만 개)을 하나 추가하면 이론상 조합 가능한 시계열은 5 × 20 × 50,000 = 500만 개까지 늘어납니다. Prometheus 카디널리티가 터질 때 실무에서 가장 흔한 원인이 바로 이렇게 고유값이 많은 필드를 레이블로 넣는 습관입니다. 이 … Read more

GitHub Actions가 매번 5분씩 걸릴 때 점검할 캐시 키

이 글에서는 GitHub Actions가 매번 5분 가까이 걸릴 때 캐시 키 설계와 적중률을 어떤 순서로 점검하면 되는지 확인하실 수 있습니다. 미리 답을 드리면, 원인은 대부분 세 가지 중 하나입니다. key에 매번 달라지는 값(커밋 SHA, 타임스탬프)을 넣어서 캐시가 매번 새로 생성되는 경우, 브랜치 범위 때문에 캐시에 접근이 안 되는 경우, 그리고 restore-keys를 안 써서 부분 일치조차 … Read more

CI에서만 테스트가 깨질 때, 로컬과 다른 네 가지를 좁히는 순서

CI에서만 테스트가 깨질 때는 거의 항상 환경 변수, OS·런타임·타임존, 병렬 실행과 격리, 네트워크 접근성 이 네 가지 중 하나에서 원인을 찾을 수 있습니다. 로컬에서는 멀쩡히 통과하던 테스트가 GitHub Actions나 GitLab CI 같은 파이프라인에서만 빨갛게 실패한다면, 코드 로직을 의심하기 전에 이 네 가지를 순서대로 좁혀 나가는 쪽이 디버깅 시간을 훨씬 줄여줍니다. 이 글에서는 각 원인을 어떤 … Read more