웹 자동화는 현대 개발 워크플로우에서 필수적인 요소로 자리 잡았습니다. 그중에서도 Playwright는 탁월한 안정성과 강력한 API로 많은 개발자에게 사랑받고 있죠. 하지만 실제 환경에서는 단순한 웹사이트 자동화가 아닌, OAuth를 통한 로그인이나 복잡한 WYSIWYG 에디터 제어와 같은 까다로운 시나리오에 직면하곤 합니다. 오늘은 Playwright를 활용하여 Tistory의 카카오 OAuth 로그인 과정을 자동화하고, 더 나아가 TinyMCE 에디터에 콘텐츠를 완벽하게 입력하는 과정에서 얻은 경험과 핵심 팁들을 공유하고자 합니다.
Tistory는 자체 계정 로그인 외에도 카카오, 네이버 등 다양한 소셜 로그인 옵션을 제공하며, 특히 카카오 로그인은 여러 단계의 리다이렉션과 동적인 DOM 변경을 수반하여 자동화 스크립트를 작성하는 데 상당한 난이도를 가집니다. 여기에 포스팅 시 만나는 TinyMCE 에디터는 일반적인 텍스트 입력 방식으로는 제어가 어렵죠. 이 포스트를 통해 이러한 난관들을 Playwright로 어떻게 극복했는지, 그리고 강력한 셀렉터 활용법과 TinyMCE 제어 팁까지 상세히 알아보겠습니다.
Playwright, 복잡한 Tistory 로그인에 도전하다
Tistory 로그인 자동화의 첫 관문은 다름 아닌 소셜 로그인, 그중에서도 카카오 OAuth입니다. 이 과정은 단순히 아이디와 비밀번호를 입력하는 것을 넘어, 카카오 로그인 페이지로 이동했다가 다시 Tistory로 리다이렉션되는 복잡한 흐름을 가집니다. Playwright는 이러한 흐름을 안정적으로 따라갈 수 있는 강력한 기능을 제공하지만, 핵심은 각 단계에서 적절한 대기 전략과 정확한 셀렉터를 사용하는 것입니다.
- 페이지 이동 및 대기:
page.goto('https://www.tistory.com/login')로 시작하여 로그인 페이지로 이동합니다. 이후 카카오 로그인 버튼을 찾아 클릭하면 새로운 OAuth 창이 열리거나, 현재 페이지가 카카오 로그인 페이지로 변경됩니다. 중요한 것은 이 변경 사항이 완전히 로드될 때까지 기다리는 것입니다.page.wait_for_url()또는page.wait_for_load_state('networkidle')와 같은 메서드를 활용하여 페이지가 안정화될 때까지 기다려야 다음 액션을 성공적으로 수행할 수 있습니다. - 카카오 로그인 처리: 카카오 로그인 페이지에서는 사용자 이메일과 비밀번호를 입력해야 합니다. 이때
page.fill('input[name=\'email\']', 'your_email@kakao.com')과 같이 정확한 셀렉터를 사용하고,page.click('button[type=\'submit\']')으로 로그인 버튼을 클릭합니다. 여기서 발생할 수 있는 문제는 카카오 로그인 후 추가 동의 화면이나 보안 인증 화면이 나타날 수 있다는 점입니다. 스크립트는 이러한 예상치 못한 단계도 처리할 수 있도록 유연하게 설계되어야 합니다. - 리다이렉션 후 Tistory 진입: 카카오 로그인이 성공하면 Tistory는 OAuth 콜백 URL을 통해 사용자 인증 정보를 받고 로그인 세션을 설정합니다. 이 과정에서 여러 번의 리다이렉션이 발생할 수 있으므로, 최종적으로 Tistory 관리자 페이지 URL로 진입하는지
page.wait_for_url('https://*.tistory.com/manage')와 같은 방식으로 확인하는 것이 중요합니다.
이 모든 과정에서 Playwright의 Locator 객체는 DOM이 동적으로 변하더라도 요소를 자동으로 재탐색해주므로, 스크립트의 안정성을 크게 높여줍니다. 각 단계마다 스크린샷을 찍거나 로그를 남기면 디버깅에 큰 도움이 됩니다.
강력한 셀렉터 활용으로 미로 찾기
웹 자동화에서 가장 중요한 요소 중 하나는 '정확하고 안정적인 셀렉터'를 사용하는 것입니다. 웹 페이지의 DOM 구조는 수시로 변경될 수 있기 때문에, 단순한 CSS 셀렉터나 XPath만으로는 부족할 때가 많습니다. Playwright는 이를 보완하기 위해 다양한 종류의 셀렉터를 제공하며, 특히 getBy* 로케이터는 매우 강력한 도구입니다.
page.getByLabel(): 입력 필드에 레이블이 명확하게 지정되어 있을 때 유용합니다. 예를 들어, 카카오 로그인 페이지의 이메일 입력 필드가<label for='email_id'>아이디</label><input id='email_id' ...>와 같이 구성되어 있다면,page.getByLabel('아이디')로 접근할 수 있습니다.page.getByPlaceholder(): 입력 필드에 플레이스홀더 텍스트가 있는 경우에 편리합니다. 비밀번호 입력 필드가<input type='password' placeholder='비밀번호' ...>라면page.getByPlaceholder('비밀번호')를 사용할 수 있습니다.page.getByText(): 특정 텍스트를 포함하는 요소를 찾을 때 사용합니다. 예를 들어, '로그인' 텍스트를 가진 버튼을 찾을 때page.getByText('로그인').click()와 같이 사용할 수 있습니다. 이 방법은 개발자가 동적으로 생성하는 클래스 이름이나 ID에 영향을 받지 않아 매우 안정적입니다.page.getByRole(): 웹 접근성 속성인 ARIA 역할(role)을 기반으로 요소를 찾습니다. 버튼('button'), 링크('link'), 텍스트 박스('textbox') 등 다양한 역할을 지정할 수 있습니다.page.getByRole('button', name='로그인')은 '로그인' 텍스트를 가진 버튼을 찾는 데 매우 효과적입니다.- CSS 및 XPath 조합:
getBy*로케이터로 충분하지 않거나 더 정교한 탐색이 필요할 때는 여전히 CSS 셀렉터나 XPath를 사용할 수 있습니다. 예를 들어,page.locator('.some-class > div:nth-child(2) input')와 같이 특정 구조 내의 요소를 찾거나,page.locator('//div[@id=\'parent\']/child::*')와 같이 XPath의 강력한 계층적 탐색을 활용할 수 있습니다.
안정적인 셀렉터를 선택하는 가장 좋은 방법은 Playwright Inspector를 활용하는 것입니다. 스크립트 실행 중 Inspector를 켜면 마우스로 요소를 클릭하여 Playwright가 추천하는 셀렉터를 자동으로 얻을 수 있습니다. 또한, 웹사이트의 변화에 강인한 셀렉터를 구성하려면 ID나 고유한 텍스트 콘텐츠를 기반으로 하는 셀렉터를 우선적으로 고려하는 것이 좋습니다.
TinyMCE 에디터 제어: 콘텐츠 입력의 핵심
Tistory를 비롯한 많은 CMS에서 사용하는 TinyMCE는 HTML 콘텐츠를 시각적으로 편집할 수 있게 해주는 WYSIWYG(What You See Is What You Get) 에디터입니다. 이 에디터는 일반적인 <textarea>와 달리 iframe 내부에 자체적인 DOM 구조를 가지고 있기 때문에, Playwright의 page.fill() 메서드를 직접 사용하는 것만으로는 콘텐츠를 입력하기 어렵습니다.
iframe탐색: TinyMCE는 일반적으로<iframe>태그 내에 로드됩니다. 따라서 Playwright로 이 에디터를 제어하려면 먼저 해당iframe을 찾아야 합니다. Tistory의 경우, TinyMCEiframe은 보통title='Rich Text Editor'와 같은 속성을 가지고 있습니다. Playwright의page.frame_locator("iframe[title='Rich Text Editor']")를 사용하여iframe내부의 컨텍스트에 접근할 수 있습니다.- 콘텐츠 입력 전략:
iframe내부로 접근한 후, 에디터의 실제 콘텐츠를 담고 있는<body>태그를 찾아서fill()메서드를 적용할 수 있습니다. 예를 들어, HTML 콘텐츠를 입력하고 싶다면 다음과 같이 사용합니다:const editorFrame = page.frame_locator('iframe[title=\\'Rich Text Editor\\']');editorFrame.locator('body').fill('<p>안녕하세요, Playwright로 작성된 글입니다.</p>');
이 방법은 텍스트 콘텐츠뿐만 아니라 HTML 태그가 포함된 풍부한 콘텐츠도 쉽게 삽입할 수 있게 해줍니다. - JavaScript 주입을 통한 제어: 때로는
fill()만으로는 복잡한 에디터 동작을 완벽하게 재현하기 어려울 수 있습니다. 이럴 때는page.evaluate()또는frame_locator().evaluate()메서드를 사용하여 JavaScript 코드를 직접 실행하는 것이 효과적입니다. 예를 들어, TinyMCE의 내부 API를 호출하거나,document.execCommand('insertHTML', false, html_content)와 같은 브라우저 내장 명령어를 사용할 수 있습니다. 하지만 이 방법은 에디터의 특정 버전이나 설정에 따라 동작이 달라질 수 있으므로 주의가 필요합니다. - 에디터 초기화 대기: TinyMCE는 로드되는 데 시간이 걸릴 수 있습니다.
iframe자체가 로드된 후에도 에디터 내부의 DOM이 완전히 준비될 때까지 기다려야 합니다.editorFrame.locator('body').wait_for()와 같은 명시적인 대기 명령을 사용하여 에디터가 상호작용 가능한 상태인지 확인하는 것이 중요합니다.
TinyMCE 에디터를 효과적으로 제어하는 것은 웹 자동화의 중요한 부분입니다. HTML 콘텐츠를 직접 삽입하고 싶을 때는 frame_locator().locator('body').fill() 방법을, 더 세밀한 제어가 필요할 때는 JavaScript 주입을 고려해보세요. 항상 에디터가 완전히 로드되고 준비될 때까지 대기하는 것을 잊지 말아야 합니다.
자동화 스크립트 구축 및 배포 팁
복잡한 웹 자동화 스크립트를 성공적으로 개발하는 것만큼 중요한 것은, 이를 안정적으로 운영하고 배포하는 것입니다. Playwright 기반의 Tistory 자동화 스크립트를 효율적으로 구축하고 관리하기 위한 몇 가지 팁을 공유합니다.
- 모듈화된 스크립트 구조: 로그인, 게시물 작성, 이미지 업로드 등 각 기능을 별도의 함수나 클래스로 분리하여 모듈화하는 것이 좋습니다. 이는 코드의 가독성을 높이고 유지보수를 용이하게 합니다. 예를 들어,
tistory_login(page, email, password),create_post(page, title, content, tags)와 같은 함수를 만들 수 있습니다. - Headless 모드 활용: 실제 브라우저 UI 없이 백그라운드에서 실행되는 Headless 모드는 자동화 스크립트의 실행 속도를 크게 향상시키고, 서버 환경에서 메모리 사용량을 줄여줍니다. Playwright를 초기화할 때
headless=True옵션을 설정하면 됩니다. 단, 디버깅 시에는headless=False로 설정하여 브라우저의 실제 동작을 확인하는 것이 좋습니다. - 환경 변수를 통한 자격 증명 관리: 카카오 이메일, 비밀번호와 같은 민감한 정보는 절대로 코드에 직접 포함해서는 안 됩니다.
.env파일이나 시스템 환경 변수를 사용하여 관리하고, 스크립트에서 이를 로드하여 사용해야 합니다. 이는 보안을 강화하고, 스크립트의 재사용성을 높여줍니다.python-dotenv라이브러리를 활용하면 파이썬에서.env파일을 쉽게 로드할 수 있습니다. - 견고한 오류 처리 및 로깅: 웹 자동화는 네트워크 지연, DOM 변경 등으로 인해 예상치 못한 오류가 발생할 수 있습니다.
try-except블록을 사용하여 오류를 처리하고, 문제가 발생했을 때 스크린샷을 찍거나 상세한 로그를 남기면 디버깅 시간을 크게 단축할 수 있습니다. Playwright의page.screenshot()메서드는 오류 발생 시 상태를 파악하는 데 매우 유용합니다. - CI/CD 및 스케줄링: 자동화 스크립트를 주기적으로 실행해야 한다면, CI/CD 파이프라인(예: GitHub Actions)이나 서버의 스케줄러(예: cron job, Windows Task Scheduler)에 등록하여 자동화하는 것을 고려할 수 있습니다. Docker 컨테이너에 Playwright 스크립트를 패키징하면, 어떤 환경에서도 일관된 방식으로 실행할 수 있어 배포가 훨씬 쉬워집니다.
이러한 팁들을 통해 더욱 안정적이고 효율적인 Playwright 자동화 스크립트를 구축하고, Tistory와 같은 복잡한 웹 서비스에서도 원하는 작업을 성공적으로 수행할 수 있을 것입니다.
마치며
오늘은 Playwright를 사용하여 Tistory의 복잡한 카카오 OAuth 로그인 과정을 자동화하고, TinyMCE 에디터에 콘텐츠를 입력하는 방법에 대해 자세히 알아보았습니다. 강력한 getBy* 로케이터와 frame_locator()를 활용한 TinyMCE 제어는 많은 개발자들에게 큰 도움이 될 것입니다. 웹 자동화는 단순히 반복 작업을 줄이는 것을 넘어, 서비스의 동작 방식을 깊이 이해하고 예상치 못한 문제에 대응하는 능력을 길러줍니다. Playwright의 무궁무진한 가능성을 탐험하며 여러분의 개발 여정을 더욱 풍성하게 만들어나가시길 바랍니다.