Next.js 사이트 스크래핑 기법에 관한 이 튜토리얼에서 다음을 배울 수 있습니다:
- Next란 무엇이며 왜 인기 있는가
- React 하이드레이션 작동 방식 덕분에 Next.js 웹 페이지 스크래핑이 쉬운 이유
- 웹 스크래핑을 위해 React 하이드레이션 활용 방법
자, 시작해 보겠습니다!
Next.js란 무엇이며 어떻게 작동하나요?
Next.js는 서버 측 렌더링 및 정적 생성 웹사이트 구축을 위해 React 위에 구축된 자바스크립트 프레임워크입니다. 풍부한 API와 서버 측 React 애플리케이션 구축을 위한 체계적인 접근 방식을 제공하여 개발 프로세스를 간소화합니다.
Next.js는 지난 몇 년간 큰 인기를 얻어 Statista 기준 다섯 번째로 많이 사용되는 웹 라이브러리가 되었습니다. 이는 사용 편의성, 뛰어난 성능, React와의 유사성, 방대한 문서화, 커뮤니티 지원 덕분입니다. 많은 대기업과 스타트업이 웹 개발에 Next.js를 선택하는 것도 당연합니다.
Next.js는 서버에서 데이터를 가져와 React 컴포넌트에 전달하여 사전 렌더링된 HTML 문서를 생성하는 방식으로 작동합니다. 이 프로세스는 서버에서 HTML 콘텐츠를 생성하여 클라이언트에 전송함으로써 초기 페이지 로딩 속도를 향상시켜 성능을 높입니다.
웹 스크래핑을 위한 React Hydration 활용 방법
하이드레이션은 서버 측 렌더링과 클라이언트 측 렌더링 사이의 간극을 메웁니다. 구체적으로 Next.js 하이드레이션은 Next.js가 생성한 HTML 문서를 완전히 작동하는 클라이언트 측 React 애플리케이션으로 변환하는 과정입니다.
하이드레이션 과정에서는 — 브라우저가 서버에서 반환된 HTML 페이지를 로드한 후 —React가 페이지에 상호작용 기능을 추가합니다. 구체적으로, 서버에서 렌더링된 React 컴포넌트에 대응하는 DOM 노드에 이벤트 리스너를 연결하고 상태를 처리합니다.
React가 사전 렌더링된 페이지를 하이드레이션하는 데 필요한 단계는 다음과 같습니다:
- 초기 서버 렌더링: 서버가 페이지에 사용된 React 컴포넌트의 HTML 표현을 포함한 HTML 문서를 생성합니다.
- 클라이언트 측 JavaScript 실행: 클라이언트가 HTML 마크업을 수신하면 React 코드가 포함된 JavaScript 번들을 실행합니다.
- 조정(Reconciliation): React가 서버에서 반환된 HTML과 실시간으로 생성된 가상 DOM 표현을 비교합니다. 자세한 내용은 공식 문서를 참조하세요.
- 하이드레이션: 두 개가 동일하면 React는 이벤트 핸들러를 추가하고 상태를 처리하면서 기존 DOM을 최대한 재사용하여 렌더링을 완료합니다.
이 작업을 수행하기 위해 React는 서버가 HTML 문서를 생성하는 데 사용한 것과 동일한 데이터가 필요합니다. Next.js가 생성된 페이지에 props 데이터를 포함하는 특수 DOM 요소를 추가하는 이유가 바로 여기에 있습니다.
일부 Next.js 사이트에서는 __NEXT_DATA__ ID를 가진 <script> 요소에서 이 데이터를 찾을 수 있습니다. 이 특수 DOM 노드는 React가 하이드레이션에 사용하는 JSON 형식의 데이터를 다음과 같이 포함합니다:

새로운 App Router를 사용하는 최신 Next.js 사이트에서는 하이드레이션 데이터가 여러 <script> 노드 내 self.__next_f.push() 함수 호출에 저장됩니다:

이러한 노드에는 사이트에 표시되는 데이터보다 더 많은 정보가 포함될 수 있습니다. 어떻게 가능할까요? 해당 하이드레이션 요소들은 페이지 생성 시 서버에서 가져온 모든 API 및 데이터베이스 데이터를 React 컴포넌트에 전달하기 때문입니다. 다만 컴포넌트에서 실제로 접근하여 사용되는 해당 객체의 모든 속성은 아닐 수 있습니다.
이제 React가 작동하기 위해 해당 데이터가 왜 존재해야 하는지 이해했는지 여부는 중요하지 않습니다. 중요한 것은 Next.js를 통해 생성된 웹 페이지가 렌더링될 데이터를 JSON 형식으로 특수 DOM 노드 내에 포함한다는 점입니다. 상상할 수 있듯이, 이는 Nex.js 웹 스크래핑에 엄청난 영향을 미칩니다!
하이드레이션 데이터를 통한 Next.js 사이트 스크래핑
Next.js로 구축된 페이지에서 데이터를 추출하는 것은 스크래핑 스크립트조차 필요 없을 정도로 쉽습니다. 브라우저의 개발자 도구만으로도 충분합니다.
이제 React 하이드레이션을 활용해 Next.js 사이트를 몇 초 만에 스크래핑하는 방법을 알아봅시다!
__NEXT_DATA__에서 데이터 추출하기
스크래핑 대상 페이지가 Next.js로 구축되었는지 확인했다고 가정합니다(방법은 FAQ 질문에서 확인하세요).
이제 브라우저에서 해당 페이지를 방문한 후 마우스 오른쪽 버튼을 클릭하고 “검사”를 선택하여 개발자 도구를 엽니다. 콘솔 탭으로 이동한 후 원하는 <script> 요소를 선택하기 위해 아래 JavaScript 코드를 실행하세요:
const scriptNode = document.querySelector("#__NEXT_DATA__")
이 코드는 querySelector() 함수를 사용하여 DOM에서 ID가 __NEXT_DATA__인 요소를 선택하고 scriptNode 변수에 할당합니다.
콘솔에 scriptNode를 입력하고 Enter를 누르면 원하는 노드를 확인할 수 있습니다:

해당 노드의 내부 HTML 콘텐츠에접근하여JSON 콘텐츠로 파싱하려면 다음을사용하세요:
const jsonData = JSON.parse(scriptNode.innerHTML)
자, 이제 jsonData 객체에는 페이지에 컴포넌트를 렌더링하는 데 React가 사용한 모든 데이터가 포함됩니다:

자세히 살펴보면 props 내부의 pageProps 필드에 주목하세요:
jsonData.props.pageProps

다음으로 객체를 마우스 오른쪽 버튼으로 클릭하고 “객체 복사” 옵션을 선택하세요:

마지막으로 data.json 파일을 생성하고 원하는 내용을 붙여넣으세요!
훌륭합니다! 1분도 채 걸리지 않아 Next.js 사이트에서 웹 스크래핑을 수행하셨습니다.
모든 단계를 종합하면 다음과 같은 Next.js 스크래핑 스크립트를 얻을 수 있습니다:
const scriptNode = document.querySelector("#__NEXT_DATA__")
const jsonData = JSON.parse(scriptNode.innerHTML)
jsonData.props.pageProps
self.__next_f.push 함수에서 데이터 가져오기
Next.js 13에서는 App Router가 도입되었습니다. 이로 인해 Next.js가 React에 데이터를 전달하는 방식이 변경되었습니다. 이 경우 self.__next_f.push 문자열을 포함하는 모든 <script> 노드를 선택해야 합니다.
다시 브라우저에서 대상 페이지를 방문하여 콘솔로 이동합니다. 아래 명령어를 실행하여 <script> 노드를 선택합니다:
const scriptNodes = document.querySelectorAll("script")
querySelectorAll() 은 NodeList 객체를 반환합니다. Array.from() 으로 배열로 변환한 후 filter() 메서드를 적용하여 관심 있는 노드만 추출합니다:
const hydrationScriptNodes = Array.from(scriptNodes).filter((e) => e.innerHTML.includes("self.__next_f.push"))
이제 hydrationScriptNodes 에는 페이지의 모든 하이드레이션 <script> 요소가 포함됩니다:

그러나 일반적으로 initialTree 속성을 가진 노드만 필요할 것입니다. 관심 있는 모든 하이드레이션 데이터가 저장된 위치입니다:

다음과 같이 선택합니다:
const scriptNode = hydrationScriptNodes.find((e) => e.innerHTML.includes("initialTree"))
그런 다음 관심 있는 데이터를 추출합니다:
scriptNode.innerHTML
추출된 데이터에는 관심 정보가 포함되어 있지만 추가 파싱이 필요합니다. 몇 줄만 더 추가하면 더 읽기 쉬운 형식으로 변환할 수 있습니다.

이번 Next.js 스크래핑 스크립트는 다음과 같습니다:
const scriptNodes = document.querySelectorAll("script")
const hydrationScriptNodes = Array.from(scriptNodes).filter((e) => e.innerHTML.includes("self.__next_f.push"))
const scriptNode = hydrationScriptNodes.find((e) => e.innerHTML.includes("initialTree"))
scriptNode.innerHTML
축하합니다! Next.js 사이트 스크래핑이 이보다 쉬울 수 없습니다!
이 Next.js 스크래핑 방식의 한계점
React 하이드레이션 데이터를 기반으로 한 이 스크래핑 방식은 빠르고 효과적이지만 몇 가지 한계가 있습니다. 다음과 같습니다:
- 부분 데이터: Next.js가 추가한 특수
<script>노드에는 서버에서 가져온 데이터만 포함되어 있으며, 이는 하이드레이션 과정에서 React 컴포넌트로 전달됩니다. 이는 페이지에 포함된 전체 데이터가 아닐 수 있습니다. React 컴포넌트에는 하드코딩된 값이 있거나 AJAX를 통해 동적으로 다른 데이터를 가져올 수 있기 때문입니다. 이 경우 브라우저 자동화 도구를 사용한 웹 스크래핑을 수행해야 합니다. - 추가 파싱 필요:
self.__next_f.push는독점 형식의 데이터를 포함하며, 이를 정확히 파싱하는 것이 항상 쉬운 것은 아닙니다. - 수동 작업 필요: 위 스크립트를 JavaScript, Python 등 스크래핑 스크립트로 변환하고 데이터 내보내기 로직을 통합하지 않는 한, 데이터를 텍스트 파일로 수동으로 내보내야 합니다. 자세한 내용은 JavaScript 및 Node.js를 활용한 웹 스크래핑 가이드에서 확인하세요.
결론
이 글에서는 Next.js가 무엇인지, 왜 사이트 구축에 세계적으로 가장 널리 사용되는 기술 중 하나인지, 그리고 Next.js에서 데이터를 스크래핑하는 방법을 배웠습니다. 특히 React 하이드레이션에 의존하며 그로 인해 발생하는 사항을 이해하셨을 것입니다. 이로 인해 서버가 반환하는 HTML 페이지에는 필요한 모든 데이터가 이미 포함되어 있습니다(심지어 JSON 형식으로도!). 이 때문에 Next.js 사이트의 웹 스크래핑은 매우 쉽습니다.
진짜 문제는 다른 데 있습니다: 봇 방지 기술에 의해 차단되는 것입니다. 이러한 시스템은 자동화된 스크래핑 스크립트를 감지하고 차단할 수 있습니다. 다행히 Bright Data는 여러분을 위한 몇 가지 효과적인 솔루션을 제공합니다:
- 웹 스크레이퍼 IDE: 모든 차단을 자동으로 우회하고 회피할 수 있는 웹 스크레이퍼를 구축하는 클라우드 IDE.
- 웹 스크레이퍼 API: 99.99% 가동률과 무제한 확장성을 자랑하며, 구조화된 웹 데이터에 프로그래밍 방식으로 손쉽게 접근할 수 있습니다.
- 스크래핑 브라우저: CAPTCHA 처리, 브라우저 지문 인식, 자동 재시도 등을 처리하면서 JavaScript 렌더링 기능을 제공하는 클라우드 기반 제어 가능 브라우저입니다. Playwright 및 Puppeteer와 같은 가장 인기 있는 자동화 브라우저 라이브러리와 통합됩니다.
- 웹 언락커: 모든 페이지의 원시 HTML을 원활하게 반환하여 모든 스크래핑 방지 조치를 우회하는 언락킹 API입니다.
웹 스크래핑을 직접 다루고 싶지 않지만 온라인 데이터에는 관심이 있으신가요? Bright Data의 즉시 사용 가능한 데이터 세트를 살펴보세요!
FAQ
Next.js에서 DOM에서__NEXT_DATA__를숨기거나 제거할 수 있나요 ?
아니요, 제거하거나 숨길 수 없습니다. DOM에서 _NEXT_DATA_ <script> 요소를 제거하기로 결정하면 React가 하이드레이션(hydrate)을 수행할 수 없게 됩니다. 해당 스크립트의 데이터는 React가 정상적으로 작동하는 데 필요하므로, 일부 오작동이나 기능 저하를 예상하지 않고는 제거할 수 없습니다. 이 주제에 대한 GitHub 토론을 읽어보세요.
DOM에서self.__next_f.push 호출을제거할 수 있나요 ?
아니요, Next.js가 추가한 <script> 노드 내 self.__next_f.push 호출을 제거할 수 없습니다. 해당 DOM 요소는 클라이언트 측 React 애플리케이션이 예상대로 하이드레이션되고 작동할 수 있도록 서버에서 추가됩니다. 자세한 내용은 해당 주제에 대한 GitHub 토론을 확인하세요.
사이트가 Next.js로 구축되었는지 확인하는 방법은 무엇인가요?
사이트가 Next.js로 구축되었는지 확인하는 방법은 몇 가지 있습니다. 먼저, 일부 Next.js 버전에서 기본적으로 설정되는 X-Powered-By 헤더를 확인하세요:

그렇지 않다면 DOM에 <script id="__NEXT_DATA__" ... > 노드나 <script>self.__next_f.push(...)</script> 노드가 포함되어 있는지 확인하세요.
Next.js만이 React 하이드레이션에 의존하는 기술인가요?
아니요, Next.js만이 React 하이드레이션에 의존하는 기술은 아닙니다. Gatsby와 같은 다른 서버 측 렌더링(SSR) 생성기들도 서버에서 렌더링된 HTML을 클라이언트 측에서 상호작용 가능한 React 애플리케이션으로 변환하기 위해 React 하이드레이션을 활용합니다. 이 과정은 React를 사용한 SSR에서 흔히 사용되는 접근 방식이며 Next.js에만 국한되지 않습니다.