21.09.15 세 번째 TIL

서태욱·2021년 9월 15일
0

🖊📘오늘 배운 것

<4주차>

나홀로메모장(POST를 이용한 API)

  • 사전 작업으로 package설치 (Flask, pymongo, requests, bs4)
(설치 완료 후 ok를 누르지 않고 그냥 빨간 x를 눌러 꺼버려서 자꾸 설치가 안되었다고 뜬다. 확실하게 확인하는 습관 들이기!)
  • 조각기능의 구현
    URL만 가지고 원하는 부분을 크롤링(스크래핑)해오기 -> meta tag 스크롤링!
(app.py와 index.html에 코드스니펫으로 뼈대를 붙여넣고 run을 했는데 jinja2.exceptions.TemplateNotFound: index.html이라는 오류가 뜨면서 나홀로 메모장이 나오지 않았다. 구글링 해보니 flask에서 인식하는 템플릿 폴더의 위치가 잘못되어 있다는 거 같다.
해결 방법으로는 모듈인 경우와 패키지 형태인 경우 두가지가 나와 있었는데, 패키지를 설치해서 진행하는 거니까 두 번째 방법으로 진행해 보았다. 간단하게 index.html을 templates 폴더에 넣어주면 끝. 해결에 참고한 링크)
  • app.py
from flask import Flask, render_template, jsonify, request
app = Flask(__name__)

import requests
from bs4 import BeautifulSoup

from pymongo import MongoClient
client = MongoClient('localhost', 27017)
db = client.dbsparta

## HTML을 주는 부분
@app.route('/')
def home():
   return render_template('index.html')

@app.route('/memo', methods=['GET'])
def listing():
    articles = list(db.articles.find({},{'_id':False}))
    return jsonify({'all_articles':articles})

## API 역할을 하는 부분
@app.route('/memo', methods=['POST'])
def saving():
    url_receive = request.form['url_give']
    comment_receive = request.form['comment_give']

    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_receive, headers=headers)

    soup = BeautifulSoup(data.text, 'html.parser')

    title = soup.select_one('meta[property="og:title"]')['content']
    image = soup.select_one('meta[property="og:image"]')['content']
    desc = soup.select_one('meta[property="og:description"]')['content']

    doc = {
        'title':title,
        'image':image,
        'desc':desc,
        'url':url_receive,
        'comment':comment_receive
    }

    db.articles.insert_one(doc)

    return jsonify({'msg':'저장이 완료 되었습니다!'})

if __name__ == '__main__':
   app.run('0.0.0.0',port=5000,debug=True)
  • index.html
<!Doctype html>
<html lang="ko">

    <head>
        <!-- Required meta tags -->
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

        <!-- Bootstrap CSS -->
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
              integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
              crossorigin="anonymous">

        <!-- JS -->
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
                integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
                crossorigin="anonymous"></script>

        <!-- 구글폰트 -->
        <link href="https://fonts.googleapis.com/css?family=Stylish&display=swap" rel="stylesheet">


        <title>스파르타코딩클럽 | 나홀로 메모장</title>

        <!-- style -->
        <style type="text/css">
            * {
                font-family: "Stylish", sans-serif;
            }

            .wrap {
                width: 900px;
                margin: auto;
            }

            .comment {
                color: blue;
                font-weight: bold;
            }

            #post-box {
                width: 500px;
                margin: 20px auto;
                padding: 50px;
                border: black solid;
                border-radius: 5px;
            }
        </style>
        <script>
            $(document).ready(function () {
                showArticles();
            });

            function openClose() {
                if ($("#post-box").css("display") == "block") {
                    $("#post-box").hide();
                    $("#btn-post-box").text("포스팅 박스 열기");
                } else {
                    $("#post-box").show();
                    $("#btn-post-box").text("포스팅 박스 닫기");
                }
            }

            function postArticle() {
                let url = $('#post-url').val()
                let comment = $('#post-comment').val()

                $.ajax({
                    type: "POST",
                    url: "/memo",
                    data: {url_give:url, comment_give:comment},
                    success: function (response) { // 성공하면
                        alert(response["msg"]);
                        window.location.reload()
                    }
                })
            }

            function showArticles() {
                $.ajax({
                    type: "GET",
                    url: "/memo",
                    data: {},
                    success: function (response) {
                        let articles = response['all_articles']
                        for (let i = 0; i < articles.length; i++) {
                            let title = articles[i]['titles']
                            let image = articles[i]['image']
                            let url = articles[i]['url']
                            let desc = articles[i]['desc']
                            let comment = articles[i]['comment']

                            let temp_html = `<div class="card">
                                             <img class="card-img-top"
                                                    src="${image}"
                                                    alt="Card image cap">
                                              <div class="card-body">
                                              <a target="_blank" href="#" class="card-title">${title}</a>
                                              <p class="card-text">${desc}</p>
                                              <p class="card-text comment">${comment}</p>
                                            </div>
                                          </div>`
                            $('#cards-box').append(temp_html)

                        }
                    }
                })
            }
        </script>

    </head>

    <body>
        <div class="wrap">
            <div class="jumbotron">
                <h1 class="display-4">나홀로 링크 메모장!</h1>
                <p class="lead">중요한 링크를 저장해두고, 나중에 볼 수 있는 공간입니다</p>
                <hr class="my-4">
                <p class="lead">
                    <button onclick="openClose()" id="btn-post-box" type="button" class="btn btn-primary">포스팅 박스 열기
                    </button>
                </p>
            </div>
            <div id="post-box" class="form-post" style="display:none">
                <div>
                    <div class="form-group">
                        <label for="post-url">아티클 URL</label>
                        <input id="post-url" class="form-control" placeholder="">
                    </div>
                    <div class="form-group">
                        <label for="post-comment">간단 코멘트</label>
                        <textarea id="post-comment" class="form-control" rows="2"></textarea>
                    </div>
                    <button type="button" class="btn btn-primary" onclick="postArticle()">기사저장</button>
                </div>
            </div>
            <div id="cards-box" class="card-columns">
            </div>
        </div>
    </body>

</html>

<5주차> 미니프로젝트:마이 페이보릿 무비스타!

5주차를 진행하기 위한 기초 작업

  • FileZilla 설치, 가비아 가입 후 도메인 구매

작업 순서: API를 만들기 위해 다음 사항을 꼭 기억해야 한다.

  1. 클라이언트와 서버 연결 확인
  2. 서버 만들기
  3. 클라이언트 만들기
  4. 완성 확인

그동안 배운 것과 진행해서 작성해 둔 코드들을 이용해서 "마이 페이보릿 무비스타"라는 페이지를 만들었다.

  • 크롤링으로 배우 이름, 최근작, 좋아요 수, 사진 등을 추출한 다음 요청방식 "GET"으로 불러와서 응답 데이터로 보낸다.
  • 다음은 "POST"를 사용해 클라이언트에서 받은 이름을 찾아 좋아요(like)를 누르면 순위가 올라가게 하고, 또 삭제를 누르면 해당 배우가 삭제되도록 했다.
    자주 사용되지 않는다던 아래의 delete 코드를 이용.
db.mystar.delete_one({'name':name_receive})

만든 프로젝트를 실제로 서버에 올리기

처음 가입했던 AWS에 프로젝트 결과물을 업로드 하기 위한 작업들을 했다.

❗문제점 발생

terminal을 켜서 sudo chmod 400 명령어를 사용해 키페어를 등록하는 과정이 있었는데, 강의에서는 명령어 앞에 $가 붙어 있었다. 그런데

zsh: command not found: $

라는 에러 메시지가 뜨면서 에러가 났다.. 알아보니 맥북 OS의 차이 때문이었다. 터미널 환경 변수가 OS업데이트 이후 zsh로 변경된 것. zsh에서는 $의 역할을 %가 하는 것으로 바뀐 것 같다.

% sudo chmod 400

로 바꿔서 입력하니 해결!

이후 내용은 AWS에서 서버를 구축하고 숙제를 업로드 하는 식으로 진행 되었는데 아직 주차별 숙제를 하지 못해서 진행하지는 못했고 훑어보는 느낌으로 마무리 했다.


총평

일단 어찌저찌 5주차로 구성된 기본 강의를 끝냈다. 겨우 어렴풋이 코딩이 어떤 것인지를 맛본 느낌이다. 요모조모 뜯어보며 어떻게 작동되는 건지 좀 더 고민하는 시간을 가질 필요가 있겠다.

profile
re:START

0개의 댓글