토이 프로젝트/Python 갖고놀기

1일 1커밋 git push 자동화 만들기 - IT 뉴스 사이트 웹 크롤링 && crontab 이용

TerianP 2023. 1. 1.
728x90

본 내용은 오직 공부를 위한 내용이며 제 코드를 복제, 수정하여 사용할때 일어날 수 있는 웹 크롤링과 관련된 불법적인 내용에서는 책임질 수 없습니다

 

1. "개발자는 귀찮아해야 해"

전 회사에서 엑셀 파일로 업무를 하면서 엑셀 함수를 짜는 저를 보신 매니저님께 들었던 이야기였습니다. 사실 당시까지만 해도 "왜...? 귀찮아해야한다는거지?" 라고 궁금해 했었습니다. 그런데 최근에는 조금씩 이해가 가기 시작했습니다. 실제로 귀찮아 해야지만 그걸 어떻게 발전시킬 수 있을지 고민하게되고, 말 그대로 여러가지를 "개발" 할  수 있게 되니까 그런게 아닐까라고 이제서야 조금씩 이해가 가더라구요ㅋㅋ

 

왜 이 이야기를 먼저 꺼냈냐하면 사실 올해 목표로 잡은 것 중 하나가 1일 1커밋 입니다. 아무래도 git 잔디를 관리해야 하고 싶다는 생각이 들어서요ㅋㅋ근데 또 생각해보면 일을 하면서 1일 1커밋이 상당히 어렵다는 걸 느꼈습니다. 일하고 돌아와서 까먹을 때도 있고, 귀찮다고 넘길때도 있고...그렇더라구요.

 

그런데 저는 또 나름 개발자 아니겠습니까?ㅋㅋㅋ

귀찮으면 귀찮지 않도록 만들고 발전시키는게 개발자라면 'git push 자동화'를 목표로 간단한 프로젝트를 시작해봤습니다. 바로 python requests 및 BeautifulSoup 라이브러리와 linux 의 crontab 을 이용한 git push 자동화 프로젝트입니다!!

 

자동으로 git 에 push 를 한다고하더라도 단순한 내용을 push 하기에는 조금 아쉽다는 느낌을 받았습니다. 뭔가 특별한? 내용을 하고 싶었는데 그렇게 생각한 것이 "IT 뉴스 사이트에서 최신 기사의 내용" 을 가져와서 txt 파일로 저장하고 이것을 push 하면 어떨까라는 생각이 들었습니다. 이렇게하면 단순한 내용이 아니라 IT 에 공부에 도움이 되는 내용이고, 나중에 확인하기도 좋고, 심지어 웹 크롤링이라는 것도 공부해볼 수 있으니 1석 3조의 느낌을 만들어봤습니다.

 

또한 이번 프로젝트는 python 으로 해봤습니다. Java 가 아닌 python 을 사용한 이유는 이런 데이터 작업들과 관련해서는 BeautifulSoup 도 그렇고 pandas 도 그렇고 python 이 훨씬 좋기 때문이었습니다.

물론 Java 에서도 JSoup 가 있긴하지만....python 이 더 편하고, 예제가 많아요ㅋㅋ

 

https://github.com/SeJonJ/AutoGitPush

 

GitHub - SeJonJ/AutoGitPush: Auto Git Push everyDay

Auto Git Push everyDay. Contribute to SeJonJ/AutoGitPush development by creating an account on GitHub.

github.com

 

2. 동작 방법

1) https://www.infoq.com/development/news/ 사이트에서 1 page 내용만 크롤링하여 가져옵니다.

2) 크롤링한 내용을 파싱하여 각각 제목, 링크 주소, 간단한 설명으로 분리하여 list 형태로 저장합니다.

3) 이번달에 해당하는 디렉토리가 없는 경우 해당 디렉토리를 생성한 후 오늘 날짜.txt 파일로 크롤링하여 가져온 내용을 저장합니다.

=> /2023-01/2023-01-01.txt

4) git push 를 자동으로 해줄 수 있도록 돕는 bash 스크립트 파일을 만듭니다 => autoPush.sh

5) crontab 을 이용해서 매일 6시에 자동으로 실행 될 수 있도록 합니다. 이때 서버가 계속 살아있어야함으로 aws ec2 를 사용하거나 저처럼 라즈베리 파이 안에서 crontab 을 설정하셔야 합니다.

 

3. python code

1) crawler.py

- requests 와 beautifulsoup 를 이용한 웹 크롤링 하기 위한 python 코드

- header 와 url, res 를 설정한 후 웹에서 내용을 크롤링해와서 결과를 res 변수에 저장한다.

- 이후 soup 의 html.parser 와 soup.select 를 이용해 내가 원하는 값들이 담긴 tag 만 선택해서 내용을 가져온다. 파싱한 내용은 title, href, desc 라는 list 로 저장된다.

- saveText 함수는 text 파일로 저장하기 위한 내용이다. open 함수를 이용해 w - 쓰기 모드 - 로 파일을 열어서 title, href, desc 내용을 하나의 string 으로 만든 뒤 파일에 write 한다.

import requests
from bs4 import BeautifulSoup as bs4
import os

header = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36'
    }

## 다른 사이트를 크롤링하기 위해서는 여기를 수정!!
## 단 다른 사이트는 파라미터를 요구할 수 있기 때문에 그 부분은 추가로 세팅해야함
url = 'https://www.infoq.com/development/news/'
res = requests.get(url, headers=header)

soup = bs4(res.text, 'html.parser')
## select 를 통해서 html 에 있는 각 요소들의 내용을 가져올 수 잇음
## 이때 . 은 html 에서 class 에 해당하며, # 은 html 에서 id 에 해당한다
html1 = soup.select('.cards.no-style.boxes > li > .card__content > .card__data > .card__title > a')
html2 = soup.select('.cards.no-style.boxes > li > .card__content > .card__data > .card__excerpt')

## 모든 내용은 list 로 저장
title = [] # 제목 저장 
href = [] # 링크 저장 
desc = [] # 설명 저장

# 제목 리스트 return
def getTitle():
    for data in html1:
        data.text.replace('\n','')
        data.text.replace('\n\n','')
        ## 파이썬에서 list 에 저장할때는 append 사용 => list.add 와 같은 의미
        title.append(data.text)

    return title

# 링크 리스트 return
def getHref():
    for data in html1:
        href.append(data.attrs['href'])

    return href

# 설명 리스트 return
def getDesc():
    for data in html2:
        desc.append(data.text)

    return desc

# 내용 저장
def saveText(month, filename):
    ## w 는 쓰기 모드로 파일을 연다는 것을 의미
    f = open("./"+month+"/"+filename+".txt", "w")

    ## title 의 길이만큼, 즉 크롤링해온 내용만큼 for 문 시작
    for i in range(len(title)):
        
        ## 저장할 내용을 str 형태로 생성
        ## 반복문이니까 각 list 에서 i 번째 요소를 가져와서 str 로 저장한다
        data = str(i+1)+" 번째 검색 내용 \n"+"제목 : "+title[i]+"\n"+"주소 : https://www.infoq.com/"+href[i]+"\n"+"설명 : "+desc[i]+"\n"

        ## 실제로 파일 f 에 내용을 쓰기 write
        f.write(data)

    f.close()

 

2) createDir.py

- 디렉토리를 생성하는 내용의 코드이다.

- crawler 에 한꺼번에 만들까하다가...서로 다른 내용이기 때문에 그냥 파일도 나눠버렸다.

- 코드는 정말 간단한데 파라미터 - data - 로 넘어온 내용의 경로가 없다면, 그 디렉토리를 생성한다. 

import os

def createDirectory(date):
    try:
        ## 만약 data 라는 경로가 없다면
        if not os.path.exists(date):
            ## 경로 생성
            os.makedirs(date)
    except OSError:
        print("Creation of the directory %s failed" % date)

 

3) main.py

- 메인 파이썬 코드 파일

- 사실 뭐 main 이라고 크게 다른 내용이 있는건 아니고, 그냥 다른 쪽의 파이썬 파일의 코드를 여기서 한번에 실행할 수 있도록 모아두기 위한 파일

- 각각 crawler 의 함수를 실행하여 내용을 크롤링해오고, 디렉토리를 생성하고, 내용을 저장한다.

- 결국 bash 에서 실행할 파일은 main.py 하나면 된다.

import crawler
import createDir as dir
from datetime import datetime

# 사이트에서 내용 크롤링하기
crawler.getTitle()
crawler.getHref()
crawler.getDesc()

# 이번달 디렉토리 없으면 생성
date = datetime.today()
month = date.strftime('%Y-%m')
# print(date)
dir.createDirectory(month)

# 내용 저장
filename = date.strftime('%Y-%m-%d')
crawler.saveText(month, filename)

 

4. gitPush.sh

- git 에 push 를 위한 bash 스크립트 파일

- bash 언어를 처음본다면 낯설수 있지만 사실 크게 어렵지는 않다.

1) cd 로 $sourceDir 에 해당하는 디렉토리로 이동한 뒤 python3 main.py 를 실행한다. 

2) 이후 echo "push Start ~~~ " 의 내용을 현재 디렉토리의 부모 디렉토리에 push.log 라는 이름으로 저장한다.

3) 이후 git  과 관련된 명령어를 칠 때마다 log 에 내용을 저장한다.

4) git commit 내용은 '오늘날짜' new update 로 저장된다

 

- 여기서 가장 중요한 점은github_Id, Token, Address, sourceDir, logFile 에 해당하는 내용을 자신에게 맞게 수정해야한다.

#!/bin/bash

date=`date`
github_Id="github ID"
github_Token="github_Token 내용"
github_Address="github 주소"
sourceDir="소스 주소"
logFile="로그파일 주소 => ../push.log"

## 예시
## github_Id="SeJonJ"
## github_Token="git token"
## github_Address="github.com/SeJonJ/AutoGitPush.git"
## sourceDir="/home/sejon/gitrepo/AutoGitPush"
## logFile="../push.log"

cd $sourceDir

python3 main.py

echo "========= push Start (Date : $date) =========" && echo "========= push Start (Date : $date) =========" >>$logFile 2>&1

git add -A
echo "git add -A" >> $logFile>&1

git commit -m $date"news update"
echo "`git commit -m "$date news update"`" >> $logFile 2>&1

echo "git push!!" >> $logFile 2>&1
git push https://$github_Id:$github_Token@$github_Address >> $logFile 2>&1

echo "========= push OK (Date : $date) =========" && echo "========= push OK (Date : $date) =========" >> $logFile 2>&1

 

- 또한 bash 파일의 권한은 꼭 쓰기 권한이 있어야한다. 따라서 나는 아래 명령어로 권한을 조정하였다.

chmod 750 gitPush.sh

 

5. crontab

- 크론탭은 liunx 에서 가히 최고라고 이야기 할 수 있는 기능이다.

- 쉽게 이야기하자면 특정 "분 시 일 월 요일" 을 지정해서 특정한 내용을 실행시킬 수 있는 기능이다. DB 등을 백업할 때 crontab 에 등록하여 자동으로 백업되게 하는 등 실무에서도 많이 쓰이고, 알아두면 너무너무 좋은 기능 중 하나이다.

- 아는 개발자 형님은 wake on lan 기능을 할 수 있도록 하는 python 코드를 만들 뒤 퇴근 시간이면 자동으로 실행되게 만들어서 집에가면 자동으로 켜져있는 컴퓨터를 볼 수 있다고 한다

crontab -e
## 앞에서부터 분 시 일 월 요일 을 의미한다
## 30분 18시 매일 매월 매요일 gitPush.sh 를 실행한다
30 18 * * * gitPush.sh

 

6. 실행 결과!!

1) 로그 파일 내용

push.log

2) git commit 내용

1분마다 git push 를 설정했을 때

 

 

- Reference

https://velog.io/@johoon815/Git-Git-push-%EC%9E%90%EB%8F%99%ED%99%94-Bash-Shell

 

[Git] Git push 자동화 (Bash Shell) ⚙

Git push를 하기위해 반복되는 루틴을 더는 참을 수가 없었습니다 / Git에 대한 스터디 / 쉘 스크립트를 통한 push

velog.io

 

https://computer-science-student.tistory.com/366

 

[마크다운, Markdown] 코드 블록(code block)

마크다운(Markdown) 코드 블록(code block) 마크다운에서는 ```를 사용해서 코드 블록을 사용할 수 있다. ``` 여기에 코드 넣기 ``` 또 코드 블럭 코드(```) 시작점에 사용하는 언어를 선언하여 문법 강조

computer-science-student.tistory.com

 

https://heehehe-ds.tistory.com/entry/Git-git-clone-%ED%95%A0-%EB%95%8C-username-password-%ED%95%A8%EA%BB%98-%EC%9E%85%EB%A0%A5%ED%95%B4%EC%A3%BC%EA%B8%B0

 

[Git] git clone, push, pull 할 때 username / password 함께 입력해주기

사내 enterprise github를 사용하다 보니 다른 repository에서 git clone을 할 때 번거로운 점이 있었다. 기존 방식대로 git clone 후 git 주소를 입력하면 파일을 다운받을 때마다 username과 password를 입력하라

heehehe-ds.tistory.com

 

https://betatester.tistory.com/22

 

[Linux] 클론탭(crontab) 기본 개념

Crontab 이란 crontab은 스케줄링을 관리하는 프로그램으로 시스템 관리자에게 중요한 유틸 중 하나이다. 특정 시간대에 사용자가 작성한 스트립트나 명령을 실행 할 수 있다. 이는 rsync 같은 툴을

betatester.tistory.com

 

댓글