공통2026년 4월 26일·읽기 6·AXPERT 팀

셀렉터 캡처가 자꾸 어긋나는 이유 — AXPERT Extension v1.0.36 capture preview UX 공개

대상: AXPERT 콘텐츠 제작자, Extension 사용자, 셀렉터 시스템에 관심 있는 개발자

셀렉터 캡처가 자꾸 어긋나는 이유 — AXPERT Extension v1.0.36 capture preview UX 공개

사용자가 보고한 문제

"claude.ai 사이드바의 '결제' 메뉴를 클릭하니까 4번째 위치인데, 오버레이 박스는 맨 아래 9번째 'Chrome용 Claude' 자리에 잡힙니다. 위치가 자꾸 바뀝니다."

이런 보고가 들어왔을 때 우리는 두 가지 진단을 했습니다.

  1. DOM이 바뀐 것: claude.ai가 사이드바 구조를 바꿨나?
  2. selector가 부정확한 것: 우리가 캡처한 selector가 너무 generic해서 매번 다른 element에 매칭되나?

답은 두 번째였습니다. 그리고 보다 깊은 root cause는 따로 있었습니다.

진짜 원인 — selector가 unique 하지 않다

캡처 시점에 사용자가 클릭한 요소의 fingerprint를 보면 다음과 같았습니다.

element_key: claude_a_결제
primary_selector: a.font-base.block.whitespace-nowrap
text: "Chrome용 Claude베타"  ← 결제가 아님!

문제 1: selector가 generica.font-base.block.whitespace-nowrap은 사이드바의 9개 메뉴 모두 매칭됩니다. querySelector 호출 시 첫 번째 또는 가장 가까운 element만 잡히고, DOM이 살짝만 바뀌어도 다른 element가 잡힙니다.

문제 2: 캡처 자체가 어긋남 — element_key는 "결제"인데 text는 "Chrome용 Claude베타". 즉 사용자가 결제를 클릭했다고 생각했지만 캡처된 element는 다른 곳입니다.

v1.0.36의 4가지 해결책

1. 매칭 카운트 배지

캡처 모달에서 selector를 빌드한 직후 document.querySelectorAll(selector).length를 호출해 즉시 표시합니다.

  • ✓ unique (1 match) — 안전, 초록 배지
  • ⚠ N matches — 위치 어긋남 위험, 노랑 배지
  • 🚨 N matches — generic, 빨강 배지

사용자는 저장 버튼을 누르기 전에 자기 selector가 몇 개 element와 매칭되는지 봅니다. 1이 아니면 재캡처 권장.

2. 위치 미리보기 (3초 깜빡 highlight)

🔍 "위치 미리보기" 버튼 클릭 시:

  • selector로 매칭되는 모든 element에 깜빡이는 outline 적용
  • 첫 번째 element를 화면 중앙으로 scrollIntoView
  • 3초 후 자동 정리

이걸로 사용자는 "내가 클릭한 게 진짜 그 element인가?"를 한눈에 확인합니다.

3. ancestor walk 5단계 + nth-of-type fallback

selector가 unique하지 않을 때 자동으로 보강하는 알고리즘:

1. class chain 3 → 2 → 1 단계 시도
2. 5단계 조상까지 walk — data-testid / aria-label / id / role 발견 시 prefix
3. semantic landmark (nav/aside/header) 자동 활용
4. 그래도 unique 안 되면 nth-of-type 추가
5. best non-unique 폴백 (match 수 가장 적은 candidate)

claude.ai 사이드바 헤더처럼 data-testid가 없는 element도 nav h2:nth-of-type(N) 같은 selector로 자동 unique화 됩니다.

4. Ctrl+클릭 escape hatch

사용자가 메뉴 탐색 모드 도중 그냥 페이지 이동하고 싶을 때:

  • 일반 클릭 = 캡처 + 페이지 동작 (둘 다 진행)
  • Ctrl/⌘ + 클릭 = 캡처 스킵, 페이지 동작만 (escape)

새 페이지로 이동해도 chrome.storage에 캡처 리스트가 보존되어 자동 재개됩니다.

보안 강화 (덤)

같은 사이클에 발견한 보안 이슈도 함께 해결했습니다.

XSS — renderExploreList innerHTML

DOM에서 추출한 텍스트(aria-label, href)를 HTML 템플릿 리터럴에 그대로 삽입하던 버그. 악의적 페이지가 aria-label="</span><img onerror=...>" 같은 텍스트를 가지면 Extension이 그 페이지 컨텍스트에서 JS를 실행할 수 있었습니다.

Fix: escHtml() 헬퍼 — & < > " ' HTML entity 인코딩.

CSS injection

tryCandidates.push(\[data-testid="${value}"]`)같은 selector 빌드 코드. 값에][`가 있으면 selector syntax 깨지고 silent fail.

Fix: CSS.escape() — attribute value의 모든 특수 문자 처리.

배포 결과

  • CWS (Chrome Web Store): v1.0.13 → v1.0.36 게시 (23 versions stale 해소)
  • 직접배포: /downloads/axpert-extension-v1.0.36.zip 156KB
  • 로컬 dev: chrome://extensions reload 한 번이면 즉시 활성화

기존에 위치 어긋남이 있었던 element들은 재캡처 한 번이면 ancestor walk + capture preview UX로 unique selector가 생성됩니다.

마무리

UI 셀렉터는 끊임없이 깨집니다. 우리는 자동 복구(self-heal AI recovery layer)와 사용자 도구(capture preview) 두 축으로 대응합니다. 후자가 더 중요한 이유는, 사용자가 잘못된 캡처를 즉시 인지할 수 있어야 시스템이 천천히 무너지지 않기 때문입니다.

다음 사이클은 selector pool 평균 점수를 90+로 끌어올리는 LLM augment 가속 작업입니다. 이미 cron이 매분 자동 가동 중이고, 평균은 약 +1점/시간 속도로 상승하고 있습니다.


관련 글: 영상 시청과 실습이 다른 이유 · 이랜드 케이스 스터디

태그
#Extension#제품노트#셀렉터#UX

글로 읽었다면, 이제 직접 만들어보세요

AXPERT는 영상이 아닌 실제 AI 서비스에서 직접 실습하는 학습 플랫폼입니다.

무료 퀵 가이드로 시작하기 →