Blogger 테마 XML 자동 업로드 — Playwright + 9222 CDP 로 수동 클릭 0회

활용 팁 / 블로그 운영 / Python · 자동화
약 2,500자

Blogger 의 단점 하나는 테마 XML 을 바꿀 때마다 관리자 UI 에서 "테마 → 백업 / 복원 → 업로드" 클릭 3~4번 + 로그인 확인 + 적용 대기까지 한 번에 5분 가까이 걸리는 점입니다. 우리는 이걸 Playwright + Chrome 9222 CDP 로 자동화해서 사람 클릭 0회로 줄였습니다. 만든 의도와 실제 동작, 효과, 검증까지 그대로 풀어 둡니다.

만든 이유

테마 작업은 빈번한 시기엔 하루 5~10번 발생합니다. 색상 한 줄, 폰트 두께 한 줄, 사이드바 위치 한 줄을 바꾸고 라이브에서 결과를 확인하기까지 매번 5분이 들면 작업 흐름이 끊깁니다.

또 Blogger 의 옛 "테마 복원" 경로는 BTP (이전 사이트 이름) 같은 1세대 Classic mode 트리거가 있어서 한 번 잘못 누르면 사이트 전체 레이아웃이 옛 1세대로 회귀했습니다. 우리는 이걸 두 번 재현하고 나서 "복원" 경로를 코드 상에서 영구 차단했습니다. 안전한 경로는 단 하나, 관리자의 "현재 테마의 소스 코드 수정" 화면 (CodeMirror 편집기) 에 setValue 로 XML 전체를 직접 넣는 방식입니다.

이 흐름을 매번 손으로 하지 않게 자동화한 모듈을 만들었습니다.

작동 원리

핵심은 사람이 이미 9222 포트로 띄워둔 Chrome 에 Playwright 가 붙어서 (CDP attach) 자기 명령을 보내는 구조입니다. 새 브라우저를 별도로 띄우지 않습니다. 그래야 Google 로그인이 이미 살아있어서 CAPTCHA / 2FA 통과가 자동입니다.

순서:

  1. Chrome 9222 alive 확인http://127.0.0.1:9222/json/version 응답이 200 이면 살아있음. 죽었으면 사용자에게 "9222 Chrome 켜주세요" 알림 (Discord). 자동 기동은 OS 별 분기.
  2. Playwright CDP attachplaywright.chromium.connect_over_cdp("http://127.0.0.1:9222") 한 줄. 새 브라우저 X.
  3. 타깃 탭 찾기 — 이미 열려있는 탭 중 blogger.com/blog/themes/ 인 게 있으면 거기로 이동. 없으면 새 탭 open.
  4. "현재 테마의 소스 코드 수정" 버튼 클릭 — aria-label 또는 텍스트 selector. 한국어/영어 두 locale 다 지원.
  5. CodeMirror 편집기 활성화 대기document.querySelector('.CodeMirror') 가 나타날 때까지 polling.
  6. CodeMirror.setValue(xml) 호출 — Playwright 의 evaluate 안에서 직접 호출. clipboard / typing 아님. 50KB XML 도 즉시 반영.
  7. "테마 저장" 버튼 클릭 — 저장 후 "테마가 업데이트되었습니다" toast 가 뜨면 OK.
  8. 라이브 spot check — 60초 대기 후 https://blog-url/ fetch. theme.xml 의 sentinel comment (예: ) 가 응답에 포함되면 verified=True.

전 과정 평균 30초. 사람 클릭 0회.

실제 효과

  • 한 번 업로드 시간: 5분 → 30초 (90% 단축)
  • 누적 자동 업로드 횟수: 사용 개시 후 약 320회
  • "복원" 경로 잘못 눌러서 1세대 Classic 모드로 회귀한 사고: 도입 전 2건 → 도입 후 0건
  • 실패 사례: 9222 Chrome 죽음 4건 / Google 로그인 만료 2건 / CAPTCHA 1건. 모두 사람 알림 → 수동 복구.
  • 백업: 매 업로드 전 theme.xml.before. 자동 저장. 잘못된 업로드 시 1초 안에 직전 버전으로 롤백 가능.

부가 효과로 "테마 한 줄 바꿔 보고 싶다" 라는 가벼운 실험이 늘었습니다. 매번 5분 든다고 생각하면 망설이게 되지만 30초면 그냥 해 봅니다. 결과적으로 디자인 iteration 이 빨라졌습니다.

검증 방법

세 가지 검증을 했습니다.

XML round-trip 검증 — 업로드 후 같은 페이지의 CodeMirror 에서 getValue() 를 다시 호출해서 그 값이 우리가 보낸 XML 과 byte-by-byte 동일한지 확인합니다. Blogger 의 SkinVariables 파서가 silent reject 하는 케이스 (CDATA 안에 raw HTML 토큰이 있는 경우 등) 를 잡기 위한 안전망입니다. 320회 중 silent reject 잡힌 케이스 5건.

라이브 spot check — 업로드 후 60초 대기 후 라이브 사이트 fetch. theme.xml 의 sentinel 마커가 응답에 포함되는지 확인. 320/320 통과.

1세대 Classic 모드 회귀 방지 테스트 — 의도적으로 "복원" 버튼을 우리 자동화가 누르려고 시도하면 코드 상에서 차단되는지 단위 테스트로 확인. assert "restore" not in click_targets 에서 항상 통과. 차단 hook 이 정상 작동.

따라 만드는 법

전체 모듈을 옮기는 것보다 핵심 두 줄만 가져가는 게 실용적입니다.

먼저 Chrome 을 9222 포트로 띄웁니다.


# Windows
"C:\Program Files\Google\Chrome\Application\chrome.exe" \
 --remote-debugging-port=9222 \
 --user-data-dir=C:\chrome_debug_profile

# macOS
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
 --remote-debugging-port=9222 \
 --user-data-dir=$HOME/chrome_debug_profile

그 다음 Playwright 로 attach 합니다.


import asyncio
from playwright.async_api import async_playwright

BLOG_ID = "1234567890"
THEME_XML = open("theme.xml", encoding="utf-8").read()

async def upload_theme(xml: str):
 async with async_playwright() as p:
 browser = await p.chromium.connect_over_cdp("http://127.0.0.1:9222")
 ctx = browser.contexts[0]
 page = await ctx.new_page()
 await page.goto(f"https://www.blogger.com/blog/themes/{BLOG_ID}")
 # "현재 테마의 소스 코드 수정"
 await page.click("text=현재 테마의 소스 코드 수정")
 await page.wait_for_selector(".CodeMirror", timeout=30000)
 await page.evaluate(
 "(xml) => document.querySelector('.CodeMirror').CodeMirror.setValue(xml)",
 xml,
 )
 await page.click("button:has-text('테마 저장')")
 await page.wait_for_selector("text=테마가 업데이트되었습니다", timeout=60000)
 await browser.close()
 print("uploaded")

asyncio.run(upload_theme(THEME_XML))

여기서 핵심은 connect_over_cdp 한 줄과 CodeMirror.setValue 한 줄입니다. 나머지는 selector 다듬는 작업입니다.

복원 경로는 절대 누르지 마세요. 같은 페이지에 "복원" 버튼이 같이 있는데 그건 우리 사고 case 입니다. 한 번 누르면 1세대 Classic 으로 회귀해서 라이브가 무너집니다. 자동화에는 그 selector 를 코드 상에서 명시 차단해 두는 게 안전합니다.

요약: Chrome 을 9222 포트로 띄우고 Playwright 로 attach 한 후 CodeMirror.setValue 한 줄만 호출하면 Blogger 테마 자동 업로드가 됩니다. 첫 setup 한 번이면 그 뒤로는 한 줄 명령으로 모든 업데이트가 자동입니다.

Category Coverage Notice

This article follows our label-specific editorial criteria. Details:

ToolSignal Pro Editorial

ToolSignal Pro는 AI·IT·소프트웨어 트렌드를 다루는 종합 IT 인사이트 매거진입니다.

이전 글 다음 글