먹고 기도하고 코딩하라

서버에 크론탭 등록해서 자동 크롤링하기 본문

개발일지

서버에 크론탭 등록해서 자동 크롤링하기

사과먹는사람 2020. 5. 30. 13:32
728x90
728x90

 

전에 제가 카카오톡 i 오픈빌더를 파이썬 장고와 Amazon EC2를 이용해서 만든 튜토리얼을 올린 적이 있죠 ^^

 

 

카카오톡 학식봇 만들기(1) - 동적 웹페이지 크롤링 방법이 정적 웹페이지와 다른 이유

안녕하십니까? 이 시리즈는 카카오 i 오픈빌더로 학식 봇을 만드는 과정을 다룹니다. 이 포스팅은 그 중 HTML 페이지 구조 분석을 먼저 합니다. 여기서 다루는 정적 페이지가 아닌 동적 페이지임��

dev-dain.tistory.com

오늘은 보너스 단계의 포스팅입니다. 크론탭을 등록해서 자동으로 크롤링하는 것입니다.

지금도 마찬가지지만 예전에 초창기에는 리눅스에 대한 지식이 부족한 상태에서 일단 뛰어들어 만들었기 때문에 주당 1번씩 수동으로 파이썬 파일을 돌렸습니다. 컴퓨터 매일 하니 별 거 아니긴 하지만 까먹을 때도 있고 오전 수업 있을 때는 좀 귀찮더라고요. 저희 식당이 매번 똑같은 시간에 올려주는 것도 아니고 메뉴가 중간에 바뀔 때도 있거든요. 그래서 화요일 메뉴와 수요일 메뉴가 서로 바뀌었는데 학식알리미에는 똑같다는 불편(?)을 가끔 학교 커뮤니티에서 보곤 했습니다. 그럴 때마다 후다닥 수동으로 고치거나 다시 크롤링하곤 했죠.

하지만 크론탭과 함께라면 그런 수고를 덜 수 있습니다! 지금부터 해봅시다. (*이 튜토리얼은 리눅스 환경에서 가능합니다.)

 


 

일단 저는 Amazon EC2 Ubuntu 16.04 LTS 버전을 쓰고 있습니다. 우분투에서는 이것이 제대로 동작할 것입니다. 만약 Cent OS나 레드햇 등등 다른 운영체제를 쓴다면 각자 맞는 명령어로 바꿔서 써야 할 것입니다.

제 서버 컴퓨터의 디렉토리 구조와 구성은 다음과 같습니다.

$ home directory: /home/ubuntu
$ ls
geckodriver.log	myvenv	geckodriver	haksik_project
$ cd haksik_project && ls
db.sqlite3	haksik	haksik_project	LICENSE	manage.py	README.md
$ cd haksik && ls
admin.py	apps.py	geckodriver.log	__init__.py	migrations	models_py	__pycache__
scrapy_next_page.py	scrapy_page.py	tests.py	views.py	week_info.txt	week_meal.txt

평범한 장고 프로젝트의 구성입니다. 학교 홈페이지에서 학식을 긁어서 각각 week_info.txt와 week_meal.txt 로 저장해야 하는데요. 이 학식을 긁어오는 파일이 scrapy_page.py 입니다. scrapy_next_page.py는 scrapy_page.py와 기본적으로 똑같지만 드라이버로 url을 get한 다음 nextWeekday(1)이라는 '다음주' 버튼을 클릭한 다음의 html 코드를 소스로 긁어온다는 점에서 다릅니다. 이름 그대로 다음주 학식을 미리 가져온다는 뜻이죠. 주로 주말에 미리 실행하게 되는 파일입니다.

주말인 토요일에 scrapy_next_page.py 를 실행하고 싶다면, 토요일까지 기다려서 실행할 수도 있지만 그 날 바빠서 못 하거나 잊어버릴 수도 있습니다. 이럴 때 컴퓨터가 알아서 파일을 실행해준다면 참 좋겠죠? 이렇게 특정한 날짜와 시간을 정해 컴퓨터가 스스로 어떤 작업을 하게 시키려면 크론탭을 사용하면 됩니다.

 

 

배시 파일 만들기

그러려면 컴퓨터가 실행할 스크립트가 있어야겠죠. 우리는 컴퓨터에 배시 스크립트를 실행하게 할 건데, 이 스크립트 안에 특정 폴더로의 이동과 파이썬 파일을 실행할 수 있도록 명령어를 입력할 겁니다. 홈 디렉토리나 원하는 곳에 스크립트(sh) 파일을 만듭니다. 저는 putty로 접속했을 때의 기본 경로인 /home/ubuntu에 만들어보겠습니다.

$ vi autoCrawl.sh

# autoCrawl.sh 내용
#!/bin/sh
source /home/ubuntu/myvenv/bin/activate
cd /home/ubuntu/haksik_project/haksik
python3 scrapy_page.py

 

주석 포함 4줄로 모든 일이 끝났습니다! 정말 간단하죠? 경로는 모두 절대 경로를 줬습니다. 

순서대로 가상환경을 실행시키고 실행시킬 파일이 있는 경로로 이동한 다음 해당 파일을 실행하는 명령어입니다. 만약 더 복잡한 작업을 해야한다면 스크립트를 더 쓰면 되겠죠.

 

 

크론탭 작업 등록

이제 크론탭에 작업 등록을 해봅니다. 작업 등록은 다음 명령어로 열 수 있습니다.

crontab -e

 

이렇게 하면 온통 파란 글씨 주석으로 가득 찬 화면이 나올 텐데요. 크론탭 사용법 설명인데 그 주석을 보지 마시고 인터넷에서 검색해서 문서를 보시길 바랍니다. Reference의 첫 번째 문서를 참고하시기 바랍니다.

저는 다음과 같은 작업을 줬습니다.

#방학중
0 2 * * 1-5 bash /home/ubuntu/autoCrawl.sh >> /home/ubuntu/crawlCron.log 2>&1
#학기중
#*/10 0-2 * * 1-5 bash /home/ubuntu/autoCrawl.sh >> /home/ubuntu/crawlCron.log 2>&1
#주말
0 12 * * 6 bash /home/ubuntu/autoCrawlNext.sh >> /home/ubuntu/crawlCronNext.log 2>&1

 

 

크론탭 사용법

먼저 맨 첫줄부터 살펴볼까요?

0 2 * * 1-5에서 맨 첫번째 숫자 0은 분을 나타냅니다. 여기에 30을 넣게 되면 몇시인지는 모르지만 어쨌든 시계가 30분을 가리킬 때마다 실행한다는 것입니다. 0~59까지 쓸 수 있습니다.

두 번째 숫자 2는 시를 나타냅니다. 여기에 예를 들어 5가 들어가면 05시, 18이 들어가면 18시(오후 6시)에 실행된다는 거죠. 주의할 점은 0~23까지이며 오전 오후로 나뉘는 12시간제가 아니라 24시간제로 써야 한다는 점, 또 서버 시간과 한국 시간이 다르다면 한국 시간으로 언제 실행될지를 서버 시간으로 계산해서 써 줘야 합니다. 제 서버 컴퓨터는 한국 시간보다 9시간이 느리기 때문에 저는 9를 더한 한국 시간 11시에 실행되도록 했습니다.

세 번째 숫자 *는 일을 나타냅니다. 15라고 하면 매월 15일에 실행되는 식이죠. 여기서 '*'는 모든 날짜를 다 선택하는 것을 말합니다. 1~31까지 쓸 수 있습니다.

네 번째 숫자 *는 월을 나타냅니다. 2라고 하면 2월에만 실행된다는 뜻이죠. 1~12까지 쓸 수 있습니다.

마지막 다섯 번째 숫자는 요일입니다. 요일은 0~6(일~토)까지 쓸 수 있습니다. 그런데 좀 특이하죠? 1-5라고 되어 있습니다. 이건 1(월)-5(금)까지 실행한다는 의미입니다. 즉, 주중에만 실행한다는 의미죠. 

 

주석문도 한 번 볼까요? */10이라고 돼 있는데 이건 10분마다 한 번씩 실행한다는 의미입니다. 15,45처럼 써서 매시 15분, 45분이 될 때마다 실행할 수도 있습니다.

 

이렇게 숫자를 다 써주고 나면 그 다음에는 실행할 명령어를 입력합니다. 제 경우에는 bash /home/ubuntu/autoCrawl.sh 입니다.

그런 다음 로그가 저장될 위치와 파일을 지정할 수 있는데요. 저는 처음에 뭔가 잘못돼서 스크립트가 제대로 실행되지 않아 로그 확인이 필요해서 위와 같이 지정했습니다.

>> 는 이 뒤의 인자에 올 파일에 저장하겠다는 의미입니다. >> 뒤에는 로그의 절대 위치와 파일 명을 써주면 됩니다.

 

 

드라이버의 실행 경로 오류 고치기

자 이렇게 써놓으면 고생 끝 행복 시작!일 것 같았지만 저는 그렇지 않았습니다. 파이썬 스크립트가 제대로 실행되지 않는 문제가 생겼거든요. scrapy_page.py와 scrapy_next_page.py가 전부 실행되지 않았습니다. 에러 메시지는 다음과 같았습니다.

 

[Errno 2] No such file or directory: 'geckodriver'

selenium.common.exceptions.WebDriverException: Message: 'geckodriver' executable needs to be in PATH.

 

이 두 가지 에러가 중첩되어 나왔습니다. 어리둥절했죠. geckodriver는 분명 /home/ubuntu 자리에 잘 위치해 있는데 웬 헛소리? 검색하면서 여러 가지 해결법을 시도해봤습니다.

geckodriver를 찾을 수 없다는 것과 PATH에 없다는 게 결과적으로는 똑같은 얘기였습니다. 다소 허무하지만 스크립트 안에 executable_path를 명시하면 해결되는 일이었습니다.

 

# scrapy_page.py 기존 코드
url = 'https://www.duksung.ac.kr/diet/schedule.do?menuId=1151'
options = get_options()	# get_options라는 제가 만들었습니다
driver = webdriver.Firefox(options=options)

driver 옵션에 executable_path가 없습니다. 왜 없냐면 저는 이전 단계에서 설정할 때 export PATH 하면서 그냥 geckodriver PATH를 줘버렸거든요. 그래서 여태까지는 문제가 없었지만, 크론탭에서 실행할 때는 executable_path가 필요했습니다. 다음과 같이 수정했습니다.

 

# 수정 코드
url = 'https://www.duksung.ac.kr/diet/schedule.do?menuId=1151'
options = get_options()	# get_options라는 제가 만들었습니다
driver = webdriver.Firefox(options=options, executable_path=r'/home/ubuntu/geckodriver')

executable_path 를 driver를 열 때마다 명시적으로 줬더니 에러는 사라지고 로그는 깨끗해졌습니다.

또한 아래 문장도 수정했습니다.

 

# scrapy_page.py 기존 코드
meal_fp = open('week_meal.txt', 'w', encoding='utf-8')
info_fp = open('week_info.txt', 'w', encoding='utf-8')
# 수정 코드
meal_fp = open('/home/ubuntu/haksik_project/haksik/week_meal.txt', 'w', encoding='utf-8')
info_fp = open('/home/ubuntu/haksik_project/haksik/week_info.txt', 'w', encoding='utf-8')

open PATH를 제대로 안 주니까 /home/ubuntu 자리에 week_meal.txt 와 week_info.txt 가 생기더라고요. 그래서 아싸리 scrapy_page.py 자체에 열 때부터 절대 경로를 줘서 혼란을 막았습니다.

또한 덮어쓰는 것을 방지하기 위해 exist-remove 했던 것도 절대경로를 줬습니다.

 

if os.path.exists('/home/ubuntu/haksik_project/haksik/week_meal.txt'):
	os.remove('/home/ubuntu/haksik_project/haksik/week_meal.txt')
if os.path.exists('/home/ubuntu/haksik_project/haksik/week_info.txt'):
	os.remove('/home/ubuntu/haksik_project/haksik/week_info.txt')

 

이렇게 하면 크론탭 등록과 로그 남기기까지 끝입니다! 따로 신경써줘야 할 것은 없습니다.

 

 

 

 

Reference

리눅스 반복 예약작업 cron, crond, crontab

[AWS-EC2] 쉘스크립트 작성 후, 크론탭(crontab)에 작업 등록하기

Unable to get Selenium Geckodriver to work on Python - Mac OSX High Sierra

Crontab bash script: no such file or directory

 

728x90
반응형
Comments