본문 바로가기
✒️ Kibwa Voice Phishing Prev Project/Project Development & Ideas

[Flask] Flask 프레임워크를 활용한 Python WebApp 제작

by A Lim Han 2023. 9. 26.

🌍 Groom 을 활용한 Flask WebApp 제작 과정

1. Flask 어플리케이션 생성을 위한 application.py 페이지 제작

# Flask 모듈로부터 필요한 클래스와 함수 임포트
from flask import Flask, render_template, redirect, url_for

# AWS 서비스와 상호작용할 수 있도록 boto3 모듈 임포트
import boto3
import json
import time

# AWS 계정 정보 및 S3 버킷 이름 설정
aws_access_key = 'AWS 엑세스 키 ID'  
aws_secret_key = 'AWS 시크릿 엑세스 키' 
bucket_name = '파일이 위치한 버킷명' 
file_key = '파일명.txt' 

# AWS S3 클라이언트 생성
s3 = boto3.client(
ㅤㅤ's3',
ㅤㅤaws_access_key_id=aws_access_key,
ㅤㅤaws_secret_access_key=aws_secret_key
)

# Flask 애플리케이션 생성
app = Flask(__name__)

# 웹 애플리케이션의 루트 경로 ("/")에 대한 핸들러 함수
@app.route("/")
def main():
ㅤㅤreturn render_template('main.html')  # 'main.html' 템플릿을 렌더링하여 반환

# "/check_value" 경로에 대한 핸들러 함수
@app.route("/check_value")
def check_value():
ㅤㅤtry:
ㅤㅤㅤㅤ# AWS S3에서 파일 내용을 가져오기
ㅤㅤㅤㅤresponse = s3.get_object(Bucket=bucket_name, Key=file_key)
ㅤㅤㅤㅤcontent = response['Body'].read().decode('utf-8')
ㅤㅤㅤㅤvalue = int(content.strip())  # 파일 내용을 정수로 변환

ㅤㅤㅤㅤ# 파일 내용에 따라 다른 응답 반환
ㅤㅤㅤㅤif value == 0: # 판단 결과 '정상'일 경우
ㅤㅤㅤㅤㅤㅤreturn render_template('index.html', value=value)  # 'index.html' 템플릿을 렌더링하여 반환
ㅤㅤㅤㅤelif value == 1: # 판단 결과 '피싱'일 경우
ㅤㅤㅤㅤㅤㅤreturn render_template('report.html')  # 'report.html' 템플릿을 렌더링하여 반환

ㅤㅤㅤㅤexcept Exception as e:
ㅤㅤㅤㅤㅤㅤreturn "Error reading file: {}".format(e)  # 오류가 발생한 경우 오류 메시지 반환

# 애플리케이션을 0.0.0.0 주소와 80번 포트로 실행
if __name__ == "__main__":
ㅤㅤapp.run(host='0.0.0.0', port=80)

2. WebApp의 메인 화면이 될 main.html 페이지 제작

<!DOCTYPE html>
<html>
<head>
ㅤㅤ<title>보이스피싱 탐지 중입니다.</title>
</head>
<body>
ㅤㅤ<div class="container">
ㅤㅤㅤㅤ<div class="background"></div>
ㅤㅤㅤㅤ<h1>조금만 기다려주세요, 보이스피싱 여부를 탐지하는 중입니다.</h1>
ㅤㅤㅤㅤ<img src="/static/stay2.gif" width="280" height="280">
ㅤㅤ</div>
ㅤㅤ<style>
ㅤㅤ/* 스타일 시트 시작 */
ㅤㅤ.container {
ㅤㅤㅤㅤdisplay: flex;
ㅤㅤㅤㅤflex-direction: column; /* 컨테이너 안의 요소들을 세로로 나열 */
ㅤㅤㅤㅤjustify-content: center; /* 세로 중앙 정렬 */
ㅤㅤㅤㅤalign-items: center; /* 가로 중앙 정렬 */
ㅤㅤㅤㅤheight: 100vh; /* 화면 높이의 100%만큼 컨테이너 높이 설정 */
ㅤㅤㅤㅤposition: relative; /* 상대적 위치 지정 */
ㅤㅤㅤㅤbackground-image: url('/static/back.png'); /* 배경 이미지 추가 */
ㅤㅤㅤㅤbackground-size: cover; /* 이미지 크기를 화면에 맞게 조절 */
ㅤㅤ}
       
ㅤㅤ.container h1 {
ㅤㅤㅤㅤfont-size: 36px; /* 텍스트 크기 */
ㅤㅤㅤㅤtext-align: center; /* 텍스트 가운데 정렬 */
ㅤㅤㅤㅤcolor: white; /* 텍스트 색상은 흰색으로 */
    }
</style>
ㅤㅤ<script>
ㅤㅤㅤㅤ// 자바스크립트 시작
ㅤㅤㅤㅤsetTimeout(function() {
ㅤㅤㅤㅤㅤㅤwindow.location.href = '/check_value'; /* 3초 후에 '/check_value'로 이동 */
ㅤㅤㅤㅤ}, 3000);
ㅤㅤㅤㅤ// 자바스크립트 끝
ㅤㅤ</script>
</body>
</html>

 

++  application.py 실행 시 main.html이 출력된 모습

3. 탐지 결과가 '정상'일 경우 이동될 페이지 'index.html' 구현

<!DOCTYPE html>
<html>
<head>
ㅤㅤ<title>정상적인 통화입니다!</title>
</head>
<body>
ㅤㅤ<div class="container">
ㅤㅤㅤㅤ<div class="circle">
ㅤㅤㅤㅤㅤㅤ<img src="/static/bigmovingClo.gif" width="200" height="200">
ㅤㅤㅤㅤ</div>
ㅤㅤㅤㅤ<h1>보이스피싱일 확률이 낮습니다.</h1>
ㅤㅤ</div>
ㅤㅤ<style>
ㅤㅤㅤㅤ.container {
ㅤㅤㅤㅤㅤㅤdisplay: flex;
ㅤㅤㅤㅤㅤㅤflex-direction: column; /* 컨테이너 안의 요소들을 세로로 나열 */
ㅤㅤㅤㅤㅤㅤjustify-content: center; /* 세로 중앙 정렬 */
ㅤㅤㅤㅤㅤㅤalign-items: center; /* 가로 중앙 정렬 */
ㅤㅤㅤㅤㅤㅤheight: 100vh; /* 화면 높이의 100%만큼 컨테이너 높이 설정 */
ㅤㅤㅤㅤㅤㅤbackground-image: url('/static/green.jpg'); /* 배경 이미지 추가 */
ㅤㅤㅤㅤㅤㅤbackground-size: cover; /* 배경 이미지를 화면에 맞게 늘림 */
ㅤㅤㅤㅤㅤㅤbackground-position: center;
ㅤㅤㅤㅤㅤㅤbackground-repeat: no-repeat; /* 배경 이미지 반복 없음 */
ㅤㅤㅤㅤ}

ㅤㅤㅤㅤ.circle {
ㅤㅤㅤㅤㅤㅤwidth: 300px;
ㅤㅤㅤㅤㅤㅤheight: 300px;
ㅤㅤㅤㅤㅤㅤborder-radius: 50%; /* 원 모양 요소 생성 */
ㅤㅤㅤㅤㅤㅤbackground: #b7edb7; /* 동그라미 배경색 지정 */
ㅤㅤㅤㅤㅤㅤdisplay: flex;
ㅤㅤㅤㅤㅤㅤjustify-content: center; /* 가로 중앙 정렬 */
ㅤㅤㅤㅤㅤㅤalign-items: center; /* 세로 중앙 정렬 */
ㅤㅤㅤㅤㅤㅤbackground-position: center; /* 이미지 가운데 정렬 */
        }

ㅤㅤㅤㅤ.circle img {
ㅤㅤㅤㅤㅤㅤmax-width: 100%;
ㅤㅤㅤㅤㅤㅤmax-height: 100%; /* 이미지 크기를 최대한 활용하도록 설정 */
ㅤㅤㅤㅤ}
        
ㅤㅤㅤㅤ.header {
ㅤㅤㅤㅤㅤㅤfont-size: 24px;
ㅤㅤㅤㅤㅤㅤtext-align: center;
ㅤㅤㅤㅤ}
ㅤㅤ</style>
ㅤㅤ<script>
ㅤㅤㅤㅤNotification.requestPermission(); // 데스크톱 알림 권한 요청

ㅤㅤㅤㅤvar permission = Notification.requestPermission();
ㅤㅤㅤㅤconsole.log(permission)

ㅤㅤㅤㅤfunction getNotificationPermission() {
ㅤㅤㅤㅤㅤㅤ// 브라우저가 데스크톱 알림을 지원하는지 체크
ㅤㅤㅤㅤㅤㅤif (!("Notification" in window)) {
ㅤㅤㅤㅤㅤㅤㅤㅤalert("데스크톱 알림을 지원하지 않는 브라우저입니다.");
ㅤㅤㅤㅤㅤㅤ}

ㅤㅤㅤㅤㅤㅤ// 데스크톱 알림 권한을 요청하고 권한에 따라 알림을 허용 또는 거부
ㅤㅤㅤㅤㅤㅤNotification.requestPermission(function (result) {
ㅤㅤㅤㅤㅤㅤㅤㅤif (result == 'denied') {
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤNotification.requestPermission(); // 권한이 거부되었을 경우 재요청
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤalert('알림을 차단하셨습니다.\n브라우저의 사이트 설정에서 변경하실 수 있습니다.');
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤreturn false;
ㅤㅤㅤㅤㅤㅤㅤㅤ} else if (result == 'granted') {
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤalert('알림을 허용하셨습니다.');
ㅤㅤㅤㅤㅤㅤㅤㅤ}
ㅤㅤㅤㅤㅤㅤ});
ㅤㅤㅤㅤ}

ㅤㅤㅤㅤ// 새로운 데스크톱 알림을 생성
ㅤㅤㅤㅤnew Notification("피싱 알람", { body: '피싱으로부터 안전합니다.', badge: '/static/fish.png', icon: '/static/clo.png' });
ㅤㅤ</script>
</body>
</html>

 

++  index.html 렌더링 시 출력되는 페이지의 모습

4. 탐지 결과가 '피싱'일 경우 이동될 페이지 'report.html' 구현

<!DOCTYPE html>
<html>
<head>
ㅤㅤ<title>Report</title>
ㅤㅤ<link rel="stylesheet" type="text/css" href="styles.css">
ㅤㅤ<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
ㅤㅤ<script src="https://cdn.jsdelivr.net/npm/sweetalert2@10"></script>
ㅤㅤ<meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- 모바일 화면 크기에 맞게 조정 -->
</head>
<body>
ㅤㅤ<div class="container">
ㅤㅤㅤㅤ<div class="circle">
ㅤㅤㅤㅤㅤㅤ<img src="/static/remo.png" alt="Your Image" width="220" height="220">
ㅤㅤㅤㅤ</div>
ㅤㅤㅤㅤ<h1 class="header">보이스피싱일 가능성이 높습니다!</h1>
ㅤㅤㅤㅤ<button id="confirmStart" class="report-button">신고를 원하시는 경우 이 버튼을 클릭해주세요</button>
ㅤㅤ</div>
ㅤㅤ<style>
ㅤㅤ.container {
ㅤㅤㅤㅤdisplay: flex;
ㅤㅤㅤㅤflex-direction: column; /* 요소들을 세로로 배치 */
ㅤㅤㅤㅤjustify-content: center; /* 세로 중앙 정렬 */
ㅤㅤㅤㅤalign-items: center; /* 가로 중앙 정렬 */
ㅤㅤㅤㅤheight: 100vh; /* 화면 높이의 100%로 컨테이너 높이 설정 */
ㅤㅤㅤㅤbackground-image: url('/static/red2.jpg'); /* 배경 이미지 추가 */
ㅤㅤㅤㅤbackground-size: cover; /* 배경 이미지를 화면에 맞게 조절 */
ㅤㅤㅤㅤbackground-position: center;
ㅤㅤㅤㅤbackground-repeat: no-repeat; /* 배경 이미지 반복 없음 */
ㅤㅤ}

ㅤㅤ.header {
ㅤㅤㅤㅤfont-size: 24px;
ㅤㅤㅤㅤtext-align: center; /* 텍스트 가운데 정렬 */
ㅤㅤ}
            
ㅤㅤ.circle {
ㅤㅤㅤㅤwidth: 300px;
ㅤㅤㅤㅤheight: 300px;
ㅤㅤㅤㅤborder-radius: 50%; /* 원 모양의 동그라미 생성 */
ㅤㅤㅤㅤbackground: #DF0101; /* 동그라미 배경색 설정 */
ㅤㅤㅤㅤdisplay: flex;
ㅤㅤㅤㅤjustify-content: center; /* 가로 중앙 정렬 */
ㅤㅤㅤㅤalign-items: center; /* 세로 중앙 정렬 */
ㅤㅤㅤㅤbackground-position: center;
ㅤㅤ}

ㅤㅤ.circle img {
ㅤㅤㅤㅤmax-width: 100%;
ㅤㅤㅤㅤmax-height: 100%; /* 이미지 크기를 최대한 활용 */
ㅤㅤ}

ㅤㅤ.report-button {
ㅤㅤㅤㅤbackground-color: #D8D8D8;
ㅤㅤㅤㅤcolor: #000000;
ㅤㅤㅤㅤwidth: 80%; /* 모바일 화면에 맞게 너비 조정 */
ㅤㅤㅤㅤmax-width: 400px; /* 최대 너비 설정 */
ㅤㅤㅤㅤheight: 50px;
ㅤㅤㅤㅤborder-radius: 25px; /* 버튼 모서리를 둥글게 만듭니다. */
ㅤㅤㅤㅤfont-size: 15px;
ㅤㅤ}
ㅤㅤ</style>
ㅤㅤ<script>
ㅤㅤㅤㅤ// jQuery를 사용하여 문서가 준비되면 실행되는 함수
ㅤㅤㅤㅤ$(document).ready(function() {
ㅤㅤㅤㅤㅤㅤ// 버튼 클릭 시 SweetAlert2 팝업 창 표시
ㅤㅤㅤㅤㅤㅤ$("#confirmStart").click(function() {
ㅤㅤㅤㅤㅤㅤㅤㅤSwal.fire({
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤtitle: '해당 통화를 신고하시겠습니까?',
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤtext: '해당 통화는 보이스피싱일 가능성이 높습니다.',
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤicon: 'warning',
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤshowCancelButton: true,
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤconfirmButtonColor: '#3085d6',
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤcancelButtonColor: '#d33',
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤconfirmButtonText: '확인',
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤcancelButtonText: '취소'
ㅤㅤㅤㅤㅤㅤㅤㅤ}).then((result) => {
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤif (result.isConfirmed) {
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤSwal.fire(
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ'신고가 접수되었습니다.',
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ'보이스피싱에 유의하시길 바랍니다.',
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ'success'
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ)
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ}
ㅤㅤㅤㅤㅤㅤㅤㅤ});
ㅤㅤㅤㅤㅤㅤ});
ㅤㅤㅤㅤ});
ㅤㅤ</script>
ㅤㅤ<script>
ㅤㅤNotification.requestPermission(); // 알림 권한 요청

ㅤㅤvar permission = Notification.requestPermission();
ㅤㅤconsole.log(permission)
ㅤㅤ// 알림 권한 요청 함수 정의
ㅤㅤfunction getNotificationPermission() {
ㅤㅤㅤㅤ// 브라우저가 데스크톱 알림을 지원하는지 확인
ㅤㅤㅤㅤif (!("Notification" in window)) {
ㅤㅤㅤㅤㅤㅤalert("데스크톱 알림을 지원하지 않는 브라우저입니다.");
ㅤㅤㅤㅤ}
ㅤㅤㅤㅤ// 데스크톱 알림 권한 요청
ㅤㅤㅤㅤNotification.requestPermission(function (result) {
ㅤㅤㅤㅤㅤㅤ// 권한 거부 시 재요청
ㅤㅤㅤㅤㅤㅤif(result == 'denied') {
ㅤㅤㅤㅤㅤㅤㅤㅤNotification.requestPermission();
ㅤㅤㅤㅤㅤㅤㅤㅤalert('알림을 차단하셨습니다.\n브라우저의 사이트 설정에서 변경하실 수 있습니다.');
ㅤㅤㅤㅤㅤㅤㅤㅤreturn false;
ㅤㅤㅤㅤㅤㅤ}
ㅤㅤㅤㅤㅤㅤelse if (result == 'granted'){
ㅤㅤㅤㅤㅤㅤㅤㅤalert('알림을 허용하셨습니다.');
ㅤㅤㅤㅤㅤㅤ}
ㅤㅤㅤㅤ});
ㅤㅤ}
    
ㅤㅤ// 새로운 데스크톱 알림 생성
ㅤㅤnew Notification("피싱 알람", {body:'피싱으로부터 위험합니다.',badge : '/static/fish.png',icon : '/static/alert.png'});
ㅤㅤ</script>

</body>
</html>

 

++  report.html 렌더링 시 출력되는 페이지의 모습

5. 기타 스타일 지정을 위한 style.css 파일 생성

/* styles.css */

body {
ㅤㅤfont-family: Arial, sans-serif;
ㅤㅤbackground-color: #f5f5f5;
ㅤㅤmargin: 0;
ㅤㅤpadding: 0;
}

.container {
ㅤㅤmax-width: 600px;
ㅤㅤmargin: 0 auto;
ㅤㅤpadding: 20px;
ㅤㅤbackground-color: #fff;
ㅤㅤborder: 1px solid #ccc;
ㅤㅤborder-radius: 5px;
ㅤㅤbox-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
ㅤㅤtext-align: center;
}

.header {
ㅤㅤcolor: #ff6347;
ㅤㅤfont-size: 24px;
ㅤㅤmargin-bottom: 20px;
}

.report-button {
ㅤㅤbackground-color: #ff6347;
ㅤㅤcolor: #fff;
ㅤㅤborder: none;
ㅤㅤpadding: 10px 20px;
ㅤㅤfont-size: 16px;
ㅤㅤcursor: pointer;
ㅤㅤborder-radius: 5px;
}

.report-button:hover {
ㅤㅤbackground-color: #ff4500;
}

 


🌍 Flask WebApp 기타 정보

#  Flask 어플리케이션 파일 구조

 


#  Flask 어플리케이션 전체 실행 프로세스