Puppeteer를 사용하여 Google 비즈니스 리뷰 검색

이 문서의 코드는 이 github 저장소에서 사용할 수 있습니다.
https://github.com/PiiXelx64/node-google-reviews-web-scraper , 그리고 NPM 패키지도 있습니다: https://www.npmjs.com/package/google-reviews-web-scraper

실제로 유용할 수 있는 Google Maps API에 부족한 기능이 있는 경우 장소에서 리뷰를 검색할 수 있습니다. 그러나 우리는 항상 웹 사이트에서 데이터를 스크랩할 수 있습니다. 이것이 바로 제가 이 문제를 해결하기 위해 한 일입니다.


우리의 스택



페처를 생성하거나 검토하기 위해 NodeJS와 일반 이전 JS를 사용할 것입니다. 우리는 TypeScript를 사용할 수 있었지만 큰 이점이 없었습니다. NodeJS를 사용하면 코드를 통해 호출할 수 있는 헤드리스 크롬 구현인 Puppeteer에 액세스할 수 있습니다.

Google은 JavaScript 사용을 좋아하기 때문에 페이지에서 데이터를 가져오기 위해 axios와 같은 것을 사용할 수 없었습니다. 여기에서 우리의 관심 대상인 리뷰를 표시하는 데 필요한 JavaScript 코드를 실행하지 않았기 때문입니다.

프로젝트 설정



우리는 npm 프로젝트와 git repo를 만들 것입니다. 이를 위해서는 시스템에 git 및 npm이 설치되어 있어야 하며 다음 두 가지 간단한 명령을 실행해야 합니다.

npm init
git init


그 후 작업을 시작할 준비가 되었습니다.

인형극 설정



puppeteer를 시작하고 실행하려면 먼저 가져와야 합니다.

const puppeteer  = require('puppeteer');


가져오면 async 함수를 만들어야 합니다. 여기서는 getReviews 이라고 하고 url 매개변수를 지정합니다.

const getReviews = async (url) => { /* code */ }


그런 다음 이 메서드에서 browser , page 를 생성하고 관심 있는 페이지로 이동한 다음 조작하려는 구성 요소가 로드될 때까지 기다려야 합니다.

기다려야 하는 구성 요소를 찾습니다.



찾으려는 구성 요소의 클래스 또는 ID를 찾으려면 브라우저의 인스펙터를 사용할 수 있습니다.

여기에서 클래스.section-review-text에 텍스트 리뷰가 포함되어 있는 것을 볼 수 있으므로 기다리기만 하면 됩니다.

이제 getReviews 메서드에 다음이 포함됩니다.

const getReviews = async (url) => { 
    // no sandbox for the headless browser
    const browser = await puppeteer.launch({args: ['--disabled-setuid-sandbox', '--no-sandbox']});
    const page = await browser.newPage();
    await page.goto(url);
    console.log('waiting for selector');
    await page.waitForSelector('.section-review-text');
}


이제 페이지를 로드했으므로 어떻게든 데이터를 가져와야 합니다. 이를 위해 page.evaluate() 방법을 사용할 수 있습니다. 여기에서 리뷰 작성자, 게시 날짜, 등급 및 리뷰 텍스트를 가져오려고 합니다.

const data = await page.evaluate(() => {
    let reviewAuthorNamesClasses = document.getElementsByClassName('section-review-title');
    let reviewAuthorNames = [];
    for (let elements of reviewAuthorNamesClasses) {
        reviewAuthorNames.push(elements.innerText);
    }
    let datesClasses = document.getElementsByClassName('section-review-publish-date');
    let dates = [];
    for(let elements of datesClasses) {
        dates.push(elements.innerText);
    }

    let ratingsClasses = document.getElementsByClassName('section-review-stars');
    let ratings = [];
    for (let elements of ratingsClasses) {
        ratings.push(elements.children.length);
    }

    let reviewsContentClasses = document.getElementsByClassName('section-review-text');
    let reviewsContent = []
    for(let elements of reviewsContentClasses) {
        reviewsContent.push(elements.innerText);
    }
    return {
        reviewAuthorNames,
        dates,
        ratings,
        reviewsContent
    }
})


이제 data 상수에는 4개의 배열이 포함되며 각 배열에는 리뷰를 구성하는 데이터 요소 중 하나가 포함됩니다.
헤드리스 브라우저 사용이 끝나면 닫아야 합니다. 이를 위해 browser.close();를 사용할 수 있습니다.

이제 필요한 데이터가 있으므로 promise 상수가 포함된 data를 반환할 수 있습니다. 우리의 getReviews 메서드는 이제 다음과 같습니다.

const getReviews = async (url) => {
    const browser = await puppeteer.launch({args: ['--disabled-setuid-sandbox', '--no-sandbox']});
    const page = await browser.newPage();
    await page.goto(url);
    console.log(page.url);
    await page.waitForSelector('.section-review-text');
    const data = await page.evaluate(() => {
        let reviewAuthorNamesClasses = document.getElementsByClassName('section-review-title');
        let reviewAuthorNames = [];
        for (let elements of reviewAuthorNamesClasses) {
            reviewAuthorNames.push(elements.innerText);
        }
        let datesClasses = document.getElementsByClassName('section-review-publish-date');
        let dates = [];
        for(let elements of datesClasses) {
            dates.push(elements.innerText);
        }

        let ratingsClasses = document.getElementsByClassName('section-review-stars');
        let ratings = [];
        for (let elements of ratingsClasses) {
            ratings.push(elements.children.length);
        }

        let reviewsContentClasses = document.getElementsByClassName('section-review-text');
        let reviewsContent = []
        for(let elements of reviewsContentClasses) {
            reviewsContent.push(elements.innerText);
        }
        return {
            reviewAuthorNames,
            dates,
            ratings,
            reviewsContent
        }
    })
    browser.close();
    return new Promise((resolve, reject) => {
        resolve(data);
        if(reject) {
            reject({error: "error while scraping data."})
        }
    })

};


이제 방법을 모듈로 내보낼 수 있습니다.

module.exports = getReviews;


방법 테스트



이제 방법이 완료되었으므로 다음을 통해 테스트할 수 있습니다.
  • 모듈 가져오기
  • 모듈을 사용하여 장소에 대한 리뷰를 가져옵니다.
    장소로는 에펠탑을 사용하겠습니다. 장소 URL은 다음과 같습니다: https://www.google.com/maps/place/Tour+Eiffel/@48.8583736,2.292298,17z/data=!4m5!3m4!1s0x47e66e2964e34e2d:0x8ddca9ee380ef7e0!8m2!3d48.8583701!4d2.2944813 .

  • 이 예제에서는 콘솔에 데이터를 JSON으로 기록할 것입니다. 익스프레스 서버를 사용하고 인터넷을 통해 제공할 수도 있습니다.

    const getReviews = require('./getReviews');
    
    async function main() {
        try {
            const data = await getReviews("https://www.google.com/maps/place/Tour+Eiffel/@48.8583736,2.292298,17z/data=!4m5!3m4!1s0x47e66e2964e34e2d:0x8ddca9ee380ef7e0!8m2!3d48.8583701!4d2.2944813");
            console.log(JSON.stringify(data));
        } catch(e) {
            console.log(e);
        }
    
    }
    
    main();
    


    그리고 내 터미널 출력은 다음과 같습니다.

    { reviewAuthorNames:
       [ ' Romain VILCOQ ', ' Sylvain Justine ', ' Alexandre MASSON ' ],
      dates: [ 'il y a 3 semaines', 'il y a 2 jours', 'il y a 5 jours' ],
      ratings: [ 5, 5, 5 ],
      reviewsContent:
       [ 'La dame de fer est l\'emblème de notre capitale, le monument à visiter en priorité. \nLa vue depuis le sommet est incontournable !\nL\'ascension par les escaliers est une belle expérience et permet de profiter au mieux de la structure, cependant elle est réservée aux plus sportifs. La descente est possible également ���',
         'Lieu sécurisé, pas de file d\'attente. C top',
         'Magnifique et incontournable monument de la capitale française. A absolument faire lors de votre visite parisienne ! Haute de 321 mètres, cette tour de fer surplombe la région parisienne. Véritable prouesse architecturale et scientifique, …' ] }
    {"reviewAuthorNames":[" Romain VILCOQ "," Sylvain Justine "," Alexandre MASSON "],"dates":["il y a 3 semaines","il y a 2 jours","il y a 5 jours"],"ratings":[5,5,5],"reviewsContent":["La dame de fer est l'emblème de notre capitale, le monument à visiter en priorité. \nLa vue depuis le sommet est incontournable !\nL'ascension par les escaliers est une belle expérience et permet de profiter au mieux de la structure, cependant elle est réservée aux plus sportifs. La descente est possible également �😉","Lieu sécurisé, pas de file d'attente. C top","Magnifique et i
    ontournable monument de la capitale française. A absolument faire lors de votre visite parisienne ! Haute de 321 mètres, cette tour de fer surplombe la région parisienne. Véritable prouesse architecturale et scientifique, …"]}
    


    그리고 우리는 간다!

    이 프로젝트에서 배운 내용


  • 약속 사용
  • 웹스크래핑
  • 헤드리스 브라우저를 사용하여 js 전용 웹 사이트에서 데이터를 가져옵니다.

  • 이 프로젝트를 어떻게 개선할 수 있습니까?


  • 이 코드를 기반으로 API 생성
  • 작업자 스레드 사용
  • 좋은 웹페이지 즐겨찾기