자동으로 스터디 모집 글을 모아 알림을 주는 파이썬 크롤러 만들기(with Github Actions)

이번 설 연휴 동안 다짐했던 목표가 있었습니다. 바로 파이썬 공부 시작과 함께 파이썬 크롤러 만들기! 파이썬 기본 문법과 자료구조를 빠르게 공부한 뒤, 바로 파이썬 크롤러 만들기에 들어갔습니다. 파이썬 크롤러 코드가 이해가 되고 해보고 싶은 만큼 조금씩 변형해볼 수 있으니 너무 재밌었습니다.

이번에 단순히 크롤링하는 라이브러리를 익혀보는 것으로 끝내기보다, 평소 갈증이 있었던 스터디 모집 새글 알림을 받도록하는 크롤링을 목표로 발전시켰습니다. 그럼 이번 공부를 아웃풋 할 수 있을 것 같았습니다. 그래서 Python + Github Issue + Github Actions를 이용하여 진행하기로 했습니다.

  1. 파이썬 문법 기초 익히기 + 파이썬 크롤러 만들기
  2. 스터디 모집 글 크롤링하기
  3. 주기적으로 정해진 시각이 크롤러 동작하기
  4. 새글이 있다면 핸드폰으로 알림 받기

이 크롤러 코드는 Github에 오픈해두었습니다 :)

1. 크롤링 사이트의 html 구조 살펴보기

okky - 정기모임/스터디

오늘 우리가 크롤링해볼 사이트는 okky - 정기모임/스터디 게시판입니다. 해당 페이지에서 인터넷 브라우저의 개발자 도구를 이용해 html 구조를 확인해봅니다.

게시글 html code

html code 스크린샷의 두번째 줄의 div가 list-article이라는 id를 가지고 있네요. html tag의 id값은 페이지 내에서 고유하므로 우리는 여기서부터 태그 계층 구조를 시작하려고 합니다. 코드 내 < !— Table — > 주석이 있고 그 아래 ul 태그 부분이 글 작성 시각을 역순으로 정렬한 최신 스터디 모집 게시글 리스트 부분입니다.

#list-article > div > ul > li.list-group-item

제목과 작성 시각 html code
li element는 글 1개와 대응되는데, 이 안에는 링크와 제목, 글 작성 시각이 담겨있습니다. h5 태그 안에는 제목과 링크가 있고, data-created class를 갖는 div 밑에 span.timeago 태그 안에 작성 시각이 있습니다. 글 작성 시각이 필요한 이유는 당일에 작성된 글만 필터하기 위함입니다.

이렇게 화면에서 보여진 정보를 html 소스 코드 내에서 위치를 찾고 필요한 정보가 있는지 확인하는 시간을 가져 준비를 끝냈습니다.

2. 파이썬 크롤러 만들기

크롤러 만들기 할일을 리스트업하면 다음과 같습니다.

  1. okky 사이트를 호출하여 응답을 받아온다.
  2. bs4를 이용하여 응답 결과를 html tag 타입으로 파싱한다.
  3. 게시글(li) tag elements를 list로 담는다.
  4. 마감이란 텍스트가 포함된 글 역시 제외하고 대상 글들만 모은다.
  5. KST로 timezone을 설정한다.
  6. 기준 시각부터 하루 전 사이에 작성된 글만 추출한다.
  7. 오늘 작성된 글이 있다면 Github issue로 등록하여 메일로 알림을 받는다.
  8. 매일 정해진 시각에 자동으로 파이썬 크롤러가 작동되도록 github actions를 만든다.

과정을 구체적으로 나누다 보니 단계가 많지만 사실 매우 간단합니다. 그럼 바로 시작해보죠!

필요한 파이썬 라이브러리를 import

필요한 라이브러리들의 사용 목적을 간략히 정리해보면,

  • urllib
    • 지정한 url을 호출하고 돌려받은 응답을 담기 위함
  • bs4(Beautiful Soup)
    • Beautiful Soup은 HTML 구문 분석하기 위함
  • github
    • github에 issue 생성하기 위함
  • datetime
    • 현재 시각과 시간 포멧팅을 하기 위함
  • pytz
    • 타임 존을 사용하기 위함
  • dateutil.parser
    • 문자열 날짜를 date로 변환하기 위함
  • os
    • 환경 변수를 사용하기 위함

여기서 github, os, pytz는 알림을 받기 위해 필요한 것이므로 개발 스펙에 따라 없어도 무방합니다.

게시글 리스트를 추출

1 - okky 사이트를 호출하여 응답을 받아온다.
2 - bs4를 이용하여 응답 결과를 html tag 타입으로 파싱한다.
3 - 게시글(li) tag elements를 list로 담는다.

이 단계는 할일 1~3까지의 과정입니다. 처음에 li element가 글 1개에 대응된다고 했었던 것을 기억하실 겁니다. 위 코드에서 select()메서드는 리턴 타입이 array입니다. 즉, article_list에는 게시글이 여러개 담겨 있습니다.

필요한 게시글만 추출하기

4 - 마감이란 텍스트가 포함된 글 역시 제외하고 대상 글들만 모은다.
5 - KST로 timezone을 설정한다.
6 - 기준 시각부터 하루 전 사이에 작성된 글만 추출한다.

이 단계는 할일 4~6까지의 과정입니다. article_list는 array형태기 때문에 반복문으로 각 row마다 전처리를 합니다.
row는 앞서 언급한 li element입니다. 이 row 역시 html tag 타입이기 때문에 하위 태그들을 다시 선택할 수 있습니다.

대상 글들만 필터하기 위해 날짜 구현 부를 살펴보겠습니다. 이 크롤러가 작동할 서버의 타임 존은 UTC(Github)로 날짜 생성시 KST 타임 존 설정해줘야 합니다. 타임 존을 설정하지 않을 경우, today가 글이 작성된 KST보다 과거 시간이기 때문에 일부 글들은 누락 될 수 있습니다. isDateInRange() 함수를 정의하여 날짜 계산을 합니다. 대상은 24시간 전 ~ 작동 시간

더불어 모집이 끝난 게시글은 대부분 마감이란 텍스트가 포함되므로 마감된 모집 글을 제외하는 로직도 추가합니다. 이제 대상이 되는 글들은 따로 변수에 담아 분류합니다. 이 내용은 Github issue의 내용으로 사용합니다.

3. Github issue로 등록하기

7 - 오늘 작성된 글이 있다면 Github issue로 등록하여 메일로 알림을 받는다.

깃허브 이슈는 등록되거나 이슈에 새로운 코멘트가 달렸을 때 이메일로 알림을 받을 수 있습니다. 이 점을 이용하면 따로 Notification server를 구축하지 않고 손쉽게 알림을 받을 수 있습니다.
깃허브 이슈를 생성하기 위해서는 2가지가 필요합니다.

  • 이슈를 등록할 레포지토리
  • 깃허브 접근 권한이 있는 토큰

토큰은 Github Tokens에서 발급할 수 있습니다. 하지만 토큰을 코드상에 직접 하드코딩하는 것은 매우 위험합니다. 현업에서도 이와 같이 민감한 값은 암호화에서 코드상에서 분리하여 관리합니다. 깃허브에서도 동일한 기능을 제공하는데 바로 secrets1입니다.

secrets에 등록한 값은 추후 Github Actions에서 사용할 예정이고 값은 ENV에 담았기 때문에 os 모듈을 이용하여 토큰 값을 가져옵니다. 가져온 토큰을 이용하여 Github issue를 생성합니다.

파이썬 코드로 생성한 Github issue
이메일로 알림

4. Github Actions으로 파이썬 크롤링 자동화하기

8 - 매일 정해진 시각에 자동으로 파이썬 크롤러가 작동되도록 github actions를 만든다.

Github Actions란?

config.yml

GitHub Actions는 워크 플로우 모든 단계에 통합된 강력한 실행 환경을 제공합니다. 원하는 작업을 수행하기위한 작업을 검색, 생성 및 공유하고 이를 결합하여 워크 플로우를 커스텀할 수 있습니다.2

YAML 설정

파이썬을 일정 시각마다 자동으로 실행하고, 필요한 라이브러리 디펜던시를 명세합니다. 또한 미리 발행하여 secrets에 저장한 Github Token을 환경 변수에 설정 할 수 있습니다. 해당 잡이 도는 시각은 UTC 기준이므로 cron 패턴 작성시 유의하시면 됩니다. 우리는 KST기준 오후 6시에 한 번 수행하도록 셋팅했습니다.

config.yml

name: ['크롤러 이름']

on:
  schedule:
    - cron: ['분 시간 월 일 년'] UTC임을 유의

jobs:
  run:
    runs-on: ['운영체제']
    steps: // job이 실행되었을 때 처리 단계
      - uses: actions/checkout@v1 // 최신의 커밋으로 가져옴
      - name: Set up Python  // 파이썬 설치
        uses: actions/setup-python@v1 // 최신의 파이썬 버전 설치
      - name: Install dependencies  // 파이썬 필요 라이브러리
        run: |
          pip install --upgrade pip // pip version up
          pip install beautifulsoup4 // bs4 설치
          pip install pytz // 타임 존 설치
          pip install PyGithub // github 설치
          pip install python-dateutil // 날짜 파서 설치
      - name: Run Crawler  // 실제 파이썬 크롤러 실행 단계
        run: |
          python crwaler.py // github repo root 경로임
        env:
          GITHUB_TOKEN: ${{ secrets.GithubToken }} // secrets에 등록해둔 토큰을 환경변수로 셋팅

자동으로 실행된 액션은 단계별 진행상황을 확인할 수 있습니다. 만약 job이 실패하면 즉시 메일 알림이 오기 때문에 잡이 깨지는 경우를 놓치지 않을 수 있어서 좋습니다.
Github Action log

마치며

오늘 함께 만들어본 크롤러는 매우 작고 귀엽지만 단순히 파이썬 크롤러를 만들어보는 것에 그치지 않고 자동화로 발전시켜 더욱 흥미로운 토이 프로젝트가 되었습니다. 지금은 스터디 게시판이 okky 한 곳이지만, 다른 사이트도 계속해서 추가하여 더 디벨롭하려고 합니다. 미뤄왔던 파이썬을 익혀보고 아웃풋까지 낸 이번 프로젝트를 통해 크롤링의 세계로 입문해보시면 어떨까요?
다른 스터디 모집 게시판이 있다면 댓글로 남겨주세요! 해당 사이트도 추가해보겠습니다 :)

참고로 baekdev/crawler-study-gathering 레포지토리를 Watching하시면 스터디 모집 글 모음 알림을 받을 수 있습니다!

참고 할만한 글


  1. Encrypted secrets allow you to store sensitive information, such as access tokens, in your repository. Github Secrets
  2. GitHub Actions features a powerful execution environment integrated into every step of your workflow. You can discover, create, and share actions to perform any job you’d like, and combine them to customize your workflow. Github Actions