> 웹 프론트엔드 > JS 튜토리얼 > 무한 스크롤이 있는 페이지에서 데이터를 긁어내는 방법

무한 스크롤이 있는 페이지에서 데이터를 긁어내는 방법

Mary-Kate Olsen
풀어 주다: 2025-01-03 12:41:08
원래의
799명이 탐색했습니다.

더 많은 콘텐츠를 표시하려면 '버튼 클릭'과 같은 작업이 필요한 웹페이지를 본 적이 있나요? 이러한 페이지는 사용자 상호 작용을 기반으로 더 많은 콘텐츠를 로드하므로 '동적 웹페이지'라고 합니다. 이와 대조적으로 정적 웹페이지는 사용자 작업 없이도 모든 콘텐츠를 한 번에 표시합니다.

추가 숨겨진 콘텐츠에 액세스하기 위해 버튼을 클릭하는 등의 사용자 상호 작용을 시뮬레이션해야 하기 때문에 동적 페이지에서 콘텐츠를 스크랩하는 것은 어려울 수 있습니다. 이 튜토리얼에서는 "더 보기" 버튼을 통해 무한 스크롤하여 웹페이지에서 데이터를 스크랩하는 방법을 배웁니다.

전제조건

이 튜토리얼을 진행하려면 다음이 필요합니다.

  • Node.js: 최신 버전보다 안정적인 "LTS"(Long Time Support) 버전을 설치하세요.
  • Npm: 패키지를 설치하는 데 사용되는 패키지 관리자입니다. 좋은 소식은 Node.js와 함께 "npm"이 자동으로 설치되어 작업 속도가 훨씬 빨라진다는 것입니다.
  • Cheerio: HTML 파싱용
  • Puppeteer: 헤드리스 브라우저를 제어하는 ​​데 사용됩니다.
  • 스크레이퍼 구축을 위한 IDE: Visual Studio Code와 같은 모든 코드 편집기를 얻을 수 있습니다.

또한 HTML, CSS, JavaScript에 대한 기본적인 이해가 필요합니다. Chrome과 같은 웹 브라우저도 필요합니다.

프로젝트 초기화

새 폴더를 만든 다음 코드 편집기에서 엽니다. 코드 편집기에서 "터미널" 탭을 찾아 새 터미널을 엽니다. Visual Studio Code를 사용하여 이를 발견하는 방법은 다음과 같습니다.

How to Scrape Data from a Page with Infinite Scroll

다음으로 터미널에서 다음 명령을 실행하여 이 빌드에 필요한 패키지를 설치합니다.

$ npm install cheerio puppeteer
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

코드 편집기에서 프로젝트 폴더 안에 새 파일을 만들고 이름을 DynamicScraper.js로 지정하세요.

훌륭해요, 친구!

페이지 콘텐츠에 액세스하기

Puppeteer는 헤드리스 Chrome 브라우저를 제어할 수 있는 강력한 Node.js 라이브러리로, 웹페이지와 상호작용하는 데 이상적입니다. Puppeteer를 사용하면 URL을 사용하여 웹페이지를 타겟팅하고 콘텐츠에 액세스하며 해당 페이지에서 쉽게 데이터를 추출할 수 있습니다.

이 섹션에서는 헤드리스 브라우저를 사용하여 페이지를 열고, 콘텐츠에 액세스하고, 해당 페이지의 HTML 콘텐츠를 검색하는 방법을 알아봅니다. 이 튜토리얼의 대상 웹사이트는 여기에서 찾을 수 있습니다.

참고: DynamicScraper.js 내부에 모든 코드를 작성해야 합니다.

핵심 모듈, 타사 라이브러리(예: Puppeteer) 또는 사용자 정의 모듈(예: 로컬 JS 파일)을 로드하는 데 도움이 되는 require() Node.js 내장 함수를 사용하여 Puppeteer를 가져오는 것부터 시작하세요.

$ npm install cheerio puppeteer
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

다음으로 타겟 URL을 저장하기 위한 변수를 정의합니다. 이렇게 하는 것이 필수는 아니지만 코드의 어느 곳에서나 이 전역 변수를 참조하면 되므로 코드가 더 깔끔해집니다.

const puppeteer = require('puppeteer');
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

다음 단계는 헤드리스 브라우저를 시작하고 대상 페이지의 HTML 콘텐츠를 검색하는 기능을 만드는 것입니다. 작업 속도를 훨씬 높이려면 즉시 호출 함수 표현식(IIFE) 방법을 선택해야 합니다.

try-and-catch 블록을 사용하여 비동기 IIFE 정의:

const url = 'https://www.scrapingcourse.com/button-click';
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

참고: 이 튜토리얼 세그먼트의 다른 모든 코드는 try 블록 안에 작성해야 합니다.

IIFE 내에서 바로 Puppeteer의 새 인스턴스를 만들고 상호 작용을 위한 새 페이지를 엽니다.

launch 메소드를 사용하여 puppeteer 라이브러리의 새 인스턴스를 시작하고 헤드리스 모드를 전달합니다. 헤드리스 모드는 true 또는 false로 설정할 수 있습니다. 헤드리스 모드를 true로 설정하면 인형 조종자가 시작될 때 헤드리스 브라우저가 표시되지 않지만 false로 설정하면 브라우저가 표시됩니다.

Puppeteer를 시작한 후 헤드리스 브라우저에서 새 탭 열기를 트리거하는 newPage 메서드도 호출하려고 합니다.

(async () => {
    try {
        // Code goes here
    } catch (error) {
        console.error('Error:', error.message);
    }
})();
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

이제 newPage 메소드를 쿼리하여 예상 URL을 타겟팅하고 page.goto 메소드를 사용하여 이 새 탭에서 해당 웹사이트를 엽니다. 그 외에도 Puppeteer는 페이지가 모든 필수 리소스(예: 이미지 및 JS)를 로드한 경우에만 페이지가 상호 작용 및 데이터 추출이 가능한 것으로 간주하도록 하고 싶습니다.

페이지가 준비되었는지 확인하기 위해 Puppeteer는 페이지 로드를 위한 다양한 조건을 정의하는 다양한 값을 사용할 수 있는 waitUntil이라는 옵션을 제공합니다.

  • load: HTML 문서와 해당 리소스(예: 이미지, CSS, JS)가 로드된 후에 발생하는 로드 이벤트가 실행될 때까지 기다립니다. 그러나 이는 로드 이벤트 후에 로드되는 추가 JavaScript 렌더링 콘텐츠를 고려하지 않을 수 있습니다.

  • domcontentloaded: 초기 HTML이 구문 분석되면 트리거되는 DOMContentLoaded 이벤트를 기다립니다. 하지만 이는 외부 리소스(예: 이미지 또는 추가 JS)가 로드되기 전에 로드됩니다.

  • networkidle2: 활성 네트워크 요청(진행 중인 HTTP 요청(예: 이미지, 스크립트 또는 기타 리소스 로드))이 2개 이하일 때까지 500밀리초 동안 기다립니다. 이 값은 작고 지속적인 요청을 보내지만 주요 콘텐츠에는 영향을 주지 않는 페이지를 처리할 때 선호됩니다.

// Launch Puppeteer
const browser = await puppeteer.launch({ headless: false }); // Headless mode
const page = await browser.newPage(); // Open a new page
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

마지막으로 page.content()를 사용하여 현재 페이지의 모든 HTML 콘텐츠를 검색하면 됩니다. 가장 중요한 점은 시스템 속도를 저하시킬 수 있는 불필요한 메모리 사용을 방지하기 위해 브라우저 인스턴스를 닫아야 한다는 것입니다. 브라우저를 닫으려면 스크립트 끝에 browser.close()를 사용하세요.

$ npm install cheerio puppeteer
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

현재 코드를 사용하면 브라우저가 매우 빠르게 로드되고 닫혀 페이지가 제대로 표시되지 않을 수도 있습니다. 이 경우 page.waitForTimeout 메소드를 사용하여 몇 초 동안 브라우저를 지연시킬 수 있습니다. 이 메소드는 browser.close 메소드 바로 앞에 와야 합니다.

const puppeteer = require('puppeteer');
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

이 섹션의 전체 코드는 다음과 같습니다.

const url = 'https://www.scrapingcourse.com/button-click';
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

파일을 저장하고 아래 명령을 사용하여 터미널 내부에서 스크립트를 실행하세요.

(async () => {
    try {
        // Code goes here
    } catch (error) {
        console.error('Error:', error.message);
    }
})();
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

스크립트는 아래와 같은 헤드리스 브라우저를 엽니다.

How to Scrape Data from a Page with Infinite Scroll

브라우저가 로드되고 Puppeteer는 전체 HTML 콘텐츠를 가져오며 콘솔은 해당 콘텐츠를 터미널에 기록합니다.

다음은 터미널에서 얻어야 하는 출력입니다.

// Launch Puppeteer
const browser = await puppeteer.launch({ headless: false }); // Headless mode
const page = await browser.newPage(); // Open a new page
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

다음으로 클릭을 시뮬레이션하기 위해 루프를 실행하려고 합니다. 시뮬레이션에서는 i번 실행되는 for 루프를 사용하며, 여기서 i는 클릭수 변수가 됩니다.

// Navigate to the target URL
await page.goto(url, {
    waitUntil: 'networkidle2', // Ensure the page is fully loaded
});
로그인 후 복사
로그인 후 복사

참고: 이 섹션의 나머지 코드는 for 루프의 try 블록 내부에 작성되어야 합니다.

출력 디버깅 및 추적에 도움을 받으려면 현재 클릭 시도를 로그아웃하세요.

// Get the full HTML content of the page
const html = await page.content();

// Log the entire HTML content
console.log(html);

// Close the browser
await browser.close();
로그인 후 복사
로그인 후 복사

다음으로 '더 보기' 버튼을 찾아서 세 번 이상 클릭할 수 있어야 합니다. 하지만 클릭을 시뮬레이션하기 전에 '더 보기' 버튼을 사용할 수 있는지 확인해야 합니다.

Puppeteer는 요소를 사용하기 전에 요소의 가시성을 확인할 수 있는 waitForSelector() 메서드를 제공합니다.

'더 보기' 버튼의 경우 먼저 ID 선택기 값을 사용하여 찾은 후 다음과 같이 공개 상태를 확인해야 합니다.

// Delay for 10 seconds to allow you to see the browser
await page.waitForTimeout(10000);
로그인 후 복사
로그인 후 복사

이제 "더 보기" 버튼을 사용할 수 있다는 것을 알았으므로 Puppeteer click() 메소드를 사용하여 클릭할 수 있습니다.

const puppeteer = require('puppeteer');

const url = 'https://www.scrapingcourse.com/button-click';

(async () => {
    try {
        // Launch Puppeteer
        const browser = await puppeteer.launch({ headless: false }); // Headless mode
        const page = await browser.newPage(); // Open a new page

        // Navigate to the target URL
        await page.goto(url, {
            waitUntil: 'networkidle2', // Ensure the page is fully loaded
        });

        // Get the entire HTML content of the page
        const html = await page.content();

        // Log the entire HTML content
        console.log(html);

        // Delay for 10 seconds to allow you to see the browser
        await page.waitForTimeout(10000);

        // Close the browser
        await browser.close();
    } catch (error) {
        console.error('Error fetching the page:', error.message);
    }
})();
로그인 후 복사
로그인 후 복사

'더 보기' 버튼 클릭을 시뮬레이션한 후에는 데이터가 서버 요청에 따라 달라질 수 있으므로 다른 클릭을 시뮬레이션하기 전에 콘텐츠가 로드될 때까지 기다려야 합니다. setTimeout()을 사용하여 요청 사이에 지연을 도입해야 합니다.

아래 코드는 "더 보기" 버튼을 다시 클릭하는 것을 시뮬레이션하기 전에 최소 2초 동안 기다리도록 스크립트에 알립니다.

$ node dynamicScraper.js
로그인 후 복사
로그인 후 복사

이 섹션의 내용을 마무리하려면 content() 메서드를 사용하여 클릭할 때마다 현재 HTML 콘텐츠를 가져온 다음 출력을 터미널에서 로그아웃하려고 합니다.



    <title>Load More Button Challenge - ScrapingCourse.com</title>


    <header>
        <!-- Navigation Bar -->
        <nav>
            <a href="/">
                <img src="logo.svg" alt="무한 스크롤이 있는 페이지에서 데이터를 긁어내는 방법">
                <span>Scraping Course</span>
            </a>
        </nav>
    </header>

    <main>
        <!-- Product Grid -->
        <div>



<p>Note that the code structure above is what your output should look like.</p>

<p>Wow! You should be proud of yourself for getting this far. You’ve just completed your first attempt at scraping the contents of a webpage. </p>

<h2>
  
  
  Simulate the LOad More Products Process
</h2>

<p>Here, you want to access more products, and to do that, you need to click on the “Load more” button multiple times until you’ve either exhausted the list of all products or gotten the desired number of products you want to access. </p>

<p>To access this button and click on it, you must first locate the element using any CSS selectors (the class, id, attribute of the element, or tag name). </p>

<p>This tutorial aims to get at least 48 products from the target website, and to do that, you’ll have to click on the “Load more” button at least three times.</p>

<p>Start by locating the “Load more” button using any of the CSS selectors on it. Go to the target website, find the “Load more” button, right-click, and select the inspect option. </p>

<p><img src="https://img.php.cn/upload/article/000/000/000/173587927350910.jpg" alt="How to Scrape Data from a Page with Infinite Scroll"></p>

<p>Selecting the inspect option will open up developer tools just like the page below:</p>

<p><img src="https://img.php.cn/upload/article/000/000/000/173587927639663.jpg" alt="How to Scrape Data from a Page with Infinite Scroll"></p>

<p>The screenshot above shows that the “Load more” button element has an id attribute with the value "load-more-btn". You can use this id selector to locate the button during the simulation and click on it multiple times.</p>

<p>Back to the code, still inside the try block, after the line of code that logs out the previous HTML content for the default 12 products on the page.</p>

<p>Define the number of times you want to click the button. Recall that each click loads an additional 12 products. For 48 products, three clicks are required to load the remaining 36.<br>
</p>

<pre class="brush:php;toolbar:false">// Number of times to click "Load More"
const clicks = 3;
로그인 후 복사

지금까지의 전체 코드:

for (let i = 0; i 



<p>다음은 48개의 제품을 얻기 위해 버튼 클릭을 세 번 시뮬레이션한 결과입니다.<br>
</p>

<pre class="brush:php;toolbar:false">console.log(`Clicking the 'Load More' button - Attempt ${i + 1}`);
로그인 후 복사

이제 48개 제품 전체의 출력과 상호 작용하는 데만 관심을 가져야 합니다. 이렇게 하려면 마지막 섹션에서 이전 코드를 정리해야 합니다.

또한 for 루프 블록 다음에 html 변수를 가져와야 48개 제품 모두에 대해 단 하나의 출력만 얻을 수 있습니다.

정리 코드는 다음 코드 조각과 동일해야 합니다.

$ npm install cheerio puppeteer
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

이제 Cheerio를 사용하여 HTML 파싱을 시작해 보겠습니다.

우선 Cheerio는 구문 분석하려는 HTML 콘텐츠에 액세스할 수 있어야 하며, 이를 위해 해당 HTML 콘텐츠를 가져오는 load() 메서드를 제공하여 jQuery와 유사한 구문을 사용하여 액세스할 수 있도록 합니다.

HTML 콘텐츠로 Cheerio 라이브러리의 인스턴스를 만듭니다.

const puppeteer = require('puppeteer');
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

이제 $를 사용하여 로드된 HTML의 요소를 쿼리하고 조작할 수 있습니다.

다음으로 제품 정보를 저장할 배열을 초기화합니다. 이 배열에는 추출된 데이터가 저장되며 각 제품은 이름, 가격, 이미지 및 링크와 함께 객체로 저장됩니다.

const url = 'https://www.scrapingcourse.com/button-click';
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

각 제품에는 .product-item 클래스가 있다는 점을 기억하세요. 이를 Cheerio($)의 변수 인스턴스와 함께 사용하여 각 제품을 가져온 다음 몇 가지 조작을 수행합니다.

.each() 메서드는 .product-item 클래스 선택기를 사용하여 일치하는 각 요소를 반복하는 데 사용됩니다.

(async () => {
    try {
        // Code goes here
    } catch (error) {
        console.error('Error:', error.message);
    }
})();
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

특정 세부정보의 클래스 선택기를 사용하여 각 제품에서 제품 세부정보를 검색해 보겠습니다. 예를 들어 제품 이름을 얻으려면 클래스 선택기 .product-item을 사용하여 각 제품의 하위 요소를 찾아야 합니다. 해당 하위 요소의 텍스트 콘텐츠를 검색하고 공백이 있는 경우 잘라냅니다.

// Launch Puppeteer
const browser = await puppeteer.launch({ headless: false }); // Headless mode
const page = await browser.newPage(); // Open a new page
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
  • $(element).find('.product-name'): 현재 .product-item 내에서 .product-name 클래스가 있는 하위 요소를 검색합니다.
  • .text(): 요소 내부의 텍스트 콘텐츠를 검색합니다.
  • .trim(): 텍스트에서 불필요한 공백을 제거합니다.

이 개념을 활용하여 클래스 속성을 사용하여 가격, 이미지 URL 및 링크를 가져옵니다.

// Navigate to the target URL
await page.goto(url, {
    waitUntil: 'networkidle2', // Ensure the page is fully loaded
});
로그인 후 복사
로그인 후 복사

이제 예상되는 정보를 모두 얻었으므로 다음은 구문 분석된 각 제품 정보를 개별 개체로 제품 배열에 푸시하는 것입니다.

// Get the full HTML content of the page
const html = await page.content();

// Log the entire HTML content
console.log(html);

// Close the browser
await browser.close();
로그인 후 복사
로그인 후 복사

마지막으로 제품 배열을 로그아웃하여 터미널에 예상되는 출력을 가져옵니다.

// Delay for 10 seconds to allow you to see the browser
await page.waitForTimeout(10000);
로그인 후 복사
로그인 후 복사

전체 코드는 다음 코드 조각과 같아야 합니다.

const puppeteer = require('puppeteer');

const url = 'https://www.scrapingcourse.com/button-click';

(async () => {
    try {
        // Launch Puppeteer
        const browser = await puppeteer.launch({ headless: false }); // Headless mode
        const page = await browser.newPage(); // Open a new page

        // Navigate to the target URL
        await page.goto(url, {
            waitUntil: 'networkidle2', // Ensure the page is fully loaded
        });

        // Get the entire HTML content of the page
        const html = await page.content();

        // Log the entire HTML content
        console.log(html);

        // Delay for 10 seconds to allow you to see the browser
        await page.waitForTimeout(10000);

        // Close the browser
        await browser.close();
    } catch (error) {
        console.error('Error fetching the page:', error.message);
    }
})();
로그인 후 복사
로그인 후 복사

스크립트를 저장하고 실행할 때의 출력은 다음과 같습니다.

$ node dynamicScraper.js
로그인 후 복사
로그인 후 복사

제품 정보를 CSV로 내보내기

다음 단계는 현재 JSON(JavaScript Object Notation) 형식으로 되어 있는 구문 분석된 제품 정보를 CSV(쉼표로 구분된 값) 형식으로 내보내는 것입니다. json2csv 라이브러리를 사용하여 구문 분석된 데이터를 해당 CSV 형식으로 변환합니다.

필요한 모듈을 가져오는 것부터 시작하세요.

Node.js는 파일에 데이터 쓰기 등의 파일 처리를 위한 파일 시스템(fs) 모듈을 제공합니다. fs 모듈을 가져온 후에는 json2csv 라이브러리에서 parse() 메서드를 구조 해제해야 합니다.

$ npm install cheerio puppeteer
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

CSV 파일에는 일반적으로 열 헤더가 필요합니다. 구문 분석된 정보와 동일한 순서로 주의 깊게 작성하세요. 여기서 구문 분석된 데이터는 제품 배열이며, 여기서 각 요소는 4개의 키(이름, 가격, 이미지 및 링크)가 있는 객체입니다. 적절한 매핑을 위해 이러한 객체 키를 사용하여 열 헤더의 이름을 지정해야 합니다.

CSV 파일의 필드(열 헤더)를 정의합니다.

const puppeteer = require('puppeteer');
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

이제 필드를 정의했으므로 다음 작업은 현재 구문 분석된 정보를 CSV 형식으로 변환하는 것입니다. 구문 분석() 메소드는 다음 형식으로 작동합니다: 구문 분석(WHAT_YOU_WANT_TO_CONVERT, { YOUR_COLUMN_HEADERS }).

const url = 'https://www.scrapingcourse.com/button-click';
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

이제 이 CSV 정보를 파일 확장자가 .csv인 새 파일에 저장해야 합니다. Node.js를 사용할 때 fs 모듈의 writeFileSync() 메서드를 사용하여 파일 생성을 처리할 수 있습니다. 이 방법은 파일 이름과 데이터라는 두 가지 매개변수를 사용합니다.

(async () => {
    try {
        // Code goes here
    } catch (error) {
        console.error('Error:', error.message);
    }
})();
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

이 섹션의 전체 코드는 다음과 같습니다.

// Launch Puppeteer
const browser = await puppeteer.launch({ headless: false }); // Headless mode
const page = await browser.newPage(); // Open a new page
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

스크립트를 저장하고 실행하면 products.csv라는 파일이 파일 구조에 자동으로 추가되는 것을 볼 수 있습니다.

출력 - products.csv:
How to Scrape Data from a Page with Infinite Scroll

결론

이 튜토리얼에서는 숨겨진 콘텐츠에 액세스하기 위해 시뮬레이션이 필요한 페이지에서 데이터를 스크래핑하는 복잡한 과정을 자세히 살펴보았습니다. Node.js 및 일부 추가 라이브러리를 사용하여 동적 페이지에서 웹 스크래핑을 수행하고, 스크랩한 데이터를 보다 체계적인 형식으로 구문 분석하고, CSV 파일로 압축을 푸는 방법을 배웠습니다.

위 내용은 무한 스크롤이 있는 페이지에서 데이터를 긁어내는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
저자별 최신 기사
인기 추천
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿