본문 바로가기
Server/AWS

AWS Lambda 사용기

by print_soo 2024. 6. 25.

근로관련 디스코드 봇을 만들었는데 이 프로그램이 동작할려면 매번 vscode를 실행시켜줘야하다는 문제가 있었다.

이 문제를  AWS Lambda로 해결했다.

 

빠른 요약

1. 람다에서 기본 지원하지 않는 외부 라이브러리를 모두 새로운 폴더에 설치
2. 해당 폴더에 작성한 코드를 람다에서 사용할 코드로 변경후 저장
3. 위의 내용물이 있는 폴더를 zip파일로 압축
4. AWS Lambda 함수를 생성
5. 위에서 생성한 zip파일을 코드 - 코드소스에 zip 파일로 업로드
6. 트리거 추가 후 event bridge 선택
7. event bridge에서 cron으로 규칙생성

 

 

[전체 코드]

import requests
from bs4 import BeautifulSoup
import time
import datetime
import discord
from discord.ext import commands

TOKEN = 'MTI1NDc2NTIyOTM4MDk5NzE1Mw.GN0F-x.DLtpOXyjIpgyNrY7hESFaHVqtzFJBeQdcZ3erM'
CHANNEL_ID = '1254764669856645164'
now = datetime.datetime.now()
url = "<https://www.inu.ac.kr/inu/1534/subview.do>"  # 요청할 웹 페이지의 URL
target_class = "td-date"  # 첫 번째 클래스로 지정된 클래스 이름
target_value = now.strftime("%Y.%m.%d")  # 첫 번째 클래스 요소의 내부에 포함될 값
child_class = "td-subject"  # 상위 요소 아래의 자식 요소에서 찾을 클래스 이름
strong_text = "근로"  # strong 태그 내부에 포함될 텍스트

class MyClient(discord.Client):
    async def on_ready(self):
        channel = self.get_channel(int(CHANNEL_ID))
        while True:  # 무한 루프 설정
                try:
                    # 웹페이지 요청
                    response = requests.get(url)
                    response.raise_for_status()  # 요청에 실패하면 예외 발생

                    # HTML 파싱
                    soup = BeautifulSoup(response.text, 'html.parser')
                    
                    # 특정 클래스를 가진 모든 요소 찾기
                    elements = soup.find_all(class_=target_class)
                    found = False  # 키워드를 찾았는지 여부를 추적

                    # print(f"111elements: '{elements}'")
                    await channel.send(f"-------------------{target_value}-------------------\\n")

                    for element in elements:
                        # 첫 번째 클래스를 가진 요소의 내부 값이 특정 값인지 확인
                        if target_value in element.get_text(strip=True):
                            # print(f"222element: '{element}'")
                            parent = element.find_parent()  # 특정 클래스를 가진 상위 요소 찾기
                            
                            if parent:
                                # 상위 요소 아래에 있는 특정 클래스를 가진 자식 요소 찾기
                                child_elements = parent.find_all(class_=child_class)
                                # print(f"333child_elements: '{child_elements}'")

                                

                                
                                for child in child_elements:
                                    # 자식 요소 아래에 있는 strong 태그 찾기
                                    strong_tag = child.find('strong')
                                    a_tag = child.find('a')
                                    link = a_tag.get('href')

                                    if strong_tag and strong_text in strong_tag.get_text(strip=True):
                                        # strong 태그의 텍스트가 특정 텍스트를 포함하는지 확인
                                        print(f"{strong_tag.get_text(strip=True)}\\nhttps://www.inu.ac.kr{link}\\n\\n")
                                        await channel.send(f"{strong_tag.get_text(strip=True)}\\nhttps://www.inu.ac.kr{link}\\n\\n")
                                        found = True
                                        break
                                    
                                

                    if not found:
                        # 지정된 조건을 만족하는 요소를 찾지 못한 경우 메시지 출력
                        print(f"새로 등록된 근로관련 공지사항이 없습니다.")
                except requests.exceptions.RequestException as e:
                    # 요청 중 예외가 발생한 경우 에러 메시지 출력
                    print(f"Error fetching the URL: {e}")

                time.sleep(3600)  # 1시간 대기 후 다음 반복 실행

intents = discord.Intents.default()
intents.message_content = True
client = MyClient(intents=intents)
client.run(TOKEN)

1. 외부 라이브러리 모두 새로운 폴더에 설치

우선 데스크탑에서 새 파일을 생성한다.

그 파일을 터미널에서 열어 주고 pip 명령어를 통해서 설치를 해준다.

pip install discord.py beautifulsoup4 requests

설치 후 Lambda 함수를 위해서 코드를 수정한다.

 

 

2. 람다함수에서 사용 가능하게 코드 수정해주기

os 라이브러리를 이용해서 환경변수를 사용할 수 있게 해주자.

import requests
from bs4 import BeautifulSoup
import datetime
import discord
import os
from discord.ext import commands

TOKEN = os.environ['DISCORD_TOKEN']
CHANNEL_ID = os.environ['DISCORD_CHANNEL_ID']
url = "<https://www.inu.ac.kr/inu/1534/subview.do>"
target_class = "td-date"
child_class = "td-subject"
strong_text = "근로"

intents = discord.Intents.default()
intents.message_content = True

client = discord.Client(intents=intents)

async def check_announcements():
    now = datetime.datetime.now()
    target_value = now.strftime("%Y.%m.%d")
    channel = client.get_channel(int(CHANNEL_ID))
    try:
        response = requests.get(url)
        response.raise_for_status()

        soup = BeautifulSoup(response.text, 'html.parser')
        elements = soup.find_all(class_=target_class)
        found = False

        await channel.send(f"-------------------{target_value}-------------------\\n")

        for element in elements:
            if target_value in element.get_text(strip=True):
                parent = element.find_parent()
                if parent:
                    child_elements = parent.find_all(class_=child_class)
                    for child in child_elements:
                        strong_tag = child.find('strong')
                        a_tag = child.find('a')
                        link = a_tag.get('href')

                        if strong_tag and strong_text in strong_tag.get_text(strip=True):
                            await channel.send(f"{strong_tag.get_text(strip=True)}\\nhttps://www.inu.ac.kr{link}\\n\\n")
                            found = True
                            break
                    if found:
                        break

        if not found:
            await channel.send(f"새로 등록된 근로관련 공지사항이 없습니다.")
    except requests.exceptions.RequestException as e:
        await channel.send(f"Error fetching the URL: {e}")

@client.event
async def on_ready():
    await check_announcements()
    await client.close()

def lambda_handler(event, context):
    client.run(TOKEN)
    return {
        'statusCode': 200,
        'body': 'Lambda function executed successfully'
    }

 

3. zip파일 압축

해당 코드를 위 외부 라이브러리 설치 폴더에 저장해준 뒤 아래의 명령어로 압축해준다.

zip -r 파일명.zip .

4. 람다 함수 생성

 

위 사진에서 함수 생성을 클릭 본인이 사용할 정보를 기반으로 기본정보를 선택해준다.

그후 함수 생성 클릭

5. zip 파일 업로드

 

코드 - 코드소스 - 에서 업로드 - zip 파일 클릭 후 1번에서 생성한 폴더 업로드

6. 트리거 추가 후 EVENT BRIDGE 선택

 

 

 

7. 규칙생성

 

 

! 예약 표현식에서 주의할 점 !

예약 표현식은 위 사진처럼 cron으로 표현이 된다. 매일 12시에 작동시키고 싶다면 cron(0 0 * * ? *)으로 하면된다. 

다만 AWS EventBridge의 cron 표현식은 UTC(협정 세계시)를 기준으로 한다. 한국 표준시(KST)는 UTC보다 9시간 빠르다.

따라서 실제 한국시간 12시에 작동시키려면 cron(0 15 * *  ? *) 으로 해주면 된다.