Github Action에서 Selenium 실행시키기
목차
1. 개요
Oauth 재연을 실행시키는 시점은 아마 Github를 통해서 가능해야 할 것입니다. 결론적으로는 Oauth를 재연하려면 Redirect 서버가 필요한데 이를 Github에서 처리할 수 있는 방법은 찾지 못했습니다.
https://jakpentest.tistory.com/entry/Obsidian-Github-Github-action을-활용한-티스토리-업로드-자동화
근래에 Obsidian으로 MarkDown을 편집하면 Tistory에 자동으로 포스팅 할 수 있는 시스템을 간략히 만들었습니다.
이 과정에서 Tistory에 글을 업로드 하려면 “Oauth 인증”을 거쳐야헀고 이를 Github Action을 통해 해결할 수 없기에 편법을 이용해 해결했었죠.
Github Action에서 OAuth를 성공시킬 수 없겠다고 판단한 이유는 다음 두 가지 생각 때문이었습니다.
- OAuth는 인증 코드를 받아주는 Redirect 서버가 필요한데 Github Action에서 Redirect Server로 활용할 수 있을까?
- Redirect Server를 배제하더라도 OAuth 인증과정에 따른 API 통신을 재연해 낼 수 있을까?
두 가지 이유들이 오랜 시간을 들인다면 어떻게든 해결방법을 생각해내서 풀어볼 만한 문제로 보이지만 이에 대한 시간 투자 시 배보다 배꼽이 더 커지는 상황이기에 굳이 뛰어들진 않고 편법을 선택했습니다. 지난 글에서도 다뤘듯이 이 편법은 악용하는 사례가 생길 수 있기에 따로 블로그에 기록해두진 않았습니다.
시간이 흐름에 따라 두 가지 문제를 관통하는 해법을 계속 고민하게 되었습니다. 틈틈이 조사를 하던 도중 Github Action에서 Selenium을 실행했다는 글을 보게 되었습니다. 해당 글을 읽고 나서 Selenium을 통해서 해결할 수 있을 것 같단 생각이 머릿속에 스쳤습니다.
2. Selenium으로 접근하기
2.1 Selenium이 어떻게 문제를 해결하는가 ?
Selenium은 HTML element가 동적으로 변경되는 현상에 대해 크롤링을 가능하게 만듭니다. 간단히 표현해 보자면 내 PC에서 브라우저 실행시켜 이를 조작할 수 있도록 도와주는 Manager 역할을 합니다.
Selenium의 이러한 역할 때문에 Browser에 특정 입력을 내릴 수 있을뿐더러 OAuth와 같은 복잡한 통신을 코드 레벨에서 어떻게 다뤄야 할지 신경 쓸 필요가 없습니다. 즉 필자가 풀고자 했던 문제인 Redirect Server 문제와 OAuth 인증 문제를 Selenium을 통해 Browser에서 풀 수 있게 됩니다.
2.2 Selenium 사용을 고려하지 못했던 이유
크롤링을 처음 알게 된 당시에는 돌아가는 Application을 만들기에는 Selenium이 만능이라고 여겼습니다.
그러나 현재에 들어 Selenium을 사용하게 되면 특정 Browser와 Browser에 해당하는 Driver를 필요로 하고 이는 Application이 외부 프로세스를 의존하게 만들어 성능 문제가 야기되어 개인적으로 선호하는 방식이 되진 않았습니다. 또한 Github Action의 컨테이너가 Selenium을 실행가능한지 자체도 의문이 많았습니다.
3. Github Action에서 Selenium 사용하기
본론으로 들어가 Github Action에서 Selenium을 사용할 수 있었던 방법을 적어보고자 합니다. 간략한 순서는 다음과 같습니다.
- 로컬에서 github action 테스트 준비
- chrome 및 chrome driver 준비하기
- xvfb 설정하기
3.1 로컬에서 Github Action 테스트 준비
우선 “act”를 설치해서 Github Action을 로컬에서 테스트할 수 있도록 환경을 갖췄습니다. Github Action이 정상적으로 동작하는지 테스트하려면 매번 “git commit & push”를 해줘야 하고 이는 상당히 귀찮기 때문입니다.
“act”는 Docker를 기반으로 Github Action을 테스트하는 컨테이너를 만듭니다. “act” 사용 전 Docker 컨테이너가 설치되어 있는지 확인해 봅시다.
“act”를 사용하면 다음과 같이 로컬에서 Github Action을 테스트할 수 있게 됩니다.
╭─jako@prompt-pro ~/private/git-repo/tpjt-oauthslack-src ‹master●›
╰─$ act -l
INFO[0000] Using docker host 'unix:///var/run/docker.sock', and daemon socket 'unix:///var/run/docker.sock'
WARN ⚠ You are using Apple M-series chip and you have not specified container architecture, you might encounter issues while running act. If so, try running it with '--container-architecture linux/amd64'. ⚠
Stage Job ID Job name Workflow name Workflow file Events
0 run-selenium run-selenium Run Selenium Script python-package.yml push
“act -l”은 root directory에서 실행 가능한 github action 목록을 보여줍니다. 필자는 Mac m1을 사용 중이기 때문에 act 실행 시 “'--container-architecture linux/amd64” 옵션을 고려해 보라는 경고가 뜹니다. 또한 “act” 사용 시 Docker Setting의 “General” 다음 옵션을 체크했습니다.
Use Rosetta for x86/amd64 emulation on Apple Silicon
Turns on Rosetta to accelerate x86/amd64 binary emulation on Apple Silicon. Note: You must have Virtualization framework enabled.
이로써 Github Action을 테스트할 수 있는 구색을 갖췄습니다.
3.2 Container를 통해 Selenium을 실행하려면 주의하기
Selenium은 Browser와 Browser에 맞는 Driver가 필요합니다. 다시 말하자면 Container를 통해 Selenium을 실행하기 위해선 Container 에도 Browser와 Browser에 맞는 Driver가 필요합니다.
Selenium은 Browser & Browser Driver가 서로 버전이 맞아야 동작합니다. 예를 들어 container 내부에서 apt 명령어로 chrome을 설치했지만 따로 준비한 Chrome Driver 버전이 설치한 chrome 버전과 맞지 않는다면 동작에 실패합니다.
이를 유념하지 않고 Selenium을 실행한다면 다양한 유형의 Error를 맞다고 뜨립니다. 다음은 필자가 이를 신경 쓰지 않고 테스트해서 마주쳤던 Error 메시지입니다.
selenium.common.exceptions.SessionNotCreatedException: Message: session not created: Chrome failed to start: exited normally.
(session not created: DevToolsActivePort file doesn't exist)
(The process started from chrome location /opt/google/chrome/chrome is no longer running, so ChromeDriver is assuming that Chrome has crashed.)
selenium.common.exceptions.NoSuchDriverException: Message: Unable to obtain driver for chrome; For documentation on this error, please visit:
selenium.common.exceptions.WebDriverException: Message: unknown error: Chrome failed to start: exited abnormally.
(unknown error: DevToolsActivePort file doesn't exist)
(The process started from chrome location /usr/bin/google-chrome is no longer running, so ChromeDriver is assuming that Chrome has crashed.)
selenium.common.exceptions.WebDriverException: Message: Service /root/.cache/selenium/chromedriver/linux64/116.0.5845.96/chromedriver unexpectedly exited. status code was: 255
Chrome Driver 설치는 https://googlechromelabs.github.io/chrome-for-testing/ 에서 참고할 수 있었습니다. 해당 사이트에서 버전을 선택해 Github Action Workflow를 통해 다운로드할 수 있도록 선택해 봅시다.
3.3 Github Action에서 Chrome 및 ChromeDriver 준비하기
이제 Github Action을 통해 Browser와 Browser Driver를 준비해 봅시다. 우선 Selenium을 사용하기 위해선 “chrome”이 설치되어야 합니다.
앞서 소개한 “https://googlechromelabs.github.io/chrome-for-testing” 사이트에서 Chrome 버전을 선택해 설치할 수도 있지만 필요한 패키지 목록을 일일이 추적하기 번거롭습니다. 따라서 apt 명령어로 chrome을 설치합니다.
- name: Install Chrome
run: |
set -ex
apt-get update -y
wget <https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb>
sudo apt install -y ./google-chrome-stable_current_amd64.deb
sudo apt-get install -y -f
위 command 대로 chrome을 설치하면 2024/09/22일 기준으로 “129.0.6668.58” 버전의 chrome이 설치됩니다. 여기서 확인된 chrome 버전에 맞는 chrome driver를 설치하는 command는 다음과 같습니다.
- name: Setup ChromeDriver
run: |
apt-get install -y unzip
wget <https://storage.googleapis.com/chrome-for-testing-public/129.0.6668.58/linux64/chromedriver-linux64.zip>
unzip chromedriver-linux64.zip
sudo mv ./chromedriver-linux64/chromedriver /usr/local/bin/
sudo chmod +x /usr/local/bin/chromedriver
가만 보건대 chrome 업데이트 주기를 생각한다면 chrome에 맞는 chrome-driver 버전을 셋업 하는 건 꽤나 귀찮은 일이 되지 않을까 싶네요.
3.4 xvfb 설치하기
chrome과 chromedriver를 설치했으면 이제 가상 디스플레이를 준비해야 합니다. “X 윈도 시스템”이라고도 불리며 이 환경까지 준비가 되어야 비로소 selenium이 실행 가능합니다. xvfb를 설치함으로써 이 준비를 마치면 됩니다.
- name: Setup Xvfb
run : |
sudo apt-get install -y xvfb
Xvfb :99 -ac &
export DISPLAY=:99
3.5 전체 Github Action 파일
앞서 설명한 모든 설정을 마친 후 작성된 workflow 파일은 다음과 같습니다.
name: Run Selenium Script
on:
push:
branches: [ "master" ]
jobs:
run-selenium:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install selenium requests
- name: Install Chrome
run: |
set -ex
sudo apt-get update -y
wget <https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb>
sudo apt install -y ./google-chrome-stable_current_amd64.deb
sudo apt-get install -y -f
- name: Setup ChromeDriver
run: |
wget <https://storage.googleapis.com/chrome-for-testing-public/129.0.6668.58/linux64/chromedriver-linux64.zip>
unzip chromedriver-linux64.zip
sudo mv ./chromedriver-linux64/chromedriver /usr/local/bin/
sudo chmod +x /usr/local/bin/chromedriver
- name: Setup Xvfb
run: |
sudo apt-get install -y xvfb
Xvfb :99 -screen 0 1024x768x24 &
export DISPLAY=:99
4. 마치며
github action에서 selenium을 사용하기 위한 아이디어는 github action에서 Oauth 로그인을 성공시켜 보자라는 개인의 도전 과제로 출발했습니다. 그리고 이는 Obisidian 노트와 티스토리 블로그를 연계시키기 위함에 있었습니다.
즉, Github Action에서 KaKao 로그인을 성공시킬 수 있습니다. 물론 KaKao의 보안 정책을 몇 가지 해제해야 합니다. 그러나 포스팅 자동화를 위해 따로 서버를 가동할 필요가 없다는 점에서 나름 흡족한 결과입니다.