강디너의 개발 일지

javascript - AWS Lambda 를 이용해서 크롤링하기 본문

Javascript/삽질

javascript - AWS Lambda 를 이용해서 크롤링하기

강디너 2020. 1. 27. 23:41
728x90
반응형

기획

멜론 차트를 하루에 한 번 크롤링해서 Firebase Database에 저장

 

현재 상황

1. Vue.js 를 이용해서 프론트를 만드는 중이다.

2. Firebase Database 를 사용한다.

3. 멜론 차트를 크롤링 하고 싶다  <--- 주 원인

4. 하지만 서버단이 없다 !

 

 

어떻게 구현 할까 고민하던 중 회사에서 토이 프로젝트 지원으로 AWS를 가지고 놀아도 된다고 했던 말이 기억나서 EC2에 웹서버 띄우고, 백단에서 크롤링 + 데이터 저장 하려고 했습니다.

 

하트만 누른거 티나겠다 ㅇㅅㅇ

 

이러한 기획을 가지고 데브옵스분께 쪼르르 가서 말씀드렸는데, 그 정도면 Lambda라는 것을 이용해서 하면 더 좋을 거라고(비용이었나?) 하시며 자기도 javascript 베이스로 안 해봤는데 같이 해보자고 하셨습니다.

제가 아는 람다는 화살표인데...

 

AWS Lambda란 제 입장에서 말하면 AWS에 요청을 보내면 응답을 보내주는 '착한 애'입니다.

EC2 같은 경우 계속 띄워져 있는 애임에 반해서 Lambda는 호출할 때만 응답하기 때문에 비용적에서도 효율이 좋은 애입니다.

 

AWS Lambda는 서버를 프로비저닝하거나 관리하지 않고도 코드를 실행할 수 있게 해주는 컴퓨팅 서비스입니다. AWS Lambda는 필요 시에만 코드를 실행하며, 하루에 몇 개의 요청에서 초당 수천 개의 요청까지 자동으로 확장이 가능합니다. 사용한 컴퓨팅 시간에 대해서만 요금을 지불하면 되고 코드가 실행되지 않을 때는 요금이 부과되지 않습니다.

 

자세한 건 아래 블로그에서 보고 많이 응용했습니다.

https://velopert.com/3549

 

Serverless 프레임워크로 서버리스 애플리케이션 생성 및 배포하기 | VELOPERT.LOG

이 튜토리얼은 이어지는 튜토리얼입니다. 이 포스트를 통해 블로그에 처음 방문하셨다면 Serverless 강좌 목록 페이지를 확인해주세요. AWS Lambda, Azure Functions, Google Cloud Functions 를 통하여 서버리스 애플리케이션을 만들게 된다면, 단순히 함수들을 작성하는 것 뿐만이 아니라 해당 애플리케이션에서 필요한 아키텍쳐들을 설정해주어야하는데, 이는 수동으로 하나 하나 직접하기엔 꽤나 번거로운 일 입니다. Server

velopert.com

 

코드는 제 깃허브에 있습니다.

https://github.com/DinnerKang/study_vue/tree/master/dinner-project

 

serverless.yml


service: dinner-project

provider:
  name: aws
  runtime: nodejs12.x
  stage: dev
  region: ap-northeast-2
  deploymentBucket: ${file(./config.js):config.BUCKET_NAME}
  deploymentPrefix: ${self:service}
  role: arn:aws:iam::${file(./config.js):config.ACCOUNT_NUM}:role/${file(./config.js):config.ROLE_NAME}
  usagePlan:
    quota:
      limit: 5000
      offset: 2
      period: MONTH
    throttle:
      burstLimit: 200
      rateLimit: 100

functions:
  hello:
    handler: handler.hello
    events: 
      - http:
          path: hello
          method: get
      - cloudwatchLog: '/aws/lambda/${self:service}'

 

뭔가 노출하면 안 될 것 같은 이름들은 config.js 파일에 변수명으로 처리했습니다.

리미트 제한도 설정 할 수 있습니다.

 

handler.js (1/31 수정)

'use strict';

const cheerio = require('cheerio');
const axios = require('axios');

axios.defaults.baseURL = 'https://vue-pwa-776e7.firebaseapp.com';
axios.defaults.headers['Accept'] = 'application/json, text/plain, */*';

module.exports.hello = async (event, ctx, cb) => {
  const title = [];
  const artist = [];
  const result = {};
  const rank = 100;
  const getHtml = async () => {
    try {
        return await axios.get('https://www.melon.com/chart/');
    } catch (err) {
        console.error('axios error', axios);
        console.error(err);
    }
  }

  const html = await getHtml();
  const $ = cheerio.load(html.data);
  for (let i = 0; i < rank; i++) {
      $('.ellipsis.rank01 > span > a').each( function(idx){
        const title_info = $(this);
        const title_info_text = title_info.text();
        title[idx] = title_info_text;
      })
  }
  
  for (let i = 0; i < rank; i++) {
      $('.checkEllipsis').each(function(idx){
        const artist_info = $(this);
        const artist_info_text = artist_info.text();
        artist[idx] = artist_info_text;
      })
  }
  for (let i = 0; i < rank; i ++) {
      result[i] = {
           title: title[i],
           artist: artist[i],
      }
  }
  
  const registDate = String(new Date());
  const response = {
    statusCode: 200,
    body: JSON.stringify({
      result,
      registDate,
    }),
  };
  cb(null, response);
};

프론트에서 AWS Lambda를 호출했을 때에는 정상 응답을 했는데, 스케줄을 이용해서 호출하니깐 오류가 나는 현상을 발견해서 axios 헤더를 수정하였습니다.

오류 날 때마다 멜론님께서 절 차단한 줄 알고 얼마나 가슴 졸였는지...

firebase database 이용해서 매 시간 스케줄링 해서 저장하려고 했는데... firebase 만 연동하면 오류가 발생하네요... 함수가 안끝나는거 같은데 'ctx.callbackWaitsForEmptyEventLoop = false;' 이 옵션을 써도 종료가 되지 않습니다.

이거 때문에 삽질을 엄청 했는데 찾지 못했네요 ㅠㅠ.. 누가 찾으신분 답좀 알려줘요...

커피한잔...
Comments