# Playwright 기반 네이버 블로그 "사람처럼" 발행 모듈

## 작업 개요
기존 SE API 직접 호출 방식(쿠키 추출 → httpx)이 네이버 봇 탐지에 차단되어,
**Playwright로 실제 사람이 블로그 글을 쓰는 것처럼** 전체 과정을 UI 자동화로 수행하는 모듈을 구현한다.

## 핵심 원칙: "사람처럼"
- 모든 클릭, 타이핑, 페이지 이동에 **랜덤 딜레이** 삽입
- 마우스 이동도 직선이 아닌 **자연스러운 곡선**으로
- 입력 시 기존 `human_type()` (150~350ms/글자, 5~10% 오타+백스페이스) 활용
- 스크롤도 한 번에 하지 않고 **여러 번 나눠서**

## 산출물 위치
`/home/jay/projects/BlogAuto/publisher/naver_playwright.py`

## 참조 파일
- 기존 로그인 모듈: `/home/jay/projects/BlogAuto/publisher/naver_login.py` (human_type 함수 재사용)
- 기존 SE 에디터 모듈: `/home/jay/projects/BlogAuto/publisher/naver_blog.py` (API 방식 — 참고만)
- 발행할 콘텐츠: `/home/jay/workspace/output/blog/naver/content-20260408-인카금융.md`
- 발행할 이미지: `/home/jay/workspace/output/blog/naver/images/` (3장)
- 인증 정보: `/home/jay/projects/BlogAuto/.env.keys` (NAVER_LOGIN_ID, NAVER_LOGIN_PW)
  - 주의: `export` 접두사 없는 버전 사용 중

## 구현 요구사항

### 1. 전체 플로우
```
1. Playwright persistent context 실행 (Chrome 프로필 유지)
2. 네이버 로그인 (이미 로그인 상태면 스킵)
   - naver_login.py의 human_type() 재사용
   - 로그인 후 2~3초 대기
3. 블로그 글쓰기 페이지로 이동
   - https://blog.naver.com/blogpc001?Redirect=Write
   - SE 에디터 로딩 대기 (3~5초)
4. 제목 입력
   - 제목 입력란 클릭 → human_type으로 타이핑
5. 본문 입력 (핵심)
   - SE 에디터 본문 영역 클릭
   - 단락별로 human_type으로 타이핑
   - 단락 사이 Enter 2번 (빈 줄)
   - quotation(인용구) 삽입: 에디터 도구모음에서 인용구 버튼 클릭 → 스타일 선택 → 텍스트 입력
   - 구분선(---) 삽입: 에디터 도구모음에서 구분선 버튼 클릭
6. 이미지 삽입
   - 이미지 버튼 클릭 → 파일 선택 다이얼로그 → set_input_files() 사용
   - 업로드 완료 대기 (3~5초)
   - 적절한 위치에 삽입
7. 태그 입력
   - 태그 입력란에 키워드 입력 (Enter로 구분)
8. 발행 버튼 클릭
   - "발행" 버튼 찾기 → 클릭
   - 발행 완료 확인 (URL 변경 또는 성공 메시지)
```

### 2. 핵심 함수들

```python
class NaverPlaywrightPublisher:
    def __init__(self, headless=True):
        ...
    
    def _random_delay(self, min_sec=0.5, max_sec=2.0):
        """랜덤 딜레이"""
    
    def _human_mouse_move(self, page, x, y):
        """자연스러운 마우스 이동 (베지어 곡선)"""
    
    def _human_scroll(self, page, amount):
        """자연스러운 스크롤 (여러 번 나눠서)"""
    
    def _login_if_needed(self, page):
        """로그인 상태 확인 → 필요 시 human_type으로 로그인"""
    
    def _navigate_to_write(self, page):
        """글쓰기 페이지로 이동 + SE 에디터 로딩 대기"""
    
    def _type_title(self, page, title):
        """제목 입력"""
    
    def _type_body(self, page, paragraphs):
        """본문 입력 — 단락별 타이핑 + 인용구/구분선 삽입"""
    
    def _insert_image(self, page, image_path):
        """이미지 삽입 — 파일 업로드"""
    
    def _add_tags(self, page, tags):
        """태그 입력"""
    
    def _click_publish(self, page):
        """발행 버튼 클릭"""
    
    def publish(self, title, content_md, images, tags, visibility='public'):
        """전체 플로우 실행"""
```

### 3. 콘텐츠 파싱
- 마크다운 콘텐츠에서 frontmatter 제거
- `[quotation_line]텍스트[/quotation_line]` → 인용구(line 스타일) 삽입
- `[quotation_postit]텍스트[/quotation_postit]` → 인용구(postit 스타일) 삽입
- `[quotation_corner]텍스트[/quotation_corner]` → 인용구(corner 스타일) 삽입
- `---` → 구분선 삽입
- `[이미지: ...]` → 해당 위치에 이미지 삽입
- 나머지 텍스트 → 일반 단락으로 타이핑

### 4. SE 에디터 UI 요소 탐색 힌트
- 이전에 Chrome CDP로 캡처한 정보:
  - SE 에디터 내부 객체: `SmartEditor._editors["blogpc001"]._documentService`
  - 인용구 버튼: 에디터 도구모음의 인용구 아이콘
  - 이미지 버튼: 에디터 도구모음의 사진 아이콘
- Playwright의 `page.frame_locator()` 또는 `page.locator()` 활용
- SE 에디터가 iframe 안에 있을 수 있으니 iframe 탐색 필요

### 5. CLI
```bash
# 마크다운 파일로 발행
python3 -m publisher.naver_playwright publish \
  --content /path/to/content.md \
  --images /path/to/images/ \
  --visibility public

# 헤드풀 모드 (디버깅용, 브라우저 창 표시)
python3 -m publisher.naver_playwright publish \
  --content /path/to/content.md \
  --headful
```

### 6. 테스트
- human_type 재사용 확인
- 콘텐츠 파싱 단위 테스트 (quotation/구분선/이미지 위치 추출)
- 랜덤 딜레이 범위 검증
- 마우스 이동 좌표 검증 (시작점→끝점 사이에 중간점들이 있는지)
- 실제 발행은 headful 모드로 수동 확인 필요

### 7. 발행 테스트
구현 완료 후, 아래 콘텐츠로 실제 발행 테스트:
- 콘텐츠: `/home/jay/workspace/output/blog/naver/content-20260408-인카금융.md`
- 이미지: `/home/jay/workspace/output/blog/naver/images/` (3장)
- 태그: 인카금융,보험대리점,보험영업,보험GA,인카보험,인카다이렉트,GA보험,보험설계사이직,GA보험대리점취업,인카금융설계사조건
- 블로그: incar_top
- visibility: **임시저장(draft)으로 먼저 테스트** — 문제 없으면 public

## 주의사항
- headless=True가 기본이지만, **네이버는 headless를 탐지**할 수 있으므로 `--headful` 옵션 지원 필수
- Playwright launch args에 `--disable-blink-features=AutomationControlled` 추가
- user-agent는 일반 Chrome UA 사용
- persistent context로 Chrome 프로필 유지하면 한번 로그인 후 세션 유지됨
- 원격 브라우저(100.76.130.39:9222)는 사용하지 않음 — 로컬 Playwright 사용
- pyright 에러 0건

## 완료 기준
1. 모듈 구현 완료 + 테스트 PASS
2. 실제 네이버 블로그에 임시저장 성공 (헤드풀 모드)
3. 제목, 본문, 인용구, 구분선, 이미지, 태그가 모두 정상 삽입 확인