IT_Study/Web

Back-End (4) : Node.js를 이용한 Crawling 방법, WAS, CORS, SSR & CSR

__Vivacé__ 2023. 3. 2. 23:22

Node.js를 이용한 크롤링 방법

 

0. robot.txt

  • Robots exclusion standard 표준 규약
  • 각 홈페이지 뒤에 robots.txt 를 붙이면 조회할 수 있음
  • (ex: https://www.google.com/robots.txt)
  • 서비스 출시 및 영리적 목적으로 사용되는 경우, 법적인 분쟁이 발생 가능

 

 

1. Crawling 준비

*NPM(Node Package Module)

Node.js 패키지를 설치, 업데이트, 제거 및 관리 가능

 

*Puppeteer

구글에서 개발한 웹 브라우저 제어용 Node.js 라이브러리

 

package.json 생성

# 1. 원하는 directory로 이동
cd [target folder]

# 2. npm init의 역할 : package.json 생성
npm init 
// json 모습
{
  "name": "2023-03-02",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \\"Error: no test specified\\" && exit 1"
  },
  "author": "",
  "license": "ISC" # ISC는 무료 라이센스
}

 

Puppeteer 다운로드

# 다운로드 방법 : npm i [library name]
# i : install의 약어
npm i puppeteer

해당 명령어 입력 시,

 

 

  1. 디렉토리 내부에 package-lock.jsonnode_modules 파일이 설치됨
    • node_modules : package.json으로부터 install한 실제 파일들
    • package-lock.json : dependency 관리를 안정적으로 하기 위한 파일

 

  1. package.json의 dependencies에 puppeteer version 추가
    • 추후 Github upload 시, 용량이 큰 node_modules을 제거 후 “npm i package.json” 명령어를 통해 node_modules을 복구 가능

 


 

2. 크롤링 코드 작성

 

웹 스크래핑(Web Scrapping) vs 웹 크롤링(Web Crawling)

  • 웹 스크래핑(Web Scrapping) : 특정 웹 페이지에서 데이터를 수동으로 수집
  • 웹 크롤링(Web Crawling) : 원하는 모든 웹 페이지에서 데이터를 자동으로 탐색 및 수집

 

 

웹 페이지 창을 띄워서 크롤링 진행 (headless : false)

# target 폴더 내에 index.js 생성

 

// index.js 내용

// 1. 패키지를 가져오는 법 - require() 활용

const puppeteer = require("puppeteer");

const main = async() => {
    // 브라우저 만들기

    const browser = await puppeteer.launch({
        // 기본 값이 headless : True
        headless:false
    })

    // 브라우저에 페이지 만들기
    const page = await browser.newPage();

    // 페이지에서 주소로 이동하기
    await page.goto("<https://comic.naver.com/webtoon?tab=mon>")

		// 페이지에 내가 찾는 요소가 loading이 될 때까지 대기하기
    await page.waitForSelector("#content .item img");

    const data = await page.evaluate(() => {
				
				// 내가 원하는 content select
        const WebtoonList = document.querySelectorAll("#content .item img");

        // 제목 가져오기
        const result = Array.from(WebtoonList).map(li => li.getAttribute('alt'));

        return result;
    })

    console.log(data);

    // 스크린샷 찍기, fullPage:true 시 웹 페이지 전체가 찍힘
    await page.screenshot({path: "screenshot.jpg", fullPage:true});

    await browser.close();

}

main();

// index.js가 있는 directoru에 들어가 terminal에 node index.js 입력

 

웹 페이지 창을 띄우지 않고 크롤링 진행 (headless : True)

// index.js 내용

// 1. 패키지를 가져오는 법 - require() 활용

const puppeteer = require("puppeteer");

const main = async() => {
    // 브라우저 만들기
    const browser = await puppeteer.launch();

    // 브라우저에 페이지 만들기
    const page = await browser.newPage();

    // 페이지에서 주소로 이동하기
    await page.goto("<https://comic.naver.com/webtoon?tab=mon>")
		
		// 페이지에 내가 찾는 요소가 loading이 될 때까지 대기하기
		await page.waitForSelector("#content .item img");
    
		// pdf 따기 (headless : true 에서만 동작)
    await page.pdf({path: "test.pdf", format:'A4'});

    // 브라우저 종료
    await browser.close();
}

main();

// index.js가 있는 directoru에 들어가 terminal에 node index.js 입력

 


 

WAS(Web Application Server)

웹 서버(Nginx, Apache 등)데이터베이스(DB) 사이에서 동적인 컨텐츠를 생성하고, 처리하는 서버

 

Client의 DB 관련 request를 처리하는 모식도

Express

WAS의 일종으로, Node.js 기반으로 동작하는 웹 어플리케이션 프레임워크

  1. Nginx는 웹 서버로, 클라이언트로부터 HTTP 요청을 받아서, 정적인 파일(html, css, js 등)을 제공하는 역할을 수행
  2. 데이터베이스의 데이터를 조회하거나, 변경하는 등의 동적인 작업은 Nginx와 같은 웹 서버에서 직접 처리할 수 없음
  3. WAS는 웹 서버에서 요청을 받아 데이터베이스와 통신하여 동적인 데이터를 처리하고, 그 결과를 다시 웹 서버로 전달
  4. 이런 방식으로 데이터베이스와의 연결을 보안성 높게 유지 가능

 

Express 설치 + Nodemon + cors 설치

npm i express

# --location=global : 일반적으로 directory 내에 있는 package.json에만 있는 걸 활용할 수 있는데
# global option 적용 시, 다른 package에서도 이걸 활용할 수 있게 됨
npm i --location=global nodemon

# nodemon : 소스 코드의 변경을 감지하여 자동으로 어플리케이션을 재시작해줌
# test 환경에서만 할 것 / 실제 서비스에서는 issue 생길 수 있음

# cors : 웹 어플리케이션에서 CORS를 구현하기 위해 사용하는 라이브러리
# cors는 다른 도메인에서의 접근을 허용해주는 도구
# cors를 이용해 특정 IP와 PORT를 개방시켜준다
npm i cors

Express 사용법

// index.js 파일 내부 내용

const express = require('express');

const app = express();

const PORT = 8080;

const cors = require('cors');

// cors 미들웨어를 사용 - 아래 코드는 모든 접속이 허용됨
// 프론트 라이브서버 : 5500번 포트
// 백엔드 서버 : 8080 포트
// 포트가 달라도 접속이 가능하도록 설정해주는 것
app.use(cors());

// 1st param - API route
// 2nd param - req : 요청 객체, res : 응답 객체
app.get("/", (req, res) => {

    return res.json({
        test: "OK"
    });

})

app.get("/api/info", (req, res) => {

    return res.json({
        name : "jony",
        job: "tutor"
    });

})

// listen : 서버 요청 대기 상태
// 1st param - expression 서버는 PORT(8080) 포트에서 request 대기 중
// 2nd param - listen 성공 시 실행되는 callback func을 의미
app.listen(PORT, () => console.log(`${PORT} 서버 기동 중`));

CORS Policy - port까지 일치해야 통신이 가능하지만, 위 코드에서 cors로 정책을 바꿨기 때문에, 다른 port를 갖고 있는 Live Server(5500)로 express(8080)에 들어갈 수 있음

// 해당 html 파일을 Live server로 실행 시, error 발생 x
    서버의 데이터 가져오기
        const button = document.querySelector('button');
        button.addEventListener('click', async function(){
            try {
                const response = await axios.get("<http://localhost:8080/api/info>");
                console.log(response);
                
            } catch (error) {
                console.log(error);
            }
        })
    

 


 

  1. SSR(Server Side Rendering)
    • 서버에서 HTML 페이지를 동적으로 생성하여 클라이언트에게 전달하는 방식
    • 초기 로딩 속도가 빠름
    • JSP(Java Server Pages) - 서버에서 JSP 파일을 실행시키면, 결과를 HTML 형식으로 브라우저에게 전달
      • 브라우저는 자바를 해석할 능력이 없어서, JSP를 서버에서 읽어 DB와 연동해 완성한 HTML을 반환

 

  1. CSR(Client Side Rendering)
    • JavaScript를 이용하여 동적으로 웹 페이지를 생성하는 방식
      • JavaScript로 비동기 요청을 해서 데이터를 생성
    • 초기 로딩 속도가 느리지만, 사용자 인터랙션에 더 나은 UX를 제공할 수 있음