최근 개발자 커뮤니티(QnA 게시판 등)에서 빈번히 묻는 질문 중 하나가 있습니다. Python으로 특정 웹페이지를 스크래핑할 때 결과가 불완전하거나 아예 HTML 구조만 출력되는 현상에 대한 것입니다. 이러한 문제가 발생하는 근본 원인은 동적 웹페이지 데이터와 관련이 있습니다.
동적 웹페이지란 페이지 로드 시점에 모든 데이터가 HTML 태그에 포함되어 있지 않은 형태를 말합니다. 대신 서버가 데이터를 별도로 전송하고, 클라이언트 측 JavaScript가 이를 동적으로 DOM에 삽입하는 방식입니다. 이러한 데이터를 수집하려면 크게 두 가지 접근 방식을 사용할 수 있습니다.
방법 1: AJAX 요청 URL 추출하기
실제 댓글 정보를 수집해야 하는 상황을 가정해 봅니다. 이 데이터는 AJAX 기술을 활용하므로, 일반적인 requests나 urllib 모듈로 직접 접근할 경우 원하는 정보를 얻을 수 없습니다.
브라우저의 개발자 도구(Network → XHR 또는 js 탭)에서 실제 데이터 요청 URL을 찾을 수 있습니다. 해당 URL을 파악한 후 직접 접근하여 JSON 데이터를 파싱하면 됩니다.
구현 예시 코드:
import requests
import json
target_url = 'https://www.zhihu.com/api/v4/zvideos/1501903286600495105/root_comments'
request_headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36'
}
query_params = {
'order': 'normal',
'limit': 20,
'offset': 0,
'status': 'open'
}
response = requests.get(url=target_url, headers=request_headers, params=query_params)
parsed_data = json.loads(response.text)
comment_items = parsed_data['data']
for item in comment_items:
print(item['content'])
실행 결과:
참고사항:大多数 댓글 시스템은 페이지네이션을 사용하므로, 전체 데이터를 얻으려면 유사한 구조의 추가 요청 URL을 탐색해야 합니다.
방법 2: Selenium 모듈 활용하기
Selenium은 실제 브라우저 환경을 완벽히 시뮬레이션합니다. 따라서 AJAX로 렌더링되는 콘텐츠도 정상적으로 수집 가능합니다.
구현 예시 코드:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
import time
target_url = 'https://www.zhihu.com/zvideo/1501903286600495105'
chrome_options = Options()
chrome_options.add_argument('--headless')
driver = webdriver.Chrome(options=chrome_options)
driver.get(url=target_url)
time.sleep(15)
comment_elements = driver.find_elements(
By.XPATH,
"//div[@class='CommentListV2']/ul/li[@class!='NestComment--child']//*[contains(@class,'ztext')]"
)
for element in comment_elements:
print(element.text)
driver.quit()
실행 결과:
비교 분석:두 방식 모두 유사한 데이터셋을 반환합니다. AJAX URL 추출 방식은速度快, 자원 소모가 적지만 요청 구조 파악에 시간이 필요합니다. Selenium 방식은 구현이 단순하지만 브라우저 실행 오버헤드가 발생합니다. 수집 목적과 환경에 따라 적절한 방식을 선택하시기 바랍니다.