본문 바로가기
TIL/웹 초보

23.05.12

by J1-H00N 2023. 5. 12.

웹개발 종합반 fetch ~ DB 복습

 

vision5팀과의 미니프로젝트를 마치고 오늘부터는 다음주에 새로 시작할 미니프로젝트에 대비하기 위해 웹개발종합반 강의를 정주행할 계획이다.

 

html에서 fetch로 데이터 가져오기

fetch("데이터를 가져올 루트(api url, 백엔드 post 루트 ...)").then(res => res.json()).then(data => {
                let temp = data['루트에서 가져올 데이터 종류']
                $('#temp').text(temp) // id='temp'에 temp에서 text가져와 붙이기
            })

ex)

fetch("http://spartacodingclub.shop/sparta_api/weather/seoul").then(res => res.json()).then(data => {
                let temp = data['temp']
                $('#temp').text(temp)
            })

 

크롤링 기본 셋팅 여기서 (url은 프론트엔드에서 url을 받아올 수 있다)

import requests
from bs4 import BeautifulSoup

URL = "크롤링 할 사이트의 url" 
headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}
data = requests.get(URL, headers=headers) # url의 데이터를 읽어오는 기능
soup = BeautifulSoup(data.text, 'html.parser') # index.html 내용 읽는 기능

원하는 데이터 크롤링

변수 이름 = soup.select_one('사이트 원하는 데이터 검사 페이지에서 우클릭 -> selector 복사')

변수 이름.text # 변수 내 정보 중 text만 가져오기
변수 이름['href'] # 변수 내 정보 중 href(데이터 url) 가져오기

원하는 종류의 데이터만 여러개 가져오기 예시

lis = soup.select('#mainContent > div > div.box_ranking > ol > li') # 가져오려는 데이터들이 공통적으로 가지고 있는 경로

#mainContent > div > div.box_ranking > ol > li:nth-child(1) > div > div.thumb_item > div.poster_info > a
# 제목이 있는 데이터의 selector
#mainContent > div > div.box_ranking > ol > li:nth-child(1) > div > div.thumb_cont > span.txt_append > span:nth-child(1) > span
# 별점이 있는 데이터의 selector
#mainContent > div > div.box_ranking > ol > li:nth-child(1) > div > div.thumb_item > div.poster_movie > span.rank_num
# 순위가 있는 데이터의 selector
for li in lis:
    a = li.select_one('div > div.thumb_cont > strong > a') # 겹치지 않는 부분만 lis에서 추가
    title = a.text
    span = li.select_one('div > div.thumb_cont > span.txt_append > span:nth-child(1) > span')
    star = span.text
    rank_num = li.select_one('div > div.thumb_item > div.poster_movie > span.rank_num')
    rank = rank_num.text
    doc = {
        'title' : title,
        'rank' : rank,
        'star' : star
    }
    db.movies.insert_one(doc) # 위 형태의 데이터 movies라는 데이터베이스 컬렉션에 하나씩 저장

 

mongoDB 연결

더보기

데이터 베이스 삭제, Database Access 삭제, Network Access 삭제

데이터 베이스 생성 => (학습용)shared => aws, seoul확인하고 생성

=> username, password 지정(password는 코드에서도 쓰이니 간단한걸로)

=> IP address 0.0.0.0(어디서든 접속 가능) 저장 => app.py에서 pymongo, dnspython install =>

from pymongo import MongoClient
client = MongoClient('여기에 URL 입력')
db = client.dbsparta # dbsparta는 컬렉션 이름이므로 상황에 따라 적당한 이름 선택

url 입력 후 <password>에 데이터베이스 생성시 지정한 password 입력

 

pymongo 코드 요약

# 저장 - 예시
doc = {'name':'bobby','age':21}
db.users.insert_one(doc)

# 한 개 찾기 - 예시
user = db.users.find_one({'name':'bobby'})

# 여러개 찾기 - 예시 ( _id 값은 제외하고 출력) (_id 값이 필요한경우는 {'_id':False} 지우기) <= 데이터 수정, 삭제 시 필요
all_users = list(db.users.find({},{'_id':False}))

# 바꾸기 - 예시
db.users.update_one({'name':'bobby'},{'$set':{'age':19}}) # 보통 여기서 _id 이용

# 지우기 - 예시
db.users.delete_one({'name':'bobby'}) # 보통 여기서 _id 이용

 

Flask - 서버 만들기

가상 환경 만들기

python -m venv venv

pip install flask

flask 기본 세팅 코드

from flask import Flask
app = Flask(__name__)

@app.route('/') # localhost:5000
def home(): # localhost:5000에 접속하자마자 실행할 함수
   return 'This is Home!'

if __name__ == '__main__':  
   app.run('0.0.0.0',port=5000,debug=True) # localhost:5000에서 실행

 

@app.route('/mypage') # localhost:5000/mypage
def home(): # localhost:5000/mypage에 접속하자마자 실행할 함수
   return 'This is Mypage!'

 

서버와 html 연결하기

통상적으로 templates라는 폴더를 만든뒤 index.html이라는 하위 파일을 만들어 연결

연결 예시

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <title>Document</title>

    <script>
        function hey(){
            alert('안녕!')
        }
    </script>
</head>
<body>
    <button onclick="hey()">나는 버튼!</button> # 버튼을 클릭 시 hey()함수 실행
</body>
</html>

app.py

from flask import Flask
app = Flask(__name__)

@app.route('/')
def home():
   return render_template('index.html') # localhost:5000에 접속 시 index.html을 가져옴

if __name__ == '__main__':  
   app.run('0.0.0.0',port=5000,debug=True)

 

GET, POST

GET : 데이터 조회

app.py

@app.route('/test', methods=['GET']) # /test로 들어가 get 방식으로 실행
def test_get():
   title_receive = request.args.get('title_give') # index.html에서 받은 title_give값이 있다면 이 값을 title_receive에 저장
   print(title_receive)
   return jsonify({'result':'success', 'msg': '이 요청은 GET!'}) # index.html에 다음 값을 보냄

index.html

    <script>
        function hey(){
            fetch("/test").then(res => res.json()).then(data => {  # app.py에서 실행할 루트 : /test
                console.log(data) # 반환값을 콘솔창에 출력
            })
        }
    </script>

POST : 데이터 생성, 변경, 삭제

app.py

@app.route('/test', methods=['POST']) # html에서 /test로 들어가 post 방식으로 실행
def test_post():
   title_receive = request.form['title_give'] # title_give 값을 title_receive에 저장
   print(title_receive) # 받은 값 확인차 출력
   return jsonify({'result':'success', 'msg': '이 요청은 POST!'}) # 해당 값 반환

index.html

    <script>
        function hey(){
            let formData = new FormData(); # formData 인스턴스 생성
            formData.append("title_give", "블랙팬서"); # formData에 title_give가 블랙팬서라고 저장

            fetch("/test", { method: "POST", body: formData }).then(res => res.json()).then(data => {
                console.log(data) # post에서 반환한 값 콘솔창에 출력
            })
        }
    </script>

 

 

예시 진행 순서

app.py 생성

가상환경 잡기 python -m venv venv

필요 패키지 설치 pip install flask pymongo dnspython (request, bs4는 해당 프로젝트에 필요 없어서 설치 x)

templates 폴더 생성 -> index.html 생성

코드 기입

app.py

from flask import Flask, render_template, request, jsonify
app = Flask(__name__)

from pymongo import MongoClient
client = MongoClient('mongodb+srv://sparta:test@cluster0.szcxpef.mongodb.net/?retryWrites=true&w=majority')
db = client.dbsparta

@app.route('/')
def home():
   return render_template('index.html') # localhost:5000 접속 시 index.html 불러오기

@app.route("/guestbook", methods=["POST"])
def guestbook_post():
    name_receive = request.form['name_give']
    comment_receive = request.form['comment_give']
    doc = {
        'name' : name_receive,
        'comment' : comment_receive
    }
    db.fan.insert_one(doc)

    return jsonify({'msg': '저장 완료!'}) # 이름과 코멘트를 fan이라는 컬렉션에 저장하고 메시지 반환

@app.route("/guestbook", methods=["GET"])
def guestbook_get():
    all_comments = list(db.fan.find({},{'_id':False}))
    return jsonify({'result': all_comments}) # 데이터 베이스 fan 컬렉션에서 _id를 제외한 모든 데이터를 가져오고 반환

if __name__ == '__main__':
   app.run('0.0.0.0', port=5000, debug=True)

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous" />
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
        crossorigin="anonymous"></script>

    <title>초미니홈피 - 팬명록</title>

    <meta property="og:title" content="십센치(10cm) 팬명록" /> <!--메타 태그 작성-->
    <meta property="og:description" content="아티스트에게 응원 한마디!" /> <!--메타 태그 작성-->
    <meta property="og:image" content="https://img.cgv.co.kr/Movie/Thumbnail/Trailer/86297/86297207044_1024.jpg" /> <!--메타 태그 작성-->

    <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+KR:wght@200;300;400;500;600;700;900&display=swap"
        rel="stylesheet" /> <!--구글 폰트 적용-->
    <style>
        * {
            font-family: "Noto Serif KR", serif;
        }

        .mypic {
            width: 100%;
            height: 300px;

            background-image: linear-gradient(0deg,
                    rgba(0, 0, 0, 0.5),
                    rgba(0, 0, 0, 0.5)),
                url("https://img.cgv.co.kr/Movie/Thumbnail/Trailer/86297/86297207044_1024.jpg");
            background-position: center 30%;
            background-size: cover;

            color: white;

			/*아래 4줄은 요소들을 세로로 가운데 정렬하기 위한 코드*/
            display: flex;  
            flex-direction: column;
            align-items: center;
            justify-content: center;
        }

        .mypost {
            width: 95%;
            max-width: 500px;
            margin: 20px auto 20px auto;

            box-shadow: 0px 0px 3px 0px black;
            padding: 20px;
        }

        .mypost>button {
            margin-top: 15px;
        }

        .mycards {
            width: 95%;
            max-width: 500px;
            margin: auto;
        }

        .mycards>.card {
            margin-top: 10px;
            margin-bottom: 10px;
        }
    </style>
    <script>
        $(document).ready(function () {  // 새로고침될 때마다 실행되는 함수
            set_temp();
            show_comment();
        });
        function set_temp() { // 아래 api url에서 'temp' 데이터 text형태로 출력하는 함수
            fetch("http://spartacodingclub.shop/sparta_api/weather/seoul").then((res) => res.json()).then((data) => {
                let temp = data['temp']
                $('#temp').text(temp) 
            });
        }
        function save_comment() {  // 이름과 코멘트를 입력하면 저장하고 경고창과 함께 새로고침하는 함수
            // id:name, id:comment에 입력된 값 저장
            let name = $('#name').val()
            let comment = $('#comment').val()

            // formData에 위에서 저장된 값을 각각 name_give와 comment_give에 저장
            let formData = new FormData();
            formData.append("name_give", name);
            formData.append("comment_give", comment);

            // app.py /guestbook, method:"POST"에서 반환된 msg값 경고창으로 출력, 새로고침
            fetch('/guestbook', { method: "POST", body: formData, }).then((res) => res.json()).then((data) => {
                alert(data["msg"]);
                window.location.reload()
            });
        }

        function show_comment() {
            // app.py에서 /guestbook에 저장된 'result'값을 rows에 저장
            fetch('/guestbook').then((res) => res.json()).then((data) => {
                let rows = data['result']
                $('#comment-list').empty() // id:comment-list의 아래있는 내용 비우기
                rows.forEach((a) => { // rows에 있는 데이터 각자를 a라고 지정하고 아래 반복
                    let name = a['name'] // a에서 'name' 에 해당하는 값을 name에 저장
                    let comment = a['comment'] // a에서 'comment' 에 해당하는 값을 comment에 저장

                    // temp_html이라는 변수에 다음과 같은 형태 설정
                    let temp_html = `<div class="card">
                                        <div class="card-body">
                                            <blockquote class="blockquote mb-0">
                                                <p>${comment}</p> // 위에서 저장한 comment 값 반환
                                                <footer class="blockquote-footer">${name}</footer> // 위에서 저장한 name값 반환
                                            </blockquote>
                                        </div>
                                    </div>`

                	// id:comment-list 아래에 temp_html 추가
                	$('#comment-list').append(temp_html)
                })
            })
        }
    </script>
</head>

<body>
    <div class="mypic">
        <h1>십센치(10cm) 팬명록</h1>
        <p>현재기온: <span id="temp">36</span>도</p> <!--기온이 출력되도록-->
    </div>
    <div class="mypost"> <!--닉네임과 함께 댓글을 등록하는 창-->
        <div class="form-floating mb-3">
            <input type="text" class="form-control" id="name" placeholder="url" />
            <label for="floatingInput">닉네임</label>
        </div>
        <div class="form-floating">
            <textarea class="form-control" placeholder="Leave a comment here" id="comment"
                style="height: 100px"></textarea>
            <label for="floatingTextarea2">응원댓글</label>
        </div>
        <button onclick="save_comment()" type="button" class="btn btn-dark">
            댓글 남기기
        </button>
    </div>
    <div class="mycards" id="comment-list"> <!--위 script에서 temp_html을 붙일 장소-->
        <!--아래 내용은 .empty()에 의해 지워질거라 temp_html의 형태를 보여주는 예시역할-->
        <div class="card">
            <div class="card-body">
                <blockquote class="blockquote mb-0">
                    <p>새로운 앨범 너무 멋져요!</p>
                    <footer class="blockquote-footer">호빵맨</footer>
                </blockquote>
            </div>
        </div>
        <div class="card">
            <div class="card-body">
                <blockquote class="blockquote mb-0">
                    <p>새로운 앨범 너무 멋져요!</p>
                    <footer class="blockquote-footer">호빵맨</footer>
                </blockquote>
            </div>
        </div>
        <div class="card">
            <div class="card-body">
                <blockquote class="blockquote mb-0">
                    <p>새로운 앨범 너무 멋져요!</p>
                    <footer class="blockquote-footer">호빵맨</footer>
                </blockquote>
            </div>
        </div>
    </div>
</body>

</html>

'TIL > 웹 초보' 카테고리의 다른 글

webflow + chatGPT  (0) 2023.04.19
23.04.18  (0) 2023.04.18
23.04.17  (0) 2023.04.17
23.04.17  (0) 2023.04.17
23.04.14  (0) 2023.04.14