루키즈 교육의 막을 열었던 강의 (with 조정원 강사님)
교재는 아래와 같다.
https://product.kyobobook.co.kr/detail/S000001033121
뚝딱뚝딱 파이썬 자동화 | 알 스웨이가트 - 교보문고
뚝딱뚝딱 파이썬 자동화 | 이제 단순 반복 작업은 파이썬으로 해치운다 컴퓨터로 하는 작업 중에서 단순 반복 작업이 의외로 적지 않다. 파일 이름을 일일이 바꾼다거나 스프레드시트 셀을 수천
product.kyobobook.co.kr
굉장히 딱딱하게 적혀있어 추천하진 않음
IT 보안에서의 파이썬
- 모의해킹 오픈 도구(=오픈소스로 만들어진 도구)의 80% 이상이 파이썬이다.
- 자동화 업무에 파이썬이 많이 사용된다.
- 모든 운영체제에서 호환성이 좋다.
Tool - Visual Studio Code
권한 문제로 인해 C:보다 D:에 소스 코드를 두는 것을 권장함
아래는 실습한 파이썬 코드이다.
print("파이썬 웰컴")
print("파이썬", "웰컴", "python")
print("파이썬 \n", "웰컴\n")
print('파이썬 "매우" 웰컴')
print(""" 굉장히 긴 문자열입니다.........
파이썬 화이팅
파이썬자동화
""")
test.py
a = 17
b = "화이팅"
print(type(a))
print(type(b))
# 일반적인 출력
print("파이썬 " + str(a) + "기 " + b)
# format 방식 출력
print("파이썬 {}기 SK쉴더스 {}".format(a,b))
# f-string 방식 출력
print(f"파이썬 {a}기 SK쉴더스 {b}")
input01.py
name = input("이름을 입력하세요 : ")
phone = input("전화번호를 입력하세요 : ")
age = int(input("나이를 입력하세요 : "))
#일반적인 출력
print(name + "의 전화번호는", phone, "입니다", age, "살 입니다.")
#format 메서드
print("{}의 전화번호는 {}입니다. 나이는 {} 살입니다.".format(name,phone,age))
#f-string
print(f"{name}의 전화번호는 {phone} 입니다. 나이는 {age} 살입니다")
input02.py
파이썬의 세 가지 출력 방법
- 일반적인 출력 : 가독성이 떨어질 수 있고, 코드를 작성하기 번거로움
- format 메서드
- f-string : Python 3.6부터 도입된 새로운 문자열 포맷팅 방식으로, 가독성이 좋고 가장 간결하며 직관적임
기본적으로 Python 3.6 이상 버전에서는 f-string을 사용하는 것이 권장된다고 한다.
import googletrans
translator = googletrans.Translator()
input_text = input("한글을 입력하세요")
translated = translator.translate(input_text, dest='en').text
print(f" 한글 입력 값: {input_text}")
print(f" 영어로 번역한 값: {translated}")
trans01.py
googletrans 라이브러리를 이용한 한글 영어 번역 프로그램
(pip install googletrans=3.1.0a0 명령어를 통해 3.1.0a0 버전 패키지 설치 필요)
names = ["조정원", "홍길동", "김철", "정군", "박군"]
#사용자를 추가
name_input = input("추가할 이름은: ")
names.append(name_input)
#사용자 리스트를 출력
for i in range(len(names)):
print(f"인덱스: {i+1}의 이름은: {names[i]}")
list01.py
scores = [10.0, 9.0, 9.5, 7.1, 5, 8.0]
print(f"제거전 {scores}")
scores.remove(max(scores))
scores.remove(min(scores))
print(f"제거후 {scores}")
print(f"평균값: {sum(scores)/len(scores)}")
list02.py
# 성적 입력 프로그램
# 학생 5명의 성적을 입력하여 성적 평균, 최고점수, 최소점수, 평균값을 구한다.
# 80점 이상 학생 수는 count 한다.
STUDENTS = 5
scores = [] # 리스트 초기화
count = 0
for i in range(STUDENTS):
value = int(input(f"{i+1} 번째 성적을 입력하세요."))
scores.append(value)
if value >= 80:
count = count + 1
print(f"합 {sum(scores)}")
print(f"최소점수 {min(scores)}")
print(f"최고점수 {max(scores)}")
print(f"평균값 {sum(scores)/len(scores)}")
print(f"80점 점수 이상 = {count}명")
list03.py
menus = {
"아메리카노": 4000,
"카페라떼": 5000,
"카푸치노": 5000,
"바닐라라떼": 5500,
}
for name in menus.keys():
print(name)
for price in menus.values():
print(price)
selected_menu = input("주문할 메뉴를 입력하세요.")
if selected_menu in menus:
price = menus[selected_menu]
print(f"{price}")
dic_test.py
# 커피 주문 프로그램
# 각 메뉴에 대한 가격 정보를 담은 딕셔너리
menus = {
"아메리카노": 4000,
"카페라떼": 5000,
"카푸치노": 5000,
"바닐라라떼": 5500,
}
# 메뉴 리스트 출력
# .items()를 사용하면 key와 value 값을 자동으로 가져온다.
print(f"==== 메뉴 리스트 ====")
for name, price in menus.items():
print(f"{name}: {price}원")
# 주문한 메뉴들을 담을 리스트
order_list = []
# 주문 반복문
while True:
selected_menu = input("주문할 메뉴를 입력하세요. (종료: 'q')")
if selected_menu == 'q': # 사용자가 'q'를 입력하면 주문 종료
break
else:
order_list.append(selected_menu) # 주문한 메뉴를 리스트에 추가
# 총 주문 금액 계산
total_price = sum(menus[menu_name] for menu_name in order_list)
# 사용자로부터 금액 입력 받기
money = int(input(f"총 금액은 {total_price}원입니다. 입금해주세요: "))
# 거스름돈 계산하여 출력
change = money - total_price
print(f"거스름돈은 {change}원입니다.")
dic01.py
import os
# 파일들이 위치한 디렉토리 경로
dir_path = "D:\\python_sk\\static"
# 디렉토리 내 모든 파일 목록 가져오기
all_files = os.listdir(dir_path)
# .txt 확장자를 가진 파일들을 담을 리스트
txt_files = []
# 전체 파일 목록 출력 및 .txt 확장자를 가진 파일들을 따로 추출
print("전체 파일 목록")
for file in all_files:
print(file)
if file.endswith('.txt'): # .txt 확장자를 가진 파일인지 확인
txt_files.append(file)
# .txt 파일 목록 출력
print("txt 파일 목록:", txt_files)
# 각 .txt 파일을 열어서 내용 출력
for filename in txt_files:
file_path = os.path.join(dir_path, filename) # 파일의 전체 경로 생성
with open(file_path, 'r', encoding='utf-8') as f:
# 파일을 열고 내용 출력
print(f"{filename}의 내용: {f.read()}")
file01.py
파일을 열 때 with open과 open이 있는데 open은 옛날 방식이라고 한다.
open으로 파일을 열면 close 해주지 않을 경우 메모리 누수가 발생할 수 있으므로 위 코드와 같이 with open을 사용하는 것을 권장한다.
이번에는 보안 요소를 생각하며 코딩해보자.
(소스코드에서 주석 처리된 정보들이 중요한 정보라고 가정함)
참고로 파이썬에서 리스트, 집합, 튜플의 구분은 다음과 같다.
실습에서는 set (=집합) 을 사용했다.
- 가변적
- list [] ← ‘-’오퍼레이터가 지원되지 않음
- set {} ← ‘-’오퍼레이터가 지원됨, 중복X
- 불변적
- 튜플 ()
우선 새로 생성된 파일 내에 주석 처리되어 있는 라인이 있는지 검사한다.
import os
import time
# 파일 생성을 모니터링할 디렉토리 경로
DIR_WATCH = "static"
# 이전에 디렉토리에 있는 파일 목록
previous_files = set(os.listdir(DIR_WATCH))
# 무한 루프로 파일 모니터링을 진행
while True:
time.sleep(1) # 1초마다 확인
print("모니터링중")
# 현재 디렉토리에 있는 파일 목록 가져오기
current_files = set(os.listdir(DIR_WATCH))
# 새로운 파일들 찾기
new_files = current_files - previous_files
# 새로운 파일들을 확인하고 주석이 포함된 라인 출력
for filename in new_files:
print(f"====={filename}이 생성됨=====")
file_path = os.path.join(DIR_WATCH, filename)
# 새로 생성된 파일을 읽기 모드로 열고 내용을 확인
with open(file_path, 'r', encoding='utf-8') as f:
lines = f.readlines()
for num, line in enumerate(lines):
if line.startswith("#") or line.startswith("//"):
# 주석으로 시작하는 라인일 경우 출력
print(f"{num+1}줄 주석 처리: {line}")
# 이전 파일 목록을 현재 파일 목록으로 갱신
previous_files = current_files
file02.py
새로운 파일에서 주석처리된 정보가 있으면 보안 담당자의 메일로 자동 통보한다.
# 파일 모니터링
# 새로운 파일에서 주석처리된 정보가 있으면
# 보안 담당자의 메일로 자동 통보
import smtplib # SMTP 라이브러리
from email.header import Header
from email.mime.text import MIMEText
from dotenv import load_dotenv
import os
import time
# 메일 보내기 함수
def mail_sender(file_path, line):
# .env에서 정보 가져오기
load_dotenv()
SECRET_ID = os.getenv("SECRET_ID")
SECRET_PASS = os.getenv("SECRET_PASS")
# 접속 시도
smtp = smtplib.SMTP('smtp.naver.com', 587)
smtp.ehlo()
smtp.starttls()
# 로그인
smtp.login(SECRET_ID, SECRET_PASS)
# 보내는 메일, 받는 메일
myemail = "@naver.com" # 보내는 메일 (보내는 메일의 아이디, 비밀번호 정보는 있어야 함)
youremail = "@naver.com" # 받는 메일
# 보내는 내용
subject = f"파일 탐지 {file_path}" # 제목
message = f"탐지된 결과 : {file_path} : {line}" # 내용
# 인코딩
msg = MIMEText(message.encode('utf-8'), _subtype='plain', _charset='utf-8')
msg['Subject'] = Header(subject.encode('utf-8'), 'utf-8')
msg['From'] = myemail
msg['To'] = youremail
smtp.sendmail(myemail,youremail,msg.as_string())
smtp.quit()
DIR_WATCH = "static"
previous_files = set(os.listdir(DIR_WATCH))
while True:
time.sleep(1)
print("모니터링중")
current_files = set(os.listdir(DIR_WATCH))
new_files = current_files - previous_files
for filename in new_files:
print(f"====={filename}이 생성됨=====")
file_path = os.path.join(DIR_WATCH, filename)
with open(file_path,'r', encoding='utf-8') as f:
lines = f.readlines()
for num, line in enumerate(lines):
#print(line.strip("\n"))
if line.startswith("#") or line.startswith("//"):
print(f"탐지된 결과 : {file_path} : {line}")
mail_sender(file_path, line)
previous_files = current_files
mail01.py
위 코드는 .env 파일을 활용해 소스 코드 내에 개인 정보(아이디, 비밀번호)가 포함되지 않도록 하는 방법이다.
pip install python-dotenv 명령어로 패키지를 설치해 프로젝트의 환경 변수를 .env 파일에 정의하고, 코드에서 이를 로드하여 사용하면 된다.
(패키지 import문은 from dotenv import load_dotenv 이다.)
이처럼 개인정보, 즉 환경 변수는 .env 파일(=설정파일)을 생성해 몰아넣고 깃허브에 올라가지 않도록 해야 한다.
나의 경우 .env 파일의 내용은 다음과 같이 구성했다.
# .env 파일 내용
# 네이버 아이디, 비밀번호
SECRET_ID = "..."
SECRET_PASS = "..."
아래는 보안 담당자에게 통보할 때 해당 주석 내용이 무엇인지 파일을 함께 첨부해서 보내는 코드를 추가한 것이다.
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from dotenv import load_dotenv
import os
import time
# 메일 보내기 함수
def mail_sender(file_path):
# .env 파일에서 이메일 계정 정보 로드
load_dotenv()
SECRET_ID = os.getenv("SECRET_ID")
SECRET_PASS = os.getenv("SECRET_PASS")
# SMTP 서버 연결
smtp = smtplib.SMTP('smtp.naver.com', 587)
smtp.ehlo()
smtp.starttls()
# 이메일 계정으로 로그인
smtp.login(SECRET_ID, SECRET_PASS)
myemail = '@naver.com' # 송신자 이메일 주소
youremail = '@naver.com' # 수신자 이메일 주소
# 이메일 메시지 설정
msg = MIMEMultipart()
msg['Subject'] ="첨부파일 테스트 입니다." # 이메일 제목
msg['From'] = myemail # 송신자 이메일
msg['To'] = youremail # 수신자 이메일
text = """
첨부파일 메일 테스트 내용 입니다.
감사합니다.
"""
contentPart = MIMEText(text)
msg.attach(contentPart)
# 첨부파일 설정
etc_file_path = file_path
with open(etc_file_path, 'rb') as f :
etc_part = MIMEApplication( f.read() )
etc_part.add_header('Content-Disposition','attachment', filename=etc_file_path)
msg.attach(etc_part)
# 이메일 전송
smtp.sendmail(myemail, youremail, msg.as_string())
smtp.quit()
# 모니터링할 디렉토리 경로
DIR_WATCH = "static"
# 이전에 확인된 파일 목록
previous_files = set(os.listdir(DIR_WATCH))
# 주석이 포함된 라인을 저장할 파일
detected_files = "detected_files.txt"
while True:
time.sleep(1) # 1초마다 모니터링
print("모니터링 중")
current_files = set(os.listdir(DIR_WATCH))
new_files = current_files - previous_files
# 새로운 파일을 탐지하면
for filename in new_files:
file_path = os.path.join(DIR_WATCH, filename)
# 파일을 열고 주석이 포함된 라인을 확인하여 detected_files에 저장
with open(file_path, 'r', encoding='utf-8') as f:
lines = f.readlines()
for line in lines:
if line.startswith("#") or line.startswith("//"):
print(f"{file_path} 주석 처리된 라인: {line}")
# detected_files에 주석이 포함된 라인을 추가
with open(detected_files, 'a', encoding='utf-8') as wf:
wf.write(f"{file_path} 주석 처리된 라인: {line}")
# 이메일로 detected_files를 전송
mail_sender(detected_files)
# 현재 파일 목록을 이전 파일 목록으로 업데이트
previous_files = current_files
mail02.py
코드에서 알 수 있듯이 첨부파일을 보내기 위해서 MIMEMultipart()를 사용했는데, MIMEMultipart()는 MIME(Multipurpose Internet Mail Extensions) 형식의 이메일을 생성하기 위한 클래스이다.
꼭 첨부파일이 아니더라도 MIMEMultipart() 객체를 생성하면 이메일의 여러 부분을 조립할 수 있는데,
본문 텍스트, HTML 형식의 본문, 첨부 파일 등 여러 클래스가 존재하며 각각 MIMEText, MIMEImage, MIMEAudio, MIMEApplication 등의 클래스 네임을 사용하면 된다.
'대외활동 > SK Shieldus rookies' 카테고리의 다른 글
[인프라 활용을 위한 파이썬] #5 슬랙 API 활용 및 자동화 (0) | 2024.03.22 |
---|---|
[인프라 활용을 위한 파이썬] #4 FTP 서비스 연결 및 자동화 (0) | 2024.03.12 |
[인프라 활용을 위한 파이썬] #3 엑셀파일 자동화 (0) | 2024.03.10 |
[인프라 활용을 위한 파이썬] #2 웹 크롤링 및 자동화 (0) | 2024.03.07 |