OpenClaw로 서평 자동화 만들기 1부: YES24 조회와 신청 자동화

OpenClaw로 서평 자동화 만들기 1부: YES24 조회와 신청 자동화

들어가기 앞서

나는 원래 책 읽는 걸 좋아한다. 그러다 보니 자연스럽게 서평 활동에도 관심이 갔고, 올해부터는 책을 읽고 기록하는 흐름을 조금 더 꾸준히 가져가고 싶어졌다. 그렇게 시작한 것 중 하나가 책 관련 모집글을 찾아 신청하고, 선정되면 정해진 채널에 리뷰를 남기는 활동이었다.

문제는 책을 읽고 서평을 쓰는 일 자체가 아니었다. 오히려 그 앞뒤에 붙는 반복 작업이 점점 더 불편하게 느껴졌다. 비정기적으로 업데이트 되는 서평단 모집글이 올라왔는지 계속 확인해야했고, 신청하고 싶은 책인지 판단해야 했으며, 신청 시 내가 기존에 서평 후기를 작성했던 포스트들을 신청 댓글에 붙여야해서 예전 리뷰 링크를 다시 찾는 과정들은 그야말로 오버헤드였다.

이 작업들은 하나씩 떼어놓고 보면 사소하다. 하지만 이런 사소한 작업이 계속 쌓이면 결국 피곤해진다. 시간을 많이 잡아먹는다는 느낌보다, 집중력을 자꾸 끊어놓는다는 쪽에 더 가깝다. 정작 중요한 건 책을 읽고 서평을 쓰는 일인데, 그 전에 해야 하는 확인과 복붙과 정리가 점점 더 번거롭게 느껴지기 시작했다.

그래서 나는 이 과정을 자동화하여 완전히 줄여보기로 했다.

다만 내가 줄이고 싶었던 것은 단순히 손 몇 번 덜 움직이는 수준의 불편이 아니었다. 실제로는 책 관련 모집글을 발견하고, 신청하고, 리뷰를 남기고, 그 기록을 다시 다음 활동에 활용하는 서평 활동 전반의 흐름을 더 매끄럽게 만들고 싶었다. 즉, 이 글에서 말하는 자동화는 특정 신청 절차 하나를 빠르게 처리하는 이야기가 아니라, 반복되는 서평 워크플로우 전체를 다시 설계하는 과정에 가깝다.

이번에는 바로 그 과정을 OpenClaw로 자동화했다. 목표는 “AI로 자동 신청했다”가 아니라, 운영 가능한 서평 자동화 흐름을 만드는 것이었다. 며칠 뒤에도 같은 기준으로 굴러가고, 위험한 조건에서는 멈추고, 중복과 오탐을 줄일 수 있는 구조 말이다.

이 글에서는 그중에서도 1부에 해당하는 조회와 신청 자동화를 정리한다. 서평 활동의 앞단에서 무엇이 반복 비용이었는지, 왜 OpenClaw를 중심 런타임으로 택했는지, 어떤 기준으로 자동화 범위를 제한했는지, 그리고 운영 중 어떤 버그를 만나고 어떻게 검증 방식을 바꿨는지를 중심으로 다룬다.

문제 정의: 귀찮음보다 더 큰 것은 맥락 전환 비용

서평 활동의 불편은 단순한 귀찮음으로 축약하기 어렵다. 실제로 더 큰 비용은 맥락 전환이다.

무언가에 집중하고 있다가도 “모집글 올라왔나?”를 확인하려고 여러 페이지를 오가게 되고, 발견한 뒤에는 신청 가능한 상태인지 다시 확인해야 한다. 나는 인스타그램과 Yes24 두개의 채널을 서평단 활동 채널로 사용중이었는데, 인스타그램은 출판사별로 모집글과 일반 홍보글, 후기 리그램, 단순 공지가 뒤섞여 있고, YES24는 모집글이 모여 있지만 여전히 사람이 직접 훑어야 한다. 결국 읽고 쓰는 일과 직접적으로 상관없는 작업에 계속 주의가 분산된다.

이런 류의 반복 작업을 보면 늘 같은 질문을 하게 된다.

이건 사람이 계속 수동으로 해야 하는 일인가, 아니면 사람이 마지막 판단만 하도록 바꿀 수 있는 일인가.

이번 자동화는 바로 이 질문에서 출발했다.

왜 굳이 OpenClaw였는가

이 정도 자동화는 이론상 cron + node script + telegram bot + playwright 조합으로도 만들 수 있다. 실제로 많은 개인 자동화가 그렇게 시작한다. 나도 처음에는 그렇게 생각했다.

그런데 이 경우 금방 시스템이 조각난다.

  • 수집 스크립트는 따로 돌고
  • 상태 파일은 여기저기 흩어지고
  • 알림은 별도 봇 로직으로 빠지고
  • 사용자의 실행 명령은 또 다른 인터페이스를 가져야 하고
  • 브라우저 자동화는 실패했을 때 어느 층에서 재시도하거나 중단할지 경계가 흐려진다

이번에는 이 흐름을 하나의 런타임 안에서 묶고 싶었다. OpenClaw를 중심에 두면 적어도 다음 흐름은 한 덩어리로 유지할 수 있다.

  1. 정해진 시간에 수집한다.
  2. 상태를 비교해 신규만 뽑는다.
  3. 결과를 메시지로 전달한다.
  4. 사용자가 번호로 선택한다.
  5. Playwright로 신청을 실행한다.
  6. 성공 여부를 검증하고 상태를 갱신한다.

즉, OpenClaw는 여기서 단순히 “대화형 AI”라기보다 크론, 메시지 인터페이스, 상태 파일, 브라우저 자동화를 엮는 운영 런타임에 가깝게 썼다. 도구를 화려하게 쓰는 것보다, 흩어지기 쉬운 자동화 단계를 한 흐름으로 관리할 수 있다는 점이 더 컸다.

이번 자동화에서 세운 설계 원칙

처음부터 “완전 자동 신청”을 목표로 잡지는 않았다. 오히려 그런 접근이 더 위험하다고 봤다. 특히 인스타그램처럼 봇의 지속적인 Request로 인한 차단 가능성이 있는 플랫폼은 조금 편해지는 대신 계정을 잃을 수 있다.

그래서 이번 자동화는 아래 원칙을 먼저 세워두고 시작했다.

  • 사람이 판단할 구간은 남긴다.
  • 상태는 파일로 외부화한다.
  • 외부 플랫폼에는 보수적으로 접근한다.
  • 수집과 실행을 분리한다.
  • 성공 판정은 UI 문구가 아니라 도메인 기준으로 한다.

이 원칙을 기능으로 옮기면 아래와 같다.

  • 모집글 조회/감시는 자동화
  • 신청은 사용자 명령 기반으로 실행
  • 위험 신호(429, challenge, 로그인 요구, blocked)는 즉시 중단
  • 인스타 신규 계정은 한 번에 과도하게 훑지 않도록 초기 스캔 상한 적용
  • 댓글 등록 성공 여부는 문자열이 아니라 내 계정 작성자 기준으로 검증

화려한 구조는 아니다. 하지만 실제로 오래 굴러가는 자동화는 대체로 이런 제약 위에 세워진다.

수집 설계: YES24와 인스타그램을 같은 문제로 보지 않기

처음부터 YES24와 인스타그램을 동일한 방식으로 접근하지는 않았다. 두 채널은 성격이 다르기 때문이다.

YES24 리뷰어클럽은 모집글이 모이는 비교적 정돈된 소스다. 반면 인스타그램은 공식 모집글, 일반 홍보글, 후기 게시물, 출판사 태그가 섞인 리그램이 뒤엉켜 있다. 같은 “모집글 탐색”이라고 해도, 한쪽은 비교적 구조화된 목록 문제이고 다른 한쪽은 휴리스틱 필터링 문제에 가깝다.

이 차이를 인정하고 설계를 나누는 것이 첫 번째 의사결정이었다. 목록 수집을 모두 브라우저 자동화로 통일할 수도 있었지만 그렇게 하지 않았다. 단순 목록 수집은 HTTP/API 기반이 더 싸고 안정적이고, 상호작용이 필요한 신청 단계만 브라우저 자동화로 밀어 넣는 편이 훨씬 유지보수하기 좋았기 때문이다.

YES24 수집: Ajax 엔드포인트와 상태 파일 중심의 구조

YES24 리뷰어클럽은 웹 페이지 전체를 긁기보다, 내부적으로 호출되는 Ajax 엔드포인트를 이용하는 쪽이 안정적이었다. 브라우저를 띄워 DOM을 긁는 방식도 가능하지만, 그건 렌더링 타이밍이나 마크업 변경에 더 쉽게 흔들린다. 여기서는 단순히 “새 모집글이 있느냐”만 알면 되기 때문에, 브라우저는 과한 선택이었다.

핵심은 신규 판별이다.

  • 모집글 고유 번호(SEQ_NO)를 기준으로 상태를 저장한다.
  • 한 번 본 글은 state 파일에 기록하고, 이후에는 신규로 간주하지 않는다.
  • 상태는 memory/yes24-reviewerclub-state.json 같은 파일로 관리한다.

이 방식의 장점은 명확하다.

첫째, 날짜가 아니라 ID 기반으로 신규를 판별하므로 정렬이 달라져도 안정적이다.(YES24 측이 대규모로 DB를 갈아엎지만 않는다면 말이다.) 둘째, 특정 시점에 스캔이 한 번 누락되어도 다음 실행에서 다시 비교가 가능하다. 셋째, 이 정도 규모에서는 DB를 붙이는 것보다 JSON 상태 파일이 더 단순하고 복구하기 쉽다. 파일을 열어보면 현재 상태가 바로 보이기 때문에, 개인 자동화에서는 오히려 디버깅 비용이 낮다.

개인 자동화에서 상태 파일은 생각보다 중요하다. 한 번 작동하는 스크립트와 계속 굴러가는 자동화의 차이는 대체로 이런 작은 상태 관리에서 벌어진다.

인스타그램 수집: watchlist 기반의 보수적 접근

인스타그램 쪽은 접근을 훨씬 보수적으로 잡았다.

알고리즘 피드나 검색 결과를 과도하게 탐색하는 방식은 재현성이 낮고 차단 리스크도 크다. 그래서 “관심 있는 출판사 계정만 직접 watchlist에 등록하고, 그 계정의 최근 게시물 일부만 확인한다”는 구조로 설계했다.

운영 전략은 대략 아래와 같았다.

  • 감시 대상은 memory/instagram-watchlist.json 에 관리
  • 주기적 실행은 주 3회 수준으로 제한
  • 계정당 최근 게시물 일부만 확인
  • 계정/게시물 단위로 랜덤 지연을 넣어 과도한 패턴을 피함
  • 신규 계정은 첫 실행에서 최근 3개만 확인하도록 상한 적용

즉, 최대한 많이 긁는 것이 목표가 아니라 놓치지 않으면서도 과하지 않게 보는 것이 목표였다. 여기서는 recall보다 precision이 중요했다. 더 많이 잡는 것보다, 계정이 멀쩡하게 오래 살아 있는 것이 우선이기 때문이다.

이 과정에서 가장 중요하게 둔 원칙은 하나였다.

밴 방지가 정확도보다 우선한다.

그래서 로그인 요구, challenge, 429, blocked 같은 힌트가 보이면 재시도하지 않고 바로 중단하도록 했다. 실패했을 때 억지로 한 번 더 밀어붙이는 자동화는 대개 오래 못 간다.

그렇게 해서 완성된 수집 cron jobs는 아래와 같다.

대시보드에 수집설정된 cron jobs

이제 YES 24의 경우 매일 정해진 시간에, 인스타그램의 경우 주 3회 정해진 시간에 자동으로 모집글을 수집한다.

오탐 줄이기: 키워드만으로는 모집글을 판별할 수 없음

실제로 운영하며 제일 먼저 드러난 문제는 오탐이었다.

처음에는 서평, 리뷰어, 서포터즈, 베타 리더 같은 키워드 중심으로 후보를 잡았다. 하지만 실제 인스타그램에서는 이 기준이 느슨했다. 예를 들어, 내가 watchlist에 넣은 출판사를 누군가가 하단에 태그만 한 서평 후기 게시물도 후보처럼 보일 수 있었다.

이 문제는 “정규식 하나 더 추가하면 해결된다” 수준이 아니었다. 모집글은 결국 텍스트의 존재 여부보다 모집 의도를 판별해야 했기 때문이다.

그래서 필터를 2단계로 바꿨다.

  • 1차: 서평/리뷰어/서포터즈 같은 키워드 탐지
  • 2차: 모집/신청/마감/발표/선정/이벤트 같은 모집 의도 cue 탐지

여기서도 끝나지 않았다. 운영해보니 여전히 “도서 제공받아 작성”, “협찬”, “서평 후기” 같은 문구가 들어간 후기성 게시물이 섞였다. 그래서 이런 문구는 별도의 가드로 제외했다.

이런 식의 보정은 정답이 있는 작업이라기보다, 실제 로그를 보며 룰을 다듬는 과정에 가깝다. 오탐을 줄이기 위한 기준은 결국 코드보다 운영 데이터가 더 많이 가르쳐준다.

신청 자동화: 완전 자동보다 명령 기반 반자동

조회 자동화가 충분히 안정화된 뒤에는 신청 동작도 붙였다. 하지만 이 역시 무조건 자동으로 돌리지는 않았다. 내가 원하는 도서를 직접 선정해서 신청을 해야 했기 때문이다.

YES24의 신청은 해당 도서 서평모집 페이지에 신청댓글을 남기는 방식인데, 기존에 사락 리뷰를 남긴 적이 있다면 해당 리뷰 링크를 같이 첨부하면 당첨확률이 올가나는 구조였다.

신청은 텔레그램을 통해 OpenClaw가 수집해 준 신규 리스트들을 확인한 후, -서평 신청: 1,5 같은 명령을 보내면, OpenClaw가 해당 번호를 YES24 페이지에 매핑해 Playwright로 댓글을 달아주는 반자동 구조로 만들었다.

텔레그램으로 신청 명령 보내는 모습

이렇게 한 이유는 단순하다.

  • 어떤 책에 신청할지는 사람이 결정하는 편이 낫다.
  • 자동화는 클릭과 입력, 중복 확인 같은 반복 작업만 대신하면 충분하다.
  • 특히 신청은 한 번 올라간 댓글이 외부에 남기 때문에, 조회보다 더 보수적으로 다루는 게 맞다.

즉, 이 단계에서 자동화의 역할은 선택을 대신하는 것이 아니라 선택 이후의 실행 비용을 줄이는 것이었다.

여기서도 OpenClaw를 쓴 이유가 드러난다. 사용자는 별도 스크립트 인자를 기억할 필요 없이 메시지로 번호만 전달하면 되고, 시스템은 그 번호를 방금 전달한 모집글 목록과 연결해 실행하면 된다. 개인 자동화에서 “명령어를 잘 외워야 쓸 수 있는 시스템”은 생각보다 빨리 버려진다.

신청 댓글 구성: 내부 선별 기준과 외부 노출 텍스트 분리

신청 댓글에는 기존 사락 리뷰 링크를 같이 넣도록 만들었다. 이때도 단순히 모든 링크를 다 넣는 방식은 피했다.

리뷰 링크는 시간이 갈수록 계속 늘어난다. 그렇다고 전부 넣으면 댓글이 지저분해지고, 너무 적으면 활동 이력이 약해 보인다. 그래서 내부적으로는 사락 리뷰 목록을 주기적으로 수집해 평점과 최신성 기준으로 최대 10개를 선별하고, 신청 댓글은 그 저장된 목록을 불러오게 했다.

중요한 점은, 이 정책 설명을 그대로 댓글에 노출하지 않는 것이다. 시스템 내부는 똑똑하게 굴러가더라도 사용자에게 보이는 텍스트는 단순해야 한다.

그래서 실제 댓글은 아래처럼 최대한 간결한 형식으로 고정했다.

서평 신청합니다! 좋은 도서를 읽고 후기 남기고 싶습니다.

[사락 서평 링크]
...저장된 링크들

이런 식으로 내부 선별 로직외부 노출 형식을 분리해두는 것이 이후 유지보수에도 유리했다. 내부 정책은 얼마든지 바꿀 수 있지만, 외부에 노출되는 텍스트는 최대한 안정적으로 유지하는 편이 낫다.

신청 결과

운영 중 만난 문제: 댓글 등록은 됐는데 timeout이 나는 현상

이번 자동화에서 가장 인상적이었던 버그는, 댓글 등록은 실제로 됐는데 스크립트는 실패했다고 판단하는 문제였다.

처음에는 YES24 쪽 UI나 로딩 타이밍이 달라진 것으로 의심했다. 그런데 실제 페이지를 확인해보니 댓글은 이미 등록돼 있었다. 원인은 의외로 단순한 내부 버그였다.

신청 댓글 포맷을 [사락 서평 링크]로 바꿔놓고, 성공 판정 로직은 예전 문자열인 [기존 서평 링크]를 계속 기다리고 있었던 것이다. 즉 등록 자체는 성공했는데, 성공 여부를 판정하는 마지막 단계가 옛날 값에 묶여 timeout이 나고 있었다.

이 문제를 겪고 나서 다시 확인한 것은, 브라우저 자동화에서는 “클릭이 됐는가”보다 성공을 어떻게 판정할 것인가가 더 어렵다는 점이다. 실제로 깨지는 지점도 대개 동작 그 자체보다 검증 단계다.

그래서 이 문제는 단순 문자열 수정으로 끝내고 싶지 않았다. 애초에 문자열 존재 여부로 성공을 확인하는 방식 자체가 허술했기 때문이다. 누군가 비슷한 태그를 쓰거나, 페이지 본문에 같은 문자열이 들어가도 오판정할 여지가 있었다.

결국 성공 판정 기준을 아예 바꿨다.

  • 페이지 전체 텍스트에서 문자열을 찾는 대신
  • 댓글 목록에서 /blog/jake220 작성자 링크를 찾고
  • 그 작성자 블록 안에
    • [사락 서평 링크]
    • 또는 내가 방금 넣은 리뷰 URL 이 실제로 존재하는지를 확인할 때만 성공으로 처리하게 만들었다.

이제 기준은 “문자열이 보이는가”가 아니라, 내 계정이 작성한 댓글 안에 내가 보낸 내용이 있는가다. 이 차이는 꽤 크다. 자동화의 신뢰도는 결국 이런 검증 기준의 정확도에서 결정된다.

운영 관점에서 중요했던 것: 사람이 개입해야 할 지점을 남기는 설계

이번 작업을 하며 다시 확인한 것은, 좋은 자동화는 사람을 완전히 제거하는 데서 나오지 않는다는 점이다. 오히려 사람이 개입해야 할 지점을 더 선명하게 남기는 쪽이 현실적이다.

  • 무엇을 신청할지는 사람이 고른다.
  • 위험 신호가 보이면 자동화는 멈춘다.
  • 성공 여부는 사람도 검증할 수 있는 기준으로 남긴다.
  • 내부 상태는 파일로 기록해 다음 실행의 기준이 되게 한다.
  • 수집과 실행을 분리해 장애 지점을 좁힌다.

이런 식으로 구조를 잡으면 자동화가 블랙박스가 아니라, 점진적으로 고칠 수 있는 작은 운영 시스템이 된다.

이번 자동화에서 OpenClaw는 단순히 명령을 대신 실행하는 도구가 아니라, 크론·상태 파일·메시지 인터페이스·브라우저 자동화를 묶어주는 런타임처럼 작동했다. 개인 프로젝트인데도 운영 관점의 고민을 얹을 수 있었던 이유다.

마무리: 조회와 신청을 분리해두는 것이 오히려 오래 간다

이번 1부에서 만들고 싶었던 것은 “서평 신청 봇”이 아니라, 반복적인 개인 업무를 조회 → 판단 → 신청 흐름으로 재구성한 운영 가능한 자동화였다.

그리고 해보면서 더 확실해진 건, 자동화는 모든 것을 대신하는 방향보다 사람이 정말 시간을 써야 할 지점만 남기는 방향이 더 오래 간다는 점이다.

조회는 자동으로, 판단은 더 정확하게, 신청은 더 짧게.

이 세 가지가 맞물리면 비로소 자동화가 시간을 아끼는 수준을 넘어 작업 방식을 바꾼다.

이번 작업에서 특히 남은 교훈은 네 가지였다.

  • 생활 자동화는 완전 자동보다 반자동 + 검증 가능성이 오래 간다.
  • 브라우저 자동화는 실행보다 성공 판정이 더 중요하다.
  • 개인 자동화에서도 상태 파일은 사실상 작은 데이터 모델 역할을 한다.
  • 플랫폼 리스크가 있는 곳에서는 커버리지보다 계정 안전성이 우선이다.

2부에서는 여기서 한 걸음 더 나아가, 서평을 실제로 작성한 뒤 사락 리뷰 링크를 관리하고 그 결과를 다시 신청과 블로그 포스팅 흐름으로 연결하는 방법을 정리해본다.