탄소중립

[탄소중립 아카데미 6기] 자동 크롤러 구현하기

codie0226 2026. 4. 13. 17:55
반응형

회고

저번 회의에서 우리가 구축할 RAG 시스템의 컨셉을 정했다. 기본적으로 RAG에 적용할 문서를 정해야 했기에 빠르게 주제를 정해야하였고, 대학교 프로젝트인만큼 대학생들을 대상으로 방향성을 잡았다.

우리 팀의 팀원들이 전부 SW중심대학에 소속되어 있으므로, 아무래도 교내외 활동을 찾을 때 SW중심사업단 페이지를 자주 접근한다. 거기에 우리 학교 페이지에는 AI 챗봇이 없다. 따라서 프로젝트 대상으로 적절하다고 생각하였고, 이번 과제로 공지사항 페이지와 홍보게시판에 있는 게시글들을 크롤링하여 데이터를 수집하였다.

 

크롤러 만들기

웹 크롤러는 목적에 따라 다른 기능을 수행하지만, 우리가 만드는 게시판 크롤러는 비교적 구현하기 간단하다. 게시판 크롤러는 크게 다음과 같은 역할을 수행해야 한다.

  1. 일정 시간마다 게시판 크롤링
  2. 새로운 게시글이 존재할 경우, 상세 페이지 조회 및 저장
  3. 이미지 파싱 처리 및 저장

이러한 간단한 구조는 쉽게 구현할 수 있다. 사실 로컬에서 프로그램을 일일이 돌려가면서 처리할 수 있지만... 굳이 그럴 필요는 없다. 우리에겐 AWS가 있다!

 

간단한 아키텍처

먼저 고려해야 할 것은 "크롤러 자동화를 어떻게 할 것인가?"이다. 자동으로 프로그램을 돌려주는 매크로 같은 프로그램을 사용해도 되고, 서버 같은 컴퓨터에 올려서 일정 시간마다 실행하게 만드는 방법도 있다. 하지만 전기세는 무제한이 아니고 클라우드 서버 서비스는 시간당으로 비용이 청구되고, 크롤러를 24시간 내내 돌릴거 아니면 너무 과한 시스템이다.

우리의 든든한 클라우드 친구 AWS에는 람다라는 클라우드 서비스가 있다. 서버리스 시스템이라고 생각하면 될 듯 한데, 특이하게 프로그램 전체를 탑재하지 않고, 함수 단위로 런타임을 만들어서 실행할 수 있다는 장점이 있다. 무엇보다 AWS 서비스이다 보니까 종량제로 비용을 책정한다. 쓴 만큼 돈이 부과되는데, 일정 시간마다 실행하는 크롤러는 비용적이 부담이 거의 없다. 또한 람다에는 트리거를 설정하여, 특정 조건이 충족되었을 때 자동으로 람다 함수를 실행하게 할 수 있다.

AWS 람다는 여러 런타임을 지원하는데, 크롤러를 구현하는데에는 Node.js(Puppeteer, cheerio), Python(Selenium,

BeautifulSoup)이 가장 적합하다. 여러 라이브러리가 존재하여 구현하기 쉽기 때문이다. JS가 더 익숙하기도 하고, cheerio의 빠른 처리 속도를 믿고 Node.js로 구현을 해보도록 하겠다.

 

코드 구조

Node.js의 package.json을 생성하고, cheerio, axios, aws-sdk 등의 필수 라이브러리를 설치한다.

{
  "name": "inha-crawler-lambda",
  "version": "1.0.0",
  "description": "인하대학교 SW중심대학사업단 공지사항 크롤러 (AWS Lambda)",
  "main": "index.js",
  "scripts": {
    "test": "node test.js"
  },
  "dependencies": {
    "@aws-sdk/client-s3": "^3.0.0",
    "axios": "^1.6.0",
    "cheerio": "^1.0.0",
    "tesseract.js": "^7.0.0"
  }
}

다음으로 총 2개의 함수를 구현할 것이다. 하나는 정기적으로 실행되는 함수, 하나는 모든 게시글을 읽어오는 함수이다.

lib/에 공통으로 사용되는 함수들을 포함하고, 두개의 함수를 만들어서 크롤러를 구현했다. (claude가)

(자세한 코드는 스킵)

 

 

완성된 구조는 이렇게 된다. full-crawl.js가 모든 게시글을 읽어오는 함수이고, index.js가 최신 게시글만 읽어오는 함수이다.

읽어온 데이터는 S3 버킷에 자동으로 저장되고, S3에 저장된 데이터는 AWS를 연결할 수 있는 모든 곳에서 사용할 수 있게 된다.

추후에 벡터 임베딩을 진행하거나, 인공지능 학습시에도 빠르게 접근할 수 있을 것이다.

 

AWS 람다 배포

이제 직접 배포를 해보자. 먼저 AWS 콘솔에서 람다 메뉴로 들어간다.

처음에는 비어있는 대시보드가 나올 것이다. 어찌 됐든 함수 생성을 눌러 시작한다.

커다란 오렌지 '함수 생성' 버튼을 클릭해보자.

 

람다 함수는 웹 IDE에서 구현하거나, 외부에서 가져올 수도 있다. AWS 내에서는 ECR이나 S3와 같은 컨테이너 안에서도 가져올 수 있다. 나는 로컬에서 구현하였으므로 '새로 작성'을 선택하고 넘어가면 된다.

런타임은 Node.js 20.* 이상 버전이면 된다. 내가 구현한 크롤러에서는 아키텍처는 별로 상관 없으므로 기본 x86을 사용해도 되고, 비용을 극한까지 아껴야 한다 싶으면 arm을 사용해도 된다.

나머지는 그대로 두고 넘어간다.

 

 

여기까지 넘어왔으면 반 이상 끝난거다. 일단 람다 함수를 만들고 나서, 기본적으로 설정해주어야 하는 것들이 있다.

  1. 람다 함수의 Permission(권한) 설정
  2. 람다 함수의 트리거 설정
  3. 핸들러 함수와 제한시간, 허용 메모리 설정

먼저 트리거를 설정해보자. 내가 원하는 '일정 시간마다 실행' 트리거는 Event Bridge를 통해 설정할 수 있다. 트리거 추가를 누르고 Event Bridge를 찾아보자.

 

뭐가 많이 있지만 해줄건 많이 없다. 만들어 놓은 규칙이 없으니 'Create a new rule'을 통해 새로운 이벤트 규칙을 설정하고, 이름을 정하면 된다.

 

Rule Type이 중요한데, Event Pattern과 Schedule expression이 존재한다. 이벤트 패턴은 다른 AWS 서비스에서 발생한 특정 이벤트를 트리거 삼는 것이다. 오토 스케일링, EC2 인스턴스 변경사항 등이 있다. 내가 만든 크롤러는 일정 시간 마다 스케줄링 되어야 하므로 Schedule expression을 사용하면 된다.

스케줄은 간단하게 말해서 특정 시간대에 람다를 호출하는 것이다. rate 아니면 cron 표현식으로 구현할 수 있다. rate는 특정 주기마다, cron 표현식은 특정 날짜 및 시간대를 나타낼 수 있다. 일단 공지사항 크롤러니까 rate로 구현하면 되겠다.

rate(1 hours)로 설정하고 넘어간다.

 

다음으로는 람다 권한을 설정해야 한다. S3에 파일을 저장하고 읽어와야 하므로 S3에 대한 권한이 필요하다. 

 

기본적으로 CloudWatch 로그 권한이 있다. 파랗게 나와있는 role 링크를 클릭하면 람다 함수의 role 권한을 설정할 수 있다.

 

클릭하면 이런 화면이 나온다. 당황하지 않고, 권한 정책의 권한 추가에서 정책 연결을 선택하자.

 

s3를 검색하면 이런 권한들이 나온다. 크롤러 람다 람수는 s3에 대한 읽기 쓰기 권한 모두가 필요하므로, AmazonS3FullAccess를 할당하도록 하겠다. (사실 하나씩 부여하는게 더 안전하다.)

 

 

이제 람다 함수 페이지로 다시 넘어오면 다음에서 업로드에서 .zip 파일을 선택하고, 우리가 만든 코드를 압축하고 올리면 된다.

중요한 것은 노드 프로젝트인 경우 node_modules까지 포함하여 업로드해야 한다. 보통 git에는 모듈을 업로드하지 않지만, 람다에서는 라이브러리를 설치할 시간이 없으므로 반드시 같이 업로드해주어야 한다. 라이브러리를 설치하게 되면, 메모리 초과와 시간 제한, 무엇보다 설치하는 시간으로 인한 비용이 부과된다.

업로드를 해주고, 런타임 설정에서 핸들러 옵션을 확인해야 한다. 함수가 여러개인 경우, 실행할 핸들러를 별도로 선택할 수 있다.

index.handler는 index.js의 핸들러를 실행하고, full-crawl.handler는 full-crawl.js의 핸들러를 실행한다. index.js를 실행해야 하므로 그대로 두면 되겠다.

 

마지막으로 메모리와 시간 제한을 설정한다.

기본적으로 이렇게 설정되어 있다. 간단한 함수라면 메모리를 변경하지 않아도 되겠지만, 크롤러는 특성상 웹페이지의 수많은 텍스트를 읽어와야 하므로 128mb 로는 부족할 가능성이 높다. 따라서 256mb로 설정하고, 제한 시간도 넉넉하게 1분으로 설정해주면 된다.

 

이렇게 업로드 되었으면 테스트를 해보자. Test 버튼을 눌러서 테스트 이벤트를 하나 만들고 실행해보면 된다.

터미널에서 성공하였으면 S3도 확인해보자.

잘 업로드된 것을 확인할 수 있다!

이제 몇시간 기다렸다가 트리거가 잘 작동되는지 확인해보면 된다.

 

 

한 시간마다 점박이가 찍히는 것을 보니 트리거도 잘 작동하고 있다. 이제 공지사항이 새로 올라오면 저장이 잘 되는지까지 확인하면 되겠다.

 

마무리

이렇게 간단한 크롤러를 만들어 보았다. 사실 전에 비슷한 게시글 크롤러를 만들어 본적이 있어서 구현하는데 크게 어렵진 않았다.

클라우드 서비스를 하나씩 써보면서 클라우드 활용 능력을 길러보자는 느낌으로 만들어 본 크롤러인데, 생각보다 작동이 잘되어서 굉장히 만족스럽다.

AWS 람다의 장점은 정말 많다. 지금까지는 서버 측에서 구현할 때 모든 것을 하나의 서버 프로그램에 때려박고 EC2에 배포하는 방식으로 운용해왔다. 대학생 단위 프로젝트는 규모가 작으니까 그렇게 해도 상관 없겠지만, 서비스가 커지고 부하가 커지면 결국 MSA 방식으로 서비스가 쪼개질 것이다. 람다 함수는 병렬 처리도 가능하고, 작은 함수 단위로 운용하여 비용을 정말 저렴하게 사용할 수 있다. 지금 만든 크롤러도 하루에 1시간 마다 24번 실행되지만, 비용적으로는 부담이 거의 없는 수준이다. 

클로드가 계산해준 람다 함수 비용 예측

하루에 60초 실행되면 0.35원이고, 30일 내내 실행되어도 10.5원이다. 여기서 비용을 더 최적화 해본다면, 공지사항은 9시부터 6시 사이에만 올라오기 때문에 그 시간대에서만 실행하면 비용은 또 반토막이 난다.

람다는 확장성도 좋고, ECR과도 연동되므로 CD를 구축하기에도 정말 좋다. 만약 SW중심대학 페이지 외에도 다른 단과대를 크롤링해야 한다면, 그냥 사이트 링크만 바꾸고 병렬로 만들어서 재사용해도 된다.

 

앞으로도 AWS를 열심히 공부해야겠다. 백엔드 개발자로서 활용할 수 있는 좋은 인프라가 너무나도 많고, 적절하게 사용하면 비용도 정말 착하게 낼 수 있다.

반응형