본문 바로가기
항해99/프로젝트

[Flask] 스파르타피디아 프로젝트(서버, 크롤링, DB)

by junvely 2023. 2. 15.

🦄 스파르타피디아 프로젝트(서버, 크롤링, DB)

사용자가 입력한 URL 주소로 해당하는 페이지에 있는 meta 태그들의 og데이터(이미지, 타이틀, 설명 등)를

가져와 DB에 저장하기, 사용자가 영화를 추가하면 window를 load하여 DB에 저장된 영화들의 정보로 포스트들을 만들어

(이미지, 타이틀, 설명 등) 보여주기


01 프로젝트 셋팅

$ pip install flask pymongo dnspython requests bs4

- API  :  requests

- 크롤링 : requests, bs4( soup.select_one(' ') )

- 서버 : Flask

- DB : Pymongo, dnspython ( doc{ } , db.movies.insert_on( ) )

 

02 조각 기능 구현해보기

- 외부 metaprac.py 파일에서 만들고 실행해 보고 => 성공 시 app.py에 복붙하기

1. URL 페이지에서 <head> 내부의 <meta> 태그들에서 og데이터들 가져오기(이미지, 타이틀, 설명 등)

import requests
from bs4 import BeautifulSoup

url = 'https://movie.naver.com/movie/bi/mi/basic.naver?code=191597'

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)

soup = BeautifulSoup(data.text, 'html.parser')
# meta태그에서 og 정보들 가져오기
ogtitle = soup.select_one('meta[property="og:title"]')['content']
ogdesc = soup.select_one('meta[property="og:image"]')['content']
ogimage = soup.select_one('meta[property="og:description"]')['content']
print(ogtitle, ogdesc, ogimage)

 

03 뼈대 준비하기

- flask, pymongo, dnspython, requests, bs4  import 하기

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

# requests,bs4
import requests
from bs4 import BeautifulSoup
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('https://movie.naver.com/movie/sdb/rank/rmovie.naver?sel=pnt&date=20210829',headers=headers)
soup = BeautifulSoup(data.text, 'html.parser')

# db => <password>꼭 바꿔주기
from pymongo import MongoClient
client = MongoClient('mongodb+srv://junvely:test@cluster0.38f4se1.mongodb.net/?retryWrites=true&w=majority')
db = client.dbsparta

- app.py 전체 뼈대 코드

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

# requests,bs4
import requests
from bs4 import BeautifulSoup
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('https://movie.naver.com/movie/sdb/rank/rmovie.naver?sel=pnt&date=20210829',headers=headers)
soup = BeautifulSoup(data.text, 'html.parser')

# db => <password>꼭 바꿔주기
from pymongo import MongoClient
client = MongoClient('mongodb+srv://junvely:test@cluster0.38f4se1.mongodb.net/?retryWrites=true&w=majority')
db = client.dbsparta

@app.route('/')
def home():
    return render_template('index.html')

@app.route("/movie", methods=["POST"])
def movie_post():
    sample_receive = request.form['sample_give']
    print(sample_receive)
    return jsonify({'msg':'POST 연결 완료!'})

@app.route("/movie", methods=["GET"])
def movie_get():
    return jsonify({'msg':'GET 연결 완료!'})

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

- mongoClient의 <password>부분 꼭 변경해주기!!

 

1. 서버 실행시키기

2. 백엔드 POST API 만들기

- 받아올 정보 : URL, comment

- DB에 저장할 정보 : URL => (이미지, 타이틀, 설명) 가져오기,  coment

@app.route("/movie", methods=["POST"])
def movie_post():
    # URL, comment 받기
    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')
    # URL에서 ogimage, ogtitle, ogdesc => metaprac.py 복붙
    ogimage = soup.select_one('meta[property="og:image"]')
    ogtitle = soup.select_one('meta[property="og:title"]')
    ogdesc = soup.select_one('meta[property="og:description"]')

    image = ogimage['content']
    title = ogtitle['content']
    desc = ogdesc['content']

    # doc가공 => 이미지, 타이틀, desc, coment
    doc = {
        'image': image,
        'title' : title,
        'desc' : desc,
        'comment' : comment_receive,
    }
    
    # DB에 저장
    post = db.posts.insert_one(doc)
    print(post)
    return jsonify({'msg':'포스팅 완료!'})

- 가독성 고려하여 변수에 한번 더 나눠 담기

3. 프론트 POST 요청

function posting() {
        let url = $("#url").val();
        let comment = $("#comment").val();

        let formData = new FormData();
        formData.append("url_give", url);
        formData.append("comment_give", comment);

        fetch("/movie", { method: "POST", body: formData })
          .then((res) => res.json())
          .then((data) => {
            console.log(data);
            alert(data["msg"]);
          });
        window.location.reload();
      }

 

4. 백엔드 GET API 만들기

@app.route("/movie", methods=["GET"])
def movie_get():
    posts =list(db.posts.find({},{'_id': False})) 
    print(posts)
    return jsonify({'posts':posts})

 

5. 프론트 GET요청

function listing() {
        $("#cards-box").empty();
        fetch("/movie")
          .then((res) => res.json())
          .then((data) => {
            let movies = data["posts"];
            movies.forEach((post) => {
              let image = post["image"];
              let title = post["title"];
              let desc = post["desc"];
              let comment = post["comment"];

              let temp_html = `
                            <div class="col">
                                <div class="card h-100">
                                    <img
                                    src=${image}
                                    class="card-img-top"
                                    />
                                    <div class="card-body">
                                        <h5 class="card-title">${title}</h5>
                                        <p class="card-text">${desc}</p>
                                        <p>⭐⭐⭐</p>
                                        <p class="mycomment">${comment}</p>
                                    </div>
                                </div>
                            </div>
                            `;

              $("#cards-box").append(temp_html);
            });
          });
      }

- app.py 전체코드

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

from pymongo import MongoClient
client = MongoClient('mongodb+srv://junvely:test@cluster0.38f4se1.mongodb.net/?retryWrites=true&w=majority') # mongoDB 주소 사이트에서 가져오기
db = client.dbsparta

import requests
from bs4 import BeautifulSoup


@app.route('/')
def home():
    return render_template('index.html')

@app.route("/movie", methods=["POST"])
def movie_post():
    # URL, comment 받기
    url_receive = request.form['url_give']
    comment_receive = request.form['comment_give']
    star_receive = request.form['star_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')
    # URL에서 ogimage, ogtitle, ogdesc => metaprac.py 복붙
    ogimage = soup.select_one('meta[property="og:image"]')
    ogtitle = soup.select_one('meta[property="og:title"]')
    ogdesc = soup.select_one('meta[property="og:description"]')

    image = ogimage['content']
    title = ogtitle['content']
    desc = ogdesc['content']

    # doc가공 => 이미지, 타이틀, desc, coment
    doc = {
        'image': image,
        'title' : title,
        'desc' : desc,
        'comment' : comment_receive,
        'star' : star_receive,
    }
    
    # DB에 저장
    post = db.posts.insert_one(doc)
    print(post)
    return jsonify({'msg':'포스팅 완료!'})

@app.route("/movie", methods=["GET"])
def movie_get():
    posts =list(db.posts.find({},{'_id': False})) 
    print(posts)
    return jsonify({'posts':posts})

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

 

- 완성!!🙌