Scarnox · Blog

JavaScript로 렌더링되는 웹사이트를 스크래핑하는 방법

많은 최신 사이트는 거의 빈 HTML 문서를 보내고, 콘텐츠는 JavaScript로 브라우저에서 만듭니다. 스크래퍼가 페이지를 가져왔는데 상품도, 가격도, 기사 본문도 없다면, 콘텐츠는 있지만 나중에 도착하는 것입니다. 이 가이드는 어떤 종류의 페이지인지 판단하는 방법, 가능하다면 브라우저보다 빠른 경로를 찾는 방법, 그리고 Python에서 Playwright로 렌더링된 페이지를 스크래핑하는 방법을 보여 줍니다. 마지막에는 렌더링된 페이지에 captcha가 나타날 때 무엇을 해야 하는지 짧게 다룹니다.

1단계: 콘텐츠가 HTML에 있는지 확인하기

브라우저에서 view-source:로 페이지를 열거나 일반 HTTP 요청으로 가져온 뒤, 화면에 보이는 텍스트 한 조각을 소스에서 검색하세요. 흔한 결과는 세 가지입니다.

2단계: JSON 엔드포인트가 있으면 호출하기

페이지가 데이터를 엔드포인트에서 가져온다면, 그 엔드포인트를 직접 호출하는 것이 보통 가장 좋은 선택입니다. 렌더링된 페이지보다 작고, 빠르고, 안정적입니다. 요청 URL을 복사하고, 사이트가 요구하는 헤더를 확인하고, 스크립트에서 시도해 보세요. 사이트 이용 약관이 허용하는 경우에만 하고, 사이트가 기대하는 속도 제한이나 인증은 존중하세요. 문서화되지 않은 엔드포인트는 예고 없이 바뀔 수 있으므로, 응답 구조가 바뀌면 파서가 큰 소리로 실패하도록 작성하세요.

3단계: 꼭 필요하면 페이지 렌더링하기

콘텐츠가 정말로 브라우저를 필요로 한다면, 헤드리스 브라우저를 구동하세요. Python에서는 Playwright가 좋은 선택입니다. 아래 예시는 상품 목록을 열고, 콘텐츠가 나타나기를 기다린 뒤, 각 카드의 텍스트를 읽습니다.

from playwright.sync_api import sync_playwright

URL = "https://example.com/products"  # 스크래핑이 허용된 페이지

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    page = browser.new_page()
    page.goto(URL, wait_until="domcontentloaded", timeout=60_000)
    # 데이터가 도착했음을 증명하는 요소를 기다립니다.
    page.wait_for_selector(".product-card", timeout=30_000)
    titles = page.locator(".product-card h2").all_inner_texts()
    browser.close()

for title in titles:
    print(title)

특정 셀렉터를 기다리는 것이 고정된 sleep보다 훨씬 믿을 만합니다. 고정된 일시 정지는 느린 날에는 너무 짧고, 빠른 날에는 시간을 낭비합니다. 데이터가 로드된 뒤에만 나타나는 요소를 고르세요.

4단계: 무한 스크롤과 페이지네이션 처리하기

일부 페이지는 스크롤할 때마다 항목을 더 불러옵니다. 맨 아래로 스크롤하고, 항목 수가 늘어나기를 기다리고, 더 늘어나지 않으면 멈추세요. 번호가 매겨진 페이지네이션은 더 단순합니다. 다음 페이지 링크를 찾아 따라가고, 마지막 페이지에서 멈추세요. 항상 최대 페이지 수나 스크롤 횟수를 정해 두세요. 그래야 버그가 크롤러를 영원히 돌리지 못합니다.

def scroll_until_done(page, selector: str, max_rounds: int = 20) -> int:
    previous = -1
    for _ in range(max_rounds):
        count = page.locator(selector).count()
        if count == previous:
            break
        previous = count
        page.mouse.wheel(0, 4000)
        page.wait_for_timeout(1500)  # 다음 묶음이 로드될 시간을 줍니다
    return previous

5단계: 브라우저를 효율적으로 쓰기

렌더링은 비쌉니다. 필요 없는 이미지, 폰트, 미디어는 차단하고, 페이지마다 새 브라우저를 띄우지 말고 한 브라우저를 여러 페이지에 재사용하세요. 작업이 끝나면 페이지와 컨텍스트를 닫아서, 오래 실행되는 동안 메모리가 계속 늘지 않게 하세요.

def block_heavy_assets(route):
    if route.request.resource_type in ("image", "font", "media"):
        route.abort()
    else:
        route.continue_()

page.route("**/*", block_heavy_assets)

6단계: 렌더링된 페이지에 captcha가 나타날 때

렌더링된 페이지가 콘텐츠를 보여 주기 전에 captcha를 띄우기도 합니다. 그 captcha가 Scarnox에서 실시간으로 제공되는 captcha 유형인 PopularCaptcha라면, 페이지에서 sitekey를 읽고, 토큰을 요청하고, 사이트가 기대하는 폼 필드에 토큰을 넣으세요. PopularCaptcha Python 가이드가 그 단계를 따라갑니다. 다른 위젯은 아직 실시간이 아니므로, 계획을 세우기 전에 captcha 유형 설명을 확인하세요.

브라우저 자체에도 주의하세요. 명확하게 자동화된 것으로 보이는 헤드리스 브라우저는 검사를 줄이는 것이 아니라 늘릴 수 있습니다. 살펴볼 신호는 헤드리스 브라우저 감지를 읽고, 더 느리게, 더 적은 횟수로 페이지를 로드하세요.

책임 있게 스크래핑하기

다음 단계

무료 체험 크레딧으로 카드 없이 시작하세요. 계정을 만들고 직접 소유한 페이지에서 PopularCaptcha 흐름을 테스트해 보세요. 현재 요금은 요금 페이지에서 확인할 수 있습니다.