페이지 매김 및 동적 콘텐츠 처리
다음 페이지 링크를 따라가고 Playwright로 JavaScript로 렌더링된 페이지를 처리합니다.
페이지 매김 및 동적 콘텐츠 처리은(는) CoddyKit의 무료 AI Agents 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 AI Agents 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. AI Agents 강의에는 총 4개의 강의가 포함되어 있습니다.
페이지네이션 문제
대부분의 실제 웹사이트는 모든 데이터를 한 페이지에 제공하지 않습니다. 서버 부하를 줄이기 위해 결과를 여러 페이지로 나눕니다. 에이전트는 전체 데이터세트를 수집하려면 페이지네이션을 감지하고 따라가야 합니다.
페이지네이션에는 일반적으로 다음 페이지 링크와 페이지 번호 주소 패턴이라는 두 가지 방식이 사용됩니다.
다음 페이지 링크 감지
많은 사이트에는 '다음' 버튼이나 화살표 링크가 있습니다. rel='next' 속성이 있는 앵커 태그나 '다음'과 같은 텍스트가 있는 앵커 태그를 찾고, 그 href를 추출한 다음, 더 이상 존재하지 않을 때까지 반복해서 따라가세요.
from bs4 import BeautifulSoup
import httpx
def scrape_all_pages(start_url: str) -> list:
results = []
url = start_url
while url:
response = httpx.get(url, timeout=10.0)
soup = BeautifulSoup(response.text, 'html.parser')
# Collect data from this page
for item in soup.select('.result-item'):
results.append(item.text.strip())
# Find the next page link
next_link = soup.find('a', rel='next') or soup.find('a', string='Next')
url = next_link.get('href') if next_link else None
return results페이지 번호 주소 패턴
많은 응용 프로그램 인터페이스와 사이트는 예측 가능한 주소 패턴을 사용합니다. 예를 들어 /results?page=1, /results?page=2와 같은 형식입니다. 에이전트는 다음 링크를 찾기 위해 DOM을 파싱하지 않고도 이러한 주소를 직접 순회할 수 있습니다.
import httpx
def scrape_paginated_api(base_url: str, max_pages: int = 10) -> list:
all_items = []
for page in range(1, max_pages + 1):
response = httpx.get(
base_url,
params={'page': page, 'per_page': 50},
timeout=10.0
)
response.raise_for_status()
data = response.json()
items = data.get('results', [])
if not items:
break # No more data
all_items.extend(items)
print(f'Page {page}: fetched {len(items)} items')
return all_items커서 기반 페이지네이션
최신 응용 프로그램 인터페이스인 GitHub, Slack, Twitter는 커서 기반 페이지네이션을 사용합니다. 각 응답에는 다음 페이지를 위한 커서 토큰이 포함됩니다. 커서가 없거나 null이 될 때까지 다음 요청에 커서를 전달하세요.
import httpx
def fetch_with_cursor(url: str, headers: dict) -> list:
all_data = []
cursor = None
while True:
params = {'cursor': cursor} if cursor else {}
response = httpx.get(url, headers=headers, params=params, timeout=10.0)
response.raise_for_status()
data = response.json()
all_data.extend(data.get('items', []))
cursor = data.get('next_cursor') # None when done
if not cursor:
break
return all_data정적 콘텐츠와 동적 콘텐츠
일부 페이지는 초기 HTML이 전달된 후 JavaScript를 통해 콘텐츠를 로드합니다. 일반 웹 요청 클라이언트는 빈 틀만 받으며, 실제 데이터는 브라우저에서 JS가 주입합니다.
이러한 페이지에서는 플레이라이트와 같은 도구가 실제 브라우저 엔진을 실행하고, 콘텐츠를 추출하기 전에 JavaScript가 실행될 때까지 기다립니다.
플레이라이트 설치 및 가져오기
pip install playwright로 플레이라이트를 설치한 다음 playwright install chromium을 실행해 브라우저를 다운로드하세요. 비동기 에이전트 작업 흐름에는 async_playwright()를 사용하세요.
# Installation (run in terminal):
# pip install playwright
# playwright install chromium
from playwright.async_api import async_playwright
import asyncio
async def fetch_dynamic(url: str) -> str:
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
page = await browser.new_page()
await page.goto(url)
html = await page.content() # Full rendered HTML
await browser.close()
return html
# html = asyncio.run(fetch_dynamic('https://example.com'))동적 콘텐츠 로드 대기
JavaScript 페이지는 데이터를 비동기적으로 로드하는 경우가 많습니다. 콘텐츠를 추출하기 전에 특정 요소가 나타날 때까지 기다리도록 플레이라이트에 지시하세요. 그러면 필요한 데이터가 실제로 DOM에 존재하는지 확인할 수 있습니다.
from playwright.async_api import async_playwright
async def scrape_dynamic_table(url: str) -> list:
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
page = await browser.new_page()
await page.goto(url)
# Wait for the table to appear in the DOM
await page.wait_for_selector('table.results', timeout=10000)
html = await page.content()
await browser.close()
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
return [td.text for td in soup.select('table.results td')]페이지 클릭 및 상호 작용
플레이라이트는 클릭, 양식 입력, 스크롤, 키보드 입력과 같은 사용자 상호 작용을 시뮬레이션할 수 있습니다. 따라서 에이전트가 로그인 과정, 드롭다운 또는 무한 스크롤 페이지를 탐색할 수 있습니다.
from playwright.async_api import async_playwright
async def click_load_more(url: str) -> str:
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
page = await browser.new_page()
await page.goto(url)
# Click the 'Load More' button
load_more = page.locator('button:text("Load More")')
if await load_more.count() > 0:
await load_more.click()
await page.wait_for_timeout(2000) # wait 2s for content
html = await page.content()
await browser.close()
return html무한 스크롤 처리
일부 사이트는 아래로 스크롤할 때 더 많은 콘텐츠를 로드합니다. 플레이라이트는 이러한 로드를 트리거하도록 스크롤을 시뮬레이션할 수 있습니다. 반복해서 스크롤하고 매번 새로운 콘텐츠가 나타났는지 확인하세요.
from playwright.async_api import async_playwright
async def scrape_infinite_scroll(url: str, scroll_count: int = 5) -> str:
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
page = await browser.new_page()
await page.goto(url)
for _ in range(scroll_count):
await page.evaluate('window.scrollTo(0, document.body.scrollHeight)')
await page.wait_for_timeout(1500) # wait for new content
html = await page.content()
await browser.close()
return html플레이라이트와 BeautifulSoup 결합
플레이라이트가 페이지를 렌더링하고 전체 HTML을 반환하면, 쉽게 추출할 수 있도록 BeautifulSoup에 전달하세요. 이렇게 하면 두 라이브러리의 장점을 결합할 수 있습니다.
from playwright.async_api import async_playwright
from bs4 import BeautifulSoup
async def extract_js_rendered_data(url: str) -> list:
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
page = await browser.new_page()
await page.goto(url)
await page.wait_for_selector('.product-card')
html = await page.content()
await browser.close()
soup = BeautifulSoup(html, 'html.parser')
products = []
for card in soup.select('.product-card'):
products.append({
'name': card.select_one('.name').text.strip(),
'price': card.select_one('.price').text.strip()
})
return products적절한 도구 선택
모든 페이지에 플레이라이트가 필요한 것은 아닙니다. 작동하는 가장 간단한 방법을 사용하세요.
- 정적 HTML: 웹 요청 도구 + BeautifulSoup(빠르고 브라우저 오버헤드 없음)
- 페이지네이션이 적용된 구조화된 데이터 인터페이스: 페이지 또는 커서 매개변수를 사용하는 웹 요청 도구
- JS로 렌더링된 콘텐츠: 플레이라이트 비동기 방식(더 느리지만 더 강력함)
항상 정적인 방법부터 시작하고, 필요한 경우에만 플레이라이트를 사용하세요.
지식 확인: 페이지네이션과 동적 콘텐츠
페이지네이션 및 동적 콘텐츠 처리에 대한 이해도를 확인해 보세요.
복습: 페이지네이션과 동적 콘텐츠
이제 에이전트가 웹 콘텐츠의 전체 범위를 처리할 수 있습니다.
- 다음 페이지 링크를 따라가거나 주소의 페이지 매개변수를 순회하기
- 최신 응용 프로그램 인터페이스의 페이지네이션에 커서 토큰 사용하기
- JavaScript로 렌더링된 페이지에는
async_playwright()사용하기 page.wait_for_selector()로 요소가 나타날 때까지 기다리기- 쉽게 추출할 수 있도록 플레이라이트와 BeautifulSoup 결합하기
항상 가장 간단한 방법부터 시작하고, 정적인 방법으로 충분하지 않을 때만 플레이라이트로 확장하세요.
자주 묻는 질문
“페이지 매김 및 동적 콘텐츠 처리” 강의는 무료인가요?
네 — “페이지 매김 및 동적 콘텐츠 처리” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 AI Agents 강의 전체를 잠금 해제할 수 있습니다. AI Agents 강의에는 총 4개의 강의가 포함되어 있습니다.
“페이지 매김 및 동적 콘텐츠 처리”에서 뭘 배우나요?
다음 페이지 링크를 따라가고 Playwright로 JavaScript로 렌더링된 페이지를 처리합니다. 브라우저에서 직접 실행하는 실습 코드로 AI Agents을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
AI Agents을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 AI Agents은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.
“페이지 매김 및 동적 콘텐츠 처리” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 AI Agents 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 AI Agents 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.