실전 사례 가이드
이 장에서는 실제 프로젝트에 즉시 적용할 수 있는 5가지 완전한 스크립트 템플릿을 제공합니다. 가장 일반적인 다계정 자동화 시나리오를 다루며, 각 사례는 JavaScript와 Python 버전을 모두 포함합니다.
사례 1: 자동 로그인 및 상태 유지
시나리오: 특정 Mbbrowser 환경에서 대상 플랫폼에 자동으로 로그인합니다.
javascript
// JavaScript 버전
const { chromium } = require('playwright');
const axios = require('axios');
const API_URL = 'http://127.0.0.1:8186';
const SESSION_ID = '사용자_환경_ID_입력';
async function autoLogin() {
// ── Mbbrowser 환경 열기 ────────────────────────────────────
const { data } = await axios.post(`${API_URL}/api/v1/browser/start`, {
Session_ID: SESSION_ID
});
if (data.code !== 0) throw new Error(`시작 실패: ${data.message}`);
const wsEndpoint = data.data.ws;
const browser = await chromium.connectOverCDP(wsEndpoint);
const context = browser.contexts()[0];
const page = context.pages()[0] || await context.newPage();
try {
// ── 로그인 페이지 열기 및 양식 채우기 ──────────────────────
await page.goto('https://example.com/login', { waitUntil: 'domcontentloaded' });
// Playwright에서 권장하는 getByRole 위치 지정 방식
await page.getByLabel('이메일').fill('my_account@email.com');
await page.getByLabel('비밀번호').fill('my_password_123');
await page.getByRole('button', { name: '로그인' }).click();
// 대시보드로 이동할 때까지 대기 (성공적인 로그인의 신호)
await page.waitForURL('**/dashboard', { timeout: 15000 });
console.log('✅ 로그인 성공! 현재 URL:', page.url());
// Mbbrowser는 쿠키를 자동으로 유지하므로 다음 번에는 로그인할 필요가 없습니다.
console.log('🔒 쿠키가 Mbbrowser 환경에 자동으로 저장되었습니다.');
} catch (e) {
console.error('❌ 로그인 실패:', e.message);
await page.screenshot({ path: 'login_error.png', fullPage: true });
} finally {
await browser.close();
}
}
autoLogin().catch(console.error);python
# Python 버전
import requests
from playwright.sync_api import sync_playwright
API_URL = "http://127.0.0.1:8186"
SESSION_ID = "사용자_환경_ID_입력"
def auto_login():
resp = requests.post(
f"{API_URL}/api/v1/browser/start",
json={"Session_ID": SESSION_ID}, timeout=30
)
data = resp.json()
if data["code"] != 0:
print(f"❌ 시작 실패: {data['message']}")
return
ws = data["data"]["ws"]
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(ws)
context = browser.contexts[0]
page = context.pages[0] if context.pages else context.new_page()
try:
page.goto("https://example.com/login", wait_until="domcontentloaded")
page.get_by_label("이메일").fill("my_account@email.com")
page.get_by_label("비밀번호").fill("my_password_123")
page.get_by_role("button", name="로그인").click()
page.wait_for_url("**/dashboard", timeout=15000)
print(f"✅ 로그인 성공! 현재 URL: {page.url}")
except Exception as e:
print(f"❌ 로그인 실패: {e}")
page.screenshot(path="login_error.png", full_page=True)
finally:
browser.close()
if __name__ == "__main__":
auto_login()사례 2: 즉시 로그인을 위한 쿠키 주입
시나리오: 기존 쿠키 데이터를 주입하여 로그인 양식을 생략하고 즉시 접속합니다.
javascript
// JavaScript 버전
async function injectAndLogin(page, context) {
// 참고: 쿠키를 설정하기 위해 먼저 대상 도메인을 열어야 합니다.
await page.goto('https://shop.example.com', { waitUntil: 'commit' });
// 준비된 쿠키 배열 주입
await context.addCookies([
{ name: 'session_id', value: 'SID_abcdef123456', domain: '.example.com', path: '/' },
{ name: 'auth_token', value: 'Bearer_xyz789', domain: '.example.com', path: '/' }
]);
// 쿠키를 적용하기 위해 페이지 새로고침
await page.reload({ waitUntil: 'domcontentloaded' });
// 성공적인 접속 확인
const accountEl = page.getByRole('button', { name: '내 계정' });
if (await accountEl.isVisible()) {
console.log('✅ 쿠키 주입 성공! 로그인되었습니다.');
} else {
console.warn('⚠️ 쿠키가 만료되었을 수 있습니다. 다시 확보해 주세요.');
}
}NOTE
Mbbrowser의 핵심 가치: 일단 한 번 Mbbrowser 환경 내에서 성공적으로 로그인하면, 해당 쿠키는 해당 환경의 데이터 디렉토리에 영구적으로 저장됩니다. 이 "지속적인 환경"이 바로 핑거프린트 브라우저의 가치입니다!
사례 3: 네트워크 가로채기를 통한 API 데이터 수집
시나리오: HTML 파싱보다 안정적인 방식으로 XHR/Fetch 응답에서 직접 데이터를 추출합니다.
javascript
// JavaScript 버전
async function interceptAndCollect(page) {
const collectedData = [];
// ── 대상 API 응답 수신 대기 ──────────────────────────────────
page.on('response', async response => {
if (response.url().includes('/api/products') && response.status() === 200) {
try {
const json = await response.json();
if (json.data?.list) {
collectedData.push(...json.data.list);
console.log(`📦 ${collectedData.length}개의 상품 항목을 수집했습니다.`);
}
} catch (e) {}
}
});
// ── API 요청을 트리거하기 위해 상품 페이지 열기 ─────────────
await page.goto('https://example.com/products');
// ── 페이지네이션 로직 ──────────────────────────────────────
for (let i = 0; i < 5; i++) {
const nextBtn = page.getByRole('button', { name: '다음' });
if (!await nextBtn.isVisible()) break;
// 다음 클릭 및 데이터 응답 대기
await Promise.all([
page.waitForResponse(r => r.url().includes('/api/products')),
nextBtn.click()
]);
}
console.log(`✅ 총 ${collectedData.length}개의 항목 수집 완료`);
return collectedData;
}사례 4: 다계정 동시 실행 (병렬 처리)
시나리오: 여러 Mbbrowser 환경을 동시에 제어하여 작업 효율을 극대화합니다.
python
# Python 버전 —— 스레딩을 통한 병렬 처리
import threading
import requests
from playwright.sync_api import sync_playwright
API_URL = "http://127.0.0.1:8186"
SESSION_LIST = ["환경_ID_1", "환경_ID_2", "환경_ID_3", "환경_ID_4", "환경_ID_5"]
def operate_one_account(session_id, thread_id):
print(f"[Thread {thread_id}] {session_id[:8]} 시작 중...")
try:
resp = requests.post(f"{API_URL}/api/v1/browser/start", json={"Session_ID": session_id}, timeout=30)
data = resp.json()
if data["code"] != 0:
print(f"[Thread {thread_id}] ❌ 실패: {data['message']}")
return
ws = data["data"]["ws"]
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(ws)
context = browser.contexts[0]
page = context.pages[0] if context.pages else context.new_page()
# ── 비즈니스 로직 ──
page.goto("https://example.com")
print(f"[Thread {thread_id}] ✅ 완료: {page.title()}")
browser.close()
except Exception as e:
print(f"[Thread {thread_id}] ❌ 예외 발생: {e}")
finally:
requests.post(f"{API_URL}/api/v1/browser/stop", json={"Session_ID": session_id}, timeout=10)
if __name__ == "__main__":
threads = [threading.Thread(target=operate_one_account, args=(sid, i+1)) for i, sid in enumerate(SESSION_LIST)]
for t in threads: t.start()
for t in threads: t.join()
print("\n🎉 모든 계정 처리가 완료되었습니다!")IMPORTANT
병렬 실행 권장 사양:
- 16GB RAM → 동시에 10-15개 환경
- 32GB RAM → 동시에 20-30개 환경
사례 5: 운영급 프레임워크 (재시도 및 로깅)
python
# Python 운영급 프레임워크 예시
import threading
import requests
import logging
import time
from playwright.sync_api import sync_playwright, TimeoutError as PWTimeoutError
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(threadName)s] %(levelname)s %(message)s")
logger = logging.getLogger(__name__)
API_URL = "http://127.0.0.1:8186"
class MBPlaywrightSession:
def __init__(self, session_id: str, max_retry: int = 3):
self.session_id = session_id
self.max_retry = max_retry
self._pw = None
self._browser = None
def start(self):
for attempt in range(1, self.max_retry + 1):
try:
logger.info(f"[{self.session_id[:8]}] 시작 시도 (차수 {attempt})")
resp = requests.post(f"{API_URL}/api/v1/browser/start", json={"Session_ID": self.session_id}, timeout=30)
data = resp.json()
if data["code"] == 0:
self._pw = sync_playwright().start()
self._browser = self._pw.chromium.connect_over_cdp(data["data"]["ws"])
logger.info(f"[{self.session_id[:8]}] ✅ 준비 완료")
return self
except Exception as e:
logger.error(f"[{self.session_id[:8]}] 오류 발생: {e}")
time.sleep(2 ** attempt)
raise RuntimeError(f"환경 시작 실패: {self.session_id}")
@property
def page(self):
context = self._browser.contexts[0]
return context.pages[0] if context.pages else context.new_page()
def stop(self):
try:
if self._browser: self._browser.close()
if self._pw: self._pw.stop()
except Exception: pass
requests.post(f"{API_URL}/api/v1/browser/stop", json={"Session_ID": self.session_id}, timeout=10)
def __enter__(self): return self.start()
def __exit__(self, *args): self.stop()
# ── 사용 예시 ──
with MBPlaywrightSession("사용자_환경_ID_입력") as session:
try:
session.page.goto("https://www.mbbrowser.com")
logger.info(f"타이틀: {session.page.title()}")
except Exception as e:
logger.error(f"실행 오류: {e}")도구별 비교 요약
| 차원 | Puppeteer | Selenium | Playwright |
|---|---|---|---|
| Mbbrowser 필드 | data.ws | data.http | data.ws |
| 자동 대기 | 수동 | 수동 | 내장됨 |
| 네트워크 가로채기 | 기본 지원 | 지원 안 함 | 강력함 |
| 권장 사항 | JS 개발자 | 레거시 코드 | 신규 프로젝트 |
TIP
🎉 Mbbrowser + Playwright의 기초를 모두 마스터하셨습니다!
공식 문서는 playwright.dev를 방문하시고, 스크립트를 클라이언트 내에서 관리하려면 자동화 스크립트 관리자를 참조하십시오.
