공식 API 없는 네이버 블로그에 자동으로 글 올리기 — 브라우저로 뚫은 기록

여러 곳에 글을 올리는 도구를 만들면서 제일 오래 붙잡은 게 네이버 블로그였다.
워드프레스는 REST API가 있다. 주소로 요청을 보내면 글이 올라가고, 실패하면 왜 실패했는지 코드로 알려준다. 그런데 네이버 블로그는 공식 API가 없다. 외부에서 글을 올릴 공식 통로가 없다는 뜻이다.
그래서 브라우저를 직접 띄우기로 했다. 사람이 하는 것과 똑같이 로그인하고, 글쓰기를 열고, 제목을 넣고, 본문을 붙여넣고, 발행 버튼을 누르는 방식이다. Playwright로 그 과정을 코드로 옮겼다.
지금 작업 폴더에 그때 만든 스크립트가 스물다섯 개쯤 남아 있다. 파일 이름에 test, test2, debug, probe, inspect가 반복되는 걸 보면 얼마나 헤맸는지 짐작이 간다.
매번 로그인할 수는 없다
처음 부딪힌 게 로그인이었다.
글을 올릴 때마다 아이디와 비밀번호를 넣어 로그인하면 될 것 같지만 실제로는 안 된다. 자동화된 로그인이 반복되면 캡차가 뜨고, 새 기기로 인식되면 추가 인증을 요구한다. 사람이 앉아 있지 않으면 거기서 멈춘다.
그래서 세션을 저장해 재사용하기로 했다. 브라우저에는 프로필이라는 개념이 있어서, 쿠키와 로컬 저장소를 특정 폴더에 남겨두면 다음에 그 폴더로 브라우저를 열었을 때 로그인 상태가 이어진다.
사이트마다 폴더를 따로 뒀다. 처음 한 번은 창을 띄워 사람이 직접 로그인하고, 그때 저장된 세션으로 이후에는 창 없이 돌아간다. 로그인 정보를 데이터베이스에 넣지 않아도 되니 이 편이 안전하기도 했다.
로그인했는지 어떻게 아나
여기서 진짜 문제가 시작됐다. 발행을 시도하기 전에 지금 로그인 상태인지 확인해야 하는데, 이걸 어떻게 아느냐다.
처음엔 단순하게 갔다. 네이버 로그인 세션 쿠키가 브라우저에 있으면 로그인된 것으로 봤다.
한동안 잘 되다가 어느 날부터 발행이 실패했다. 로그인 상태라고 판정하고 글쓰기 페이지로 갔는데 로그인 화면이 떴다.
원인은 쿠키였다. 세션 쿠키는 서버에서 세션이 끊겨도 브라우저에 그대로 남는다. 만료일이 한 달쯤 뒤로 잡혀 있으니, 실제로는 로그아웃된 지 오래인데 쿠키는 멀쩡히 자리를 지키고 있었다. 쿠키의 존재는 로그인의 증거가 아니었다.
그래서 판정 기준을 좁혔다. 인증 쿠키와 세션 쿠키가 둘 다 있어야 로그인으로 보게 했다. 하나만으로 판단하던 걸 쌍으로 바꾼 것이다.
그것으로도 부족했다
쌍을 확인해도 여전히 구멍이 있었다. 두 쿠키가 다 있는데 서버 쪽에서 세션을 무효화한 경우다. 브라우저는 그 사실을 모른다.
결국 쿠키만 보는 걸 포기하고 서버에 직접 물어보기로 했다. 로그인해야만 열리는 페이지를 브라우저에 저장된 쿠키로 요청해보고, 로그인 화면으로 튕기면 만료로 판정한다. 창을 띄우지 않고 요청만 보내는 방식이라 0.1초면 끝난다.
여기에 예외를 하나 뒀다. 이 확인 자체가 네트워크 오류로 실패하면 쿠키 판정을 따르게 했다. 인터넷이 잠깐 끊긴 것 때문에 멀쩡한 세션을 만료로 처리하면 안 되니까.
직관과 반대였던 것
이 확인 방법을 정하면서 한 번 크게 틀렸다.
처음 생각한 건 이랬다. 로그인 페이지에 접속해보고, 이미 로그인 상태라면 다른 데로 튕겨나갈 테니 그걸로 판단하자. 자연스러운 발상이었다.
그런데 안 됐다. 항상 만료라고 나왔다.
확인해보니 네이버는 로그인된 상태에서도 로그인 페이지를 그대로 보여준다. 튕겨내지 않는다. 그러니 이 방식은 언제나 “로그인 안 됨”이라는 답만 내놓는다.
방향을 뒤집었다. 로그인 페이지가 아니라 로그인해야만 열리는 페이지를 요청하고, 그게 로그인 화면으로 튕기는지를 본다. 있어야 할 곳에 갔는데 쫓겨나면 세션이 죽은 것이다. 이렇게 바꾸니 그제야 맞았다.
돌아보면 첫 번째 발상은 서비스가 이렇게 동작할 것이라는 내 가정에 기대고 있었다. 실제로 확인해보지 않은 가정이었다.
실패가 엉뚱한 얼굴로 나타난다
브라우저 자동화에서 제일 짜증나는 부분이 이거였다.
로그인 확인을 통과했는데도 글쓰기 페이지에 들어가는 순간 로그인 화면으로 튕기는 경우가 있었다. 확인하고 진입하는 사이에 세션이 끊기거나 캡차가 뜬 것이다.
문제는 그때 코드가 어떻게 실패하느냐다. 로그인 화면에는 에디터가 없으니 제목 입력란을 찾다가 시간 초과가 난다. 그러면 화면에는 요소를 못 찾았다는 오류가 뜬다.
진짜 원인은 로그인 만료인데 겉으로는 화면 구조 문제처럼 보인다. 이러면 엉뚱한 데를 파게 된다. 실제로 한동안 에디터 구조가 바뀐 줄 알고 그쪽만 들여다봤다.
그래서 글쓰기 페이지에 들어간 직후 주소를 확인해서, 로그인 쪽으로 넘어갔으면 즉시 로그인 필요 오류를 내도록 했다. 원인과 증상이 어긋나지 않게 만든 것이다.
창 없이 돌아갈까
또 하나 뒤집은 가정이 있다.
처음엔 창을 띄우지 않고는 안 될 거라고 봤다. 본문을 붙여넣을 때 클립보드를 쓰는데 그게 창 없는 환경에서 제대로 동작하지 않을 것 같았고, 이미지 업로드도 마찬가지라고 생각했다.
그런데 실제로 시험해보니 둘 다 됐다. 서식을 유지한 채 붙여넣는 것도, 이미지를 올리는 것도 창 없이 정상 동작했다.
그래서 기본을 창 없이 도는 쪽으로 바꿨다. 디버깅할 때만 환경 변수로 창을 띄운다. 이 덕분에 사람이 보고 있지 않아도 예약 발행이 돌아가게 됐다.
가정을 검증하지 않고 설계에 반영했다면 필요 없는 제약을 계속 안고 갔을 것이다.
무거운 건 자동 갱신에서 뺐다
마지막은 작은 얘기다.
사이트 상태를 보여주는 화면이 30초마다 자동으로 갱신되게 만들어뒀다. 워드프레스는 요청 한 번이면 되니 문제가 없었다.
그런데 네이버 상태 확인은 브라우저를 띄워야 한다. 30초마다 브라우저가 열렸다 닫히는 셈이라 감당이 안 됐다. 결국 자동 갱신 대상에서 빼고, 버튼을 눌렀을 때만 확인하도록 분리했다.
같은 “상태 확인”이라도 비용이 다르면 같은 주기로 묶으면 안 된다는 걸 그때 알았다.
정리하면
브라우저 자동화는 되게 만드는 것보다 됐는지 아는 게 어려웠다.
글을 올리는 절차 자체는 오래 걸리지 않았다. 시간을 잡아먹은 건 전부 상태 판정이었다. 지금 로그인돼 있나, 이 페이지가 내가 생각한 그 페이지가 맞나, 방금 실패한 게 진짜 그 이유가 맞나.
쿠키처럼 간접적인 신호로 상태를 판단하면 언젠가 배신당한다. 신호가 남아 있다고 상태가 유효한 건 아니다. 확실히 알아야 하는 것은 결국 직접 물어봐야 했다.
그리고 실패는 원인과 다른 얼굴로 나타난다. 로그인이 끊겼는데 화면 요소를 못 찾았다고 나오는 식이다. 오류 메시지를 그대로 믿고 파다가는 엉뚱한 곳에서 시간을 버린다. 실패 지점마다 진짜 원인을 드러내는 검사를 하나씩 심어두는 게, 결국 디버깅 시간을 제일 많이 아껴줬다.



답글 남기기