API가 없는 사이트를 자동화하는 법 — Playwright 입문
안녕하세요, 천상나타입니다.
최근 몇 달간 "API가 없는 웹사이트를 어떻게 자동화할까"를 계속 고민하면서 브라우저 자동화 도구인 Playwright를 많이 써봤습니다. 네이버 서치어드바이저 색인 검사 자동화, 티스토리 글 발행 자동화 같은 게 전부 이걸로 만들었는데요, 처음 쓰시는 분들이 알면 좋을 핵심 개념들을 정리해봅니다.
Playwright가 뭔데요?
Microsoft가 만든 브라우저 자동화 라이브러리예요. 코드로 크롬을 띄워서 사람이 하는 것처럼 클릭하고, 입력하고, 화면을 읽는 도구입니다. 예전엔 Selenium이 표준이었는데, 요즘은 Playwright가 더 많이 쓰여요. 이유는 간단합니다.
- 최신 브라우저 이벤트(파일 선택창, 다운로드 등)를 공식적으로 지원
- "요소가 나타날 때까지 기다리기"가 기본 내장이라 sleep 지옥이 덜함
- TypeScript 지원이 좋고, 실제 크롬(channel: 'chrome')을 그대로 쓸 수 있음
이런 걸 자동화할 수 있습니다
제가 실제로 만든 것 중 하나 — 네이버 서치어드바이저는 공식 API가 없어서, 콘솔에서 사람이 하는 흐름을 그대로 자동화했어요.

사이트를 고르고,

URL을 넣고 결과를 읽고, 미색인이면 수집 요청까지 보냅니다. 이게 전부 코드로 돌아가요.

자동화를 돌리는 핵심 기술 5가지

1. 로그인 세션 재사용 — persistent context
로그인이 필요한 사이트는 매번 로그인할 수 없으니, 프로필 폴더를 통째로 저장하는 방식을 씁니다.
const ctx = await chromium.launchPersistentContext('profiles/mysite', {
channel: 'chrome', // 진짜 크롬 사용
headless: true,
});
최초 1회는 headless를 끄고 수동 로그인(캡챠·2단계 인증 포함)을 해주면, 그 뒤론 쿠키가 프로필 폴더에 남아서 로그인 상태로 바로 시작됩니다. 이거 하나가 자동화 절반의 공이라고 봐도 돼요.
2. 요소 찾기 — locator
const box = page.locator('input[placeholder*="URL"]').first();
await box.fill(url);
await page.keyboard.press('Enter');
page.$ 같은 구식 API 대신 locator를 쓰면, 클릭 전에 자동으로 요소가 준비될 때까지 기다려줍니다. :has-text("문구") 같이 화면에 보이는 텍스트로 찾는 것도 가능해서, 클래스명이 난독화된 사이트에서 유용해요.
3. 화면 문구로 결과 판별
자동화는 "성공/실패"를 화면에서 읽어야 합니다.
await page.waitForSelector('text=/성공적으로 색인|미색인/', { timeout: 60_000 });
const text = await page.locator('body').innerText();
const status = text.includes('성공적으로 색인됐습니다') ? 'INDEXED' : 'NOT_INDEXED';
정규식으로 여러 후보 문구를 동시에 기다리는 패턴이 실전에서 제일 많이 쓰입니다.
4. 파일 업로드 — filechooser
티스토리 에디터에 이미지를 올릴 때 쓴 기법이에요. <input type="file">이 숨겨져 있어도 버튼 클릭 → filechooser 이벤트로 잡습니다.
const chooser = page.waitForEvent('filechooser', { timeout: 8_000 });
await imageButton.click();
await (await chooser).setFiles(imagePath);
5. 속도 제한 대응 — 사람처럼 느리게
자동화가 빠르면 차단당합니다. 그래서 일부러 느리게 돌려요.
- 액션 사이에 랜덤 대기 (1~3초)
- "잠시 후 다시 시도" 문구 감지 시 길게 쉬고 재시도
- 한 번에 몰아서 하지 않고 배치로 나누기
자주 만나는 함정
| 함정 | 해결 |
|---|---|
| 세션 만료 | 프로필 폴더를 지우지 않기. 만료되면 수동 재로그인 1회 |
| headless 차단 | headless: true여도 실제 크롬 채널+저장된 세션이면 대부분 통과 |
| 결과 로딩 타이밍 | waitForSelector로 결과 문구를 기다리기 — 고정 sleep은 불안정 |
| 캡챠 | 자동으로 못 넘습니다. 수동 개입 지점을 워크플로에 넣어야 해요 |
| UI 변경 | 셀렉터가 깨집니다. 대체 셀렉터 체인(aria-label → 텍스트 → 부모 순회)으로 방어 |
정리
- Playwright는 "사람이 브라우저로 하는 일"의 자동화예요. API가 없는 사이트가 주 무대입니다
- persistent context(세션 저장)가 핵심 — 로그인을 한 번만 하면 돼요
- locator + 화면 문구 매칭 + filechooser 조합이면 대부분의 웹 UI를 자동화할 수 있습니다
- 단, 속도 제한과 캡챠는 피할 수 없으니 "느리게, 사람처럼"이 원칙이에요
다음 글에서는 canonical(표준 주소)이 뭔지, 그리고 제 사이트에서 실제로 터졌던 canonical 버그 사례를 정리해볼게요.
'IT > Tool' 카테고리의 다른 글
| dmg가 조용히 사라졌다 — electron-builder YAML 들여쓰기 삽질기 (0) | 2026.11.14 |
|---|---|
| Playwright 심화 — 세션 저장, 파일 업로드, SPA 대기 (실전 삽질기) (0) | 2026.11.14 |
| [연금 저축 공제 환급 계산기] 연소득, 연금 저축 입금액을 입력하시면 연말 정산시 세액 공제액을 계산해드립니다. - 바로 변환해드려요. (0) | 2020.05.11 |
| 로또번호를 입력하시면 해당번호로 당첨될 뻔한 내역을 알려 드립니다. - 바로 변환해드립니다. (0) | 2020.04.21 |
| [LOTTO] 로또 회차번호를 선택하시면 1등 당첨내역 정보를 알려드려요. (0) | 2020.04.18 |