들어가는 글
공모주 청약 투자를 하는 사람이라면 알 것이다. 청약일, 상장일, 환불일 등 챙겨야 할 일정이 많다. 처음엔 구글 캘린더에 하나하나 직접 입력했는데 귀찮아서 그만뒀다. 그 이후로는 38커뮤니케이션 사이트를 수시로 확인하는 식으로 버텼다. 그러다 최근에는 OpenClaw 에이전트가 38.co.kr을 크롤링한 일정을 텔레그램 알림으로 받으면서 사이트를 직접 방문하는 수고는 덜고 있다. 여기에 구글 캘린더 자동 등록까지 붙이면 더 편하지 않을까 생각이 들었다. 수작업이 귀찮아서 그만뒀던 일이 에이전트에 의해 다시 자동으로 돌아가게 되는 것이다.

https://www.38.co.kr/html/ipo/
38커뮤니케이션 - 비상장주식,장외주식시장 NO.1
비상장주식,장외주식시장 NO.1 38커뮤니케이션.비상장거래/매매,시세정보,IPO기업분석,공모주,상장폐지주식,퇴출종목,K-OTC,코넥스 정보 제공
www.38.co.kr
작업 결과물의 동작 흐름
38.co.kr (공모주 일정)
→ Python 크롤링 스크립트
→ Google Calendar API
→ 구글 캘린더 (공청약/공상장)
매주 일요일 아침에 OpenClaw 에이전트의 크론이 자동 실행되어 다음 주 공모주 일정을 구글 캘린더에 자동으로 등록한다. 이 결과물을 만들기까지의 작업 과정을 5단계로 나눠서 설명한다.
1단계: Google Calendar API 활성화
이미 Gmail API용으로 Google Cloud 프로젝트가 있었다. 같은 프로젝트에 Calendar API만 추가하면 된다.
https://developers.google.com/workspace/calendar/api/guides/overview
Google Calendar API 개요 | Google for Developers
의견 보내기 Google Calendar API 개요 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Google Calendar API는 명시적 HTTP 호출을 통해 액세스하거나 Google 클라이언트 라
developers.google.com
Google Cloud Console → API 및 서비스 → 라이브러리 → "Google Calendar API" 검색 → 사용


이게 사람이 해야 하는 첫 번째 작업이다. API 활성화는 Google Cloud Console에서만 할 수 있다.
💡 이미 Gmail API 같은 Google API를 쓰고 있다면, 같은 프로젝트에서 Calendar API를 추가로 활성화하면 된다. credentials.json을 새로 만들 필요 없이 OAuth 토큰만 재발급받으면 된다.
2단계: OAuth 토큰 재발급 (스코프 추가)
기존 토큰은 gmail.readonly 스코프만 갖고 있었다. 캘린더 접근을 위해 calendar.events 스코프를 추가해야 한다.
SCOPES = [
'https://www.googleapis.com/auth/gmail.readonly',
'https://www.googleapis.com/auth/calendar.events',
]
에이전트가 인증 스크립트를 만들어 Mac mini에서 실행하고, OAuth 인증 URL을 채팅으로 보내줬다. 나는 맥북 브라우저에서 그 URL을 열고 '계속' 버튼을 연속해서 클릭했다.


승인 후 나온 인증 코드를 다시 채팅으로 보내주면, 에이전트가 토큰을 발급받아 저장한다.
사람이 하는 일: 브라우저에서 승인 버튼 클릭 + 인증 코드 복사
에이전트가 하는 일: 인증 URL 생성, 토큰 발급, 저장
이게 사람과 AI 에이전트의 역할 분담이다. 보안상 OAuth 승인은 사람만 할 수 있고, 그래야 한다.
3단계: 캘린더 ID 확인 및 공유
기본 캘린더 외에 공모주 청약 일정만 관리할 캘린더를 하나 만들고, 캘린더 ID를 에이전트에게 전달한다. 설정으로 들어가서 해당 캘린더를 선택한 뒤 스크롤을 좀 내리면 '캘린더 통합' 섹션이 보인다. 여기서 캘린더 ID 값을 복사해서 에이전트에게 전달하면서 앞으로 공모주 일정은 이 캘린더에 추가해 달라고 말하면 된다.


삽질: calendar.events vs calendar.readonly
calendar.events 스코프로 캘린더 목록(calendarList)을 조회하려고 했더니 403 에러가 났다.
HttpError 403: "Request had insufficient authentication scopes."
캘린더 목록 조회에는 calendar.readonly 이상의 스코프가 필요하다. 하지만 우리에겐 캘린더 목록이 필요 없다. 특정 캘린더 ID만 알면 되니까.
💡 최소 권한 원칙: calendar (전체 읽기/쓰기) 대신 calendar.events (이벤트만)를 쓰면, 캘린더 생성/삭제 같은 위험한 작업은 아예 불가능하다. 에이전트에게 필요한 최소 권한만 주는 게 보안의 기본이다.
4단계: 크롤링 + 캘린더 등록 스크립트
에이전트가 sync_ipo_calendar.py를 작성했다. 동작 흐름은 아래와 같다.
- 38.co.kr 크롤링: 청약일정 페이지 + 신규상장 페이지
- 데이터 파싱: 종목명, 청약일, 공모가, 경쟁률, 주간사
- 캘린더 등록/업데이트:
- 이미 있는 이벤트 → 설명만 업데이트 (삭제 안 함)
- 새 이벤트 → 생성
- 중복 체크: seen 파일 + 캘린더 검색
이벤트 포맷
기존에 수동으로 등록하던 포맷을 에이전트에게 전달했다.


청약 이벤트 (공모주 청약 캘린더)
- 제목: [청약] 종목명
- 날짜: 청약 마감일 (나는 둘째 날에 청약하므로)
- 시간: 10:00~10:30
- 장소: 주간사 증권사명
- 설명: 공모가 + 청약일 + 경쟁률
- 알림: 1일 전
상장 이벤트 (공모주 상장 캘린더)
- 제목: [상장] 종목명
- 날짜: 상장일
- 시간: 9:50~10:50
- 장소: 주간사
- 설명: 공모가
- 알림: 1시간 전
설계 포인트: 삭제 없이 업데이트
처음에는 이미 등록된 이벤트를 스킵하도록 만들었다. 그런데 공모가 확정, 경쟁률 업데이트 같은 정보 변경이 생기면? 에이전트에게 삭제 대신 업데이트하도록 수정을 요청했다. 아래 코드는 에이전트 작성한 python 코드다.
existing = find_existing_event(service, calendar_id, title, date_dt)
if existing:
if existing.get('description', '') != desc:
existing['description'] = desc
service.events().update(
calendarId=calendar_id,
eventId=existing['id'],
body=existing,
).execute()
Calendar API의 events().update()를 사용하면 기존 이벤트를 삭제하지 않고 설명, 장소 등을 수정할 수 있다. 직접 수기 입력한 메모(배분 내역, 손익 등)도 보존된다.
5단계: 크론 등록
매주 일요일 아침 8시에 자동 실행되도록 OpenClaw 크론을 걸었다. 결과는 Discord 전용 채널에 보고된다.
매주 일요일 08:00 KST → sync_ipo_calendar.py 실행
→ 새 일정 등록 / 기존 일정 업데이트
→ Discord #공모주-투자 채널에 결과 보고
첫 실행 결과
✅ 새로 등록 (17):
[청약] 인벤테라, 교보스팩20호, 리센스메디컬, ...
[상장] 케이뱅크, 에스팀, 액스비스, 카나프테라퓨틱스
🔄 업데이트 (13): ← 설명 포맷 변경 후 재실행
기존 이벤트에 청약일/경쟁률 정보 추가

비어 있던 캘린더가 다시 채워졌다.
전체 작업 시간
Discord 채팅으로 에이전트와 대화하면서 진행했다. 시작부터 크론 등록까지 약 1시간. 내가 직접 한 건:
- Google Cloud Console에서 Calendar API "사용" 버튼 클릭
- OAuth 승인 화면에서 "계속" 버튼 클릭
- 인증 코드 복사해서 채팅에 붙여넣기
- 캘린더 ID 복사해서 채팅에 붙여넣기
나머지(스크립트 작성, 크롤링, API 연동, 크론 설정)는 전부 에이전트가 했다.
마치는 글
수동으로 하던 걸 자동화하는 건 항상 뿌듯하다. 특히 "몇 달 전에 귀찮아서 그만둔 일"이 에이전트 덕분에 다시 돌아간다는 게. 앞으로 일요일마다 다음 주 공모주 일정이 알아서 캘린더에 들어가 있을 거다. 공모가 확정이나 경쟁률 같은 정보가 업데이트되면 기존 이벤트도 자동으로 갱신된다. 청약 후 배분 결과나 상장 후 손익은 여전히 수동으로 적어야 하지만, 그건 투자 기록이니까 직접 쓰는 게 맞다.
사용한 것들
- OpenClaw: AI 에이전트 프레임워크
- Google Calendar API:
calendar.events스코프 - 38.co.kr: 공모주 일정 데이터 소스
- Python: requests, beautifulsoup4, google-api-python-client