동적 웹사이트 스크래핑

동적 웹사이트는 초기 페이지 로드 후 JavaScript를 사용하여 콘텐츠를 로드합니다. 이 가이드에서는 FourA의 브라우저 endpoint를 사용하여 이러한 사이트에서 데이터를 수집하는 방법을 설명합니다.

문제점

JavaScript를 많이 사용하는 웹사이트에 표준 HTTP request를 보내면, 실제 콘텐츠가 아닌 HTML 셸만 받게 됩니다. 필요한 데이터(제품 목록, 가격, 검색 결과)는 브라우저에서 페이지가 렌더링된 후 JavaScript에 의해 로드됩니다.

이는 React, Vue, Angular, Next.js와 같은 최신 프레임워크에서 점점 더 흔해지고 있습니다.

해결책: 브라우저 request

FourA의 브라우저 endpoint(POST /api/browser/)는 다음과 같이 동작하는 Chrome 브라우저 인스턴스에서 URL을 엽니다.

  1. 페이지 로드
  2. 모든 JavaScript 실행
  3. 콘텐츠가 렌더링될 때까지 대기
  4. 완전히 렌더링된 HTML 반환

1단계: 필요한 항목 식별

request를 보내기 전에 브라우저에서 대상 페이지를 방문하고 DevTools(F12)를 사용하여 콘텐츠가 로드되었음을 확인하는 텍스트나 요소를 찾으십시오. 예:

  • JS 렌더링 후 나타나는 제품 이름
  • 렌더링된 HTML의 product-grid와 같은 CSS 클래스
  • 데이터가 로드될 때만 나타나는 "results"와 같은 텍스트 문자열

2단계: 브라우저 request 전송

curl -X POST https://eu.api.foura.ai/api/browser/ \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/products",
    "timeout_ms": 15000,
    "checkText": "product-grid"
  }'

checkText 옵션은 렌더링된 페이지에 "product-grid" 문자열이 나타나는지 확인하도록 FourA에 지시합니다. 타임아웃 전에 나타나지 않으면 요청이 실패하여 콘텐츠가 로드되지 않았음을 알려줍니다.

3단계: HTML 파싱

응답의 body 필드에는 완전히 렌더링된 HTML이 포함되어 있습니다. 선호하는 라이브러리를 사용하여 파싱하세요:

Python(BeautifulSoup)

import requests
from bs4 import BeautifulSoup

resp = requests.post("https://eu.api.foura.ai/api/browser/", headers={
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json"
}, json={
    "url": "https://example.com/products",
    "timeout_ms": 15000,
    "checkText": "product-grid"
})

html = resp.json()["body"]
soup = BeautifulSoup(html, "html.parser")

for product in soup.select(".product-card"):
    name = product.select_one(".product-name").text.strip()
    price = product.select_one(".product-price").text.strip()
    print(f"{name}: {price}")

Node.js (cheerio)

import * as cheerio from 'cheerio';

const resp = await fetch('https://eu.api.foura.ai/api/browser/', {
  method: 'POST',
  headers: { 'X-API-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json' },
  body: JSON.stringify({
    url: 'https://example.com/products',
    timeout_ms: 15000,
    checkText: 'product-grid'
  })
});

const { body: html } = await resp.json();
const $ = cheerio.load(html);

$('.product-card').each((i, el) => {
  console.log($(el).find('.product-name').text(), $(el).find('.product-price').text());
});

문제 해결

여전히 빈 콘텐츠가 표시되나요?

  • 페이지가 실제로 JavaScript 렌더링을 사용하는지 확인합니다("페이지 소스 보기"와 DevTools 비교).
  • timeout_ms을 늘립니다. 일부 페이지는 로드 속도가 느릴 수 있습니다.
  • 페이지에 인증이나 cookie가 필요한지 확인합니다(cookies 파라미터 사용).

CAPTCHA 페이지가 표시되나요?

  • 단일/HTTP request의 경우, 자동 IP 로테이션을 위해 proxy endpoint(POST /api/proxy/)로 전환하세요.
  • browser request를 proxy를 통해 라우팅하려면 browser endpoint의 proxy 파라미터를 전달하세요. proxy endpoint는 단일/HTTP request만 래핑하며 browser request는 처리하지 않습니다.

proxy 파라미터는 이전 response에서 반환된 불투명한 proxy ID를 사용하며, 사용자 고유의 proxy 주소는 사용하지 않습니다. 먼저 POST /api/proxy/(또는 POST /api/auto/) 호출을 한 번 실행하고, 반환되는 proxy 필드를 읽은 다음 이를 고정하세요:

# Step 1: let FourA find a working exit. The response carries "proxy": "A1B2C3".
curl -X POST "https://eu.api.foura.ai/api/proxy/" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"maxTries": 5, "request": {"method": "GET", "url": "https://example.com/products"}}'

# Step 2: render through that same exit.
curl -X POST "https://eu.api.foura.ai/api/browser/" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/products", "proxy": "A1B2C3", "timeout_ms": 20000}'

ID 대신 주소를 전송하면 400 Invalid proxy format(으)로 반환됩니다. 전체 패턴은 여러 요청에서 Proxy 재사용하기에 있습니다.

다음 단계

최근 업데이트: 2026년 8월 12일