셀레니움

데이터가 외부에 있는 것들. 주식 매출,영업이익등의 데이터 표같은거. 이건 데이터를 웹으로 보여준게 아니고, 디비에 있는걸 가져오는거라서. 일반적으로 스크래핑이 되지 않음. 셀레니움은 가능하다.

 

 

# 실제 웹페이지의 스크립트 코드를 스크래핑하면, 안되는경우.

beautifulsoup 쓰면,  tbody태그같은게 없어질  있음.

먼저 bs4 파싱한 데이터를 print 한다음, 결과를 메모장에 넣고 그걸 직접 위치를 파악해야 .

 

tr여러개가 있는 테이블의 처음위치를 찍을 , tr까지 찍어줘야 .

trs = soup.select('#old_content > table > tbody > tr') 이런식으로.

tbody 전체 테이블인데 나는 tbody까지 했었음;;

 

 

 

 

My favorite movie star 사이트 만들기

 

 

 

기본 기능

- 영화인 정보를 카드로 보여주기 (read)

- 좋아요 기능 (update) : 영화인 카드의 "위로" 버튼을 누르면 좋아요 옆 숫자가 추가되고, 좋아요가 많은 순서대로 위에서부터 정렬된다.

- 영화인 정보 삭제하기 (delete) : 삭제 버튼을 누르면 해당 영화인이 삭제된다.

 

api 정리

- 조회기능 : 영화인 정보 전체를 가져옴

- 좋아요기능 : 클라이언트에서 받은 이름을 찾아서 좋아요를 증가함

- 삭제 : 클라이언트에서 받은 이름으로 영화인을 찾고, 해당 정보를 db에서 삭제.

 

 

각 api 상세 설명

 

1. 영화인 정보를 카드로 보여줌 (영화인 이름, 영화인 이미지, 좋아요 개수, 최근 작품 내용)

 

A. 요청 정보

  • 요청 URL= /api/list , 요청 방식 = GET
  • 요청 데이터 : 없음

B. 서버가 제공할 기능 : 데이터베이스에 영화인 정보를 조회(Read)하고, 영화인 정보를 응답 데이터로 보냄

C**. 응답 데이터 :** (JSON 형식) 'result'= 'success', 'stars_list'= 영화인 정보 리스트

 

서버로직

영화인 정보 전체를 조회하기 위해 서버가 받을 정보는 없습니다. 조건없이 모든 정보를 보여줄 것이니까요! =

따라서 서버 로직은 다음 단계로 구성되어야 합니다.

1. mystar 목록 전체를 검색합니다. ID는 제외하고 like 가 많은 순으로 정렬

2. 성공하면 success 메시지와 함께 stars_list 목록을 클라이언트에 전달

 

클라이언트로직

영화인 정보 전체를 조회하기 위해 서버가 받을 정보는 없습니다. 조건없이 모든 정보를 보여줄 것이니까요!

따라서 클라이언트 로직은 다음 단계로 구성되어야 합니다.

1. #star_box의 내부 html 태그를 모두 삭제

2. 서버에 1) GET 방식으로, 2) /api/list 라는 주소로 stars_list를 요청

3. 서버가 돌려준 stars_list를 stars라는 변수에 저장

4. for 문을 활용하여 stars 배열의 요소를 차례대로 조회

5. stars[i] 요소의 name, url, img_url, recent, like 키 값을 활용하여 값 조회

6. 영화인 카드 코드 만들어 #star-box에 붙이기

 

 

2. 좋아요(Update) 기능: 클라이언트에서 받은 이름(name_give)으로 찾아서 좋아요(like)를 증가

 

A. 요청 정보

  • 요청 URL= /api/like , 요청 방식 = POST
  • 요청 데이터 : 영화인 이름(name_give)

B. 서버가 제공할 기능 : 영화인 이름(요청 데이터)과 일치하는 영화인 정보의 좋아요 수를 한 개 증가시켜 데이터베이스에 업데이트하고(Update), 성공했다고 응답 메세지를 보냄

 

C. 응답 데이터 : (JSON 형식) 'result'= 'success'

 

 

서버로직

영화인 카드의 좋아요 수를 증가시키기 위해 서버가 클라이언트에게 전달받아야하는 정보는 다음과 같습니다.

- 영화인의 이름 (name_give)

따라서 서버 로직은 다음 단계로 구성되어야 합니다.

1. 클라이언트가 전달한 name_give를 name_receive 변수에 넣습니다.

2. mystar 목록에서 find_one으로 name이 name_receive와 일치하는 star를 찾습니다.

3. star의 like 에 1을 더해준 new_like 변수를 만듭니다.

4. mystar 목록에서 name이 name_receive인 문서의 like 를 new_like로 변경합니다

 

클라이언트로직

좋아요 수를 증가시키기 위해 클라이언트가 전달할 정보는 다음과 같습니다.

- 영화인의 이름 (name_give)

따라서 클라이언트 로직은 다음 단계로 구성되어야 합니다.

1. 서버에 1) POST 방식으로, 2) /api/like 라는 url에, 3) name_give라는 이름으로 name을 전달합니다. (참고) POST 방식이므로 data: {'name_give': name} 사용

2. '좋아요 완료!' alert 창을 띄웁니다.

3. 변경된 정보를 반영하기 위해 새로고침합니다.

 

 

3. 삭제(Delete) 기능: 클라이언트에서 받은 이름(name_give)으로 영화인을 찾고, 해당 영화인을 삭제

 

A. 요청 정보

  • 요청 URL= /api/delete , 요청 방식 = POST
  • 요청 데이터 : 영화인 이름(name_give)

B. 서버가 제공할 기능 : 영화인 이름(요청 데이터)와 일치하는 영화인 정보를 데이터베이스에서 삭제(Delete)하고, 성공했다고 응답 메세지를 보냄

 

C. 응답 데이터 : (JSON 형식) 'result'= 'success'

 

서버로직

영화인 카드를 삭제하기 위해 필요한 정보는 다음과 같습니다.

- 영화인의 이름 (name_give)

따라서 서버 로직은 다음 단계로 구성되어야 합니다.

1. 클라이언트가 전달한 name_give를 name_receive 변수에 넣기

2. mystar 에서 delete_one으로 name이 name_receive와 일치하는 star를 제거

3. 성공하면 success 메시지를 반환

 

클라이언트로직

영화인 카드를 삭제하기 위해 필요한 정보는 다음과 같습니다.

- 영화인의 이름 (name_give)

따라서 클라이언트 로직은 다음 단계로 구성되어야 합니다.

1. 서버에 1) POST 방식으로, 2) /api/delete 라는 url에, 3) name_give라는 이름으로 name을 전달 (참고) POST 방식이므로 data: {'name_give': name}

2. '삭제 완료! 안녕!' alert창 띄우기

3. 변경된 정보를 반영하기 위해 새로고침

 

 

DB 생성 구문 (init_db.py)

- 해당 구문을 실행하면 내 DB에 정보들이 저장된다.

# 이 구문은 db를 생성하는 구문이다. 다른건 없음. 즉 영화인에 대한 정보를 스크래핑하여 DB를 생성한다.

import requests
from bs4 import BeautifulSoup
from pymongo import MongoClient

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


# DB에 저장할 영화인들의 출처 url을 가져옵니다.
def get_urls():
    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/rpeople.nhn', headers=headers)
    soup = BeautifulSoup(data.text, 'html.parser')

    # 네이버 영화인정보 테이블 데이터
    trs = soup.select('#old_content > table > tbody > tr')



    urls = []
    for tr in trs:
        a = tr.select_one('td.title > a')
        if a is not None:
            base_url = 'https://movie.naver.com/'
            url = base_url + a['href']
            urls.append(url)

    return urls
# 결과적으로 딱 50명에 대한 링크만 다 가져온다.
# 아래에서 해당 링크를 열어서 스크래핑을 수행하는 것.


# 출처 url로부터 영화인들의 사진, 이름, 최근작 정보를 가져오고 mystar 콜렉션에 저장합니다.
def insert_star(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)
    soup = BeautifulSoup(data.text, 'html.parser')

    name = soup.select_one('#content > div.article > div.mv_info_area > div.mv_info.character > h3 > a').text
    img_url = soup.select_one('#content > div.article > div.mv_info_area > div.poster > img')['src']
    recent_work = soup.select_one('#content > div.article > div.mv_info_area > div.mv_info.character > dl > dd > a:nth-child(1)').text

    doc = {
        'name': name,
        'img_url': img_url,
        'recent': recent_work,
        'url': url,
        'like': 0
    }

    db.mystar.insert_one(doc)
    print('완료!', name)



# 기존 mystar 콜렉션을 삭제하고, 출처 url들을 가져온 후, 크롤링하여 DB에 저장합니다.
def insert_all():
    db.mystar.drop()  # mystar 콜렉션을 모두 지워줍니다.
    urls = get_urls()
    for url in urls:
        insert_star(url)


### 실행하기
insert_all()

 

 

메인 구문 (app.py)

- 메인구문으로 디비 저장후, 실제로 사이트 운영하는.

from pymongo import MongoClient
from flask import Flask, render_template, jsonify, request

app = Flask(__name__)
client = MongoClient('localhost', 27017)
db = client.dbsparta


# HTML 화면 보여주기
@app.route('/')
def home():
    return render_template('index.html')


# API 역할을 하는 부분
@app.route('/api/list', methods=['GET'])
def show_stars():
    # 1. db에서 mystar 목록 전체를 검색합니다. ID는 제외하고 like 가 많은 순으로 정렬합니다.
    # 참고) find({},{'_id':False}), sort()를 활용하면 굿!
    # {} 다 가져오라는 것이며, 뒤에 .sort는 전체 값에 대해 sort를 적용한다. 괄호 잘 볼것.  (sort는 1이 오름차순(점점 커지는 형태), -1이 내림차순(점점작아지는형태. 젤큰값이 위로 간다)
    # 즉, 홈페이지가 새로고침되면, 여기 좋아요가 큰거부터 차례대로 넣는다는 뜻임. 만약 숫자가 동률이면, 여기가 내림차순이니까 한글이름도 내림차순이어서 ㅎ 부터 되는것임. sort에 추가 옵션을 주면 한글도 다르게 정렬할수있다고 함. 검색.
    stars = list(db.mystar.find({}, {'_id': False}).sort('like', -1))
    # 2. 성공하면 success 메시지와 함께 stars_list 목록을 클라이언트에 전달합니다.
    return jsonify({'result': 'success', 'stars_list': stars})


@app.route('/api/like', methods=['POST'])
def like_star():
    # 1. 클라이언트가 전달한 name_give를 name_receive 변수에 넣습니다.
    name_receive = request.form['name_give']

    # 2. mystar 목록에서 find_one으로 name이 name_receive와 일치하는 star를 찾습니다.
    star = db.mystar.find_one({'name': name_receive})
    # 3. star의 like 에 1을 더해준 new_like 변수를 만듭니다.
    new_like = star['like'] + 1

    # 4. mystar 목록에서 name이 name_receive인 문서의 like 를 new_like로 변경합니다.
    # 참고: '$set' 활용하기!
    db.mystar.update_one({'name': name_receive}, {'$set': {'like': new_like}})

    # 5. 성공하면 success 메시지를 반환합니다. 성공했따는것을 알려주기 위함.
    return jsonify({'result': 'success'})


@app.route('/api/delete', methods=['POST'])
def delete_star():
    # 1. 클라이언트가 전달한 name_give를 name_receive 변수에 넣습니다.
    name_receive = request.form['name_give']
    # 2. mystar 목록에서 delete_one으로 name이 name_receive와 일치하는 star를 제거합니다.
    db.mystar.delete_one({'name': name_receive})
    # 3. 성공하면 success 메시지를 반환합니다.
    return jsonify({'result': 'success'})


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

 

 

html 구문 (index.html)

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>마이 페이보릿 무비스타 | 프론트-백엔드 연결 마지막 예제!</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.8.0/css/bulma.min.css"/>
    <script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
    <style>
        .center {
            text-align: center;
        }

        .star-list {
            width: 500px;
            margin: 20px auto 0 auto;
        }

        .star-name {
            display: inline-block;
        }

        .star-name:hover {
            text-decoration: underline;
        }

        .card {
            margin-bottom: 15px;
        }
    </style>
    <script>
        $(document).ready(function () {
            // index.html 로드가 완료되면 자동으로 showStar() 함수를 호출합니다.
            showStar();
        });

        function showStar() {
            // 1. #star_box의 내부 html 태그를 모두 삭제합니다.
            // 데이터베이스 내용 뿌리기 전에 항상 비워준다.
            $('#star-box').empty()

            // 2. 서버에 1) GET 방식으로, 2) /api/list 라는 주소로 star_list를 요청합니다.
            $.ajax({
                type: "GET",
                url: "/api/list",
                data: {},
                success: function (response) {
                    // 3. 서버가 돌려준 star_list를 star라는 변수에 저장합니다.
                    let stars = response['stars_list']
                    // 4. for 문을 활용하여 star 배열의 요소를 차례대로 조회합니다.
                    for (let i = 0; i < stars.length; i++) {
                        let star = stars[i]
                        // 5. star[i] 요소의 name, url, img_url, recent, like 키 값을 활용하여 값을 조회합니다.
                        let name = star['name']
                        let url = star['url']
                        let imgUrl = star['img_url']
                        let recentWork = star['recent']
                        let like = star['like']

                        // 6. 영화인 카드를 만듭니다.
                        let tempHtml = `<div class="card">
                                <div class="card-content">
                                  <div class="media">
                                    <div class="media-left">
                                      <figure class="image is-48x48">
                                        <img
                                          src="${imgUrl}"
                                          alt="Placeholder image"
                                        />
                                      </figure>
                                    </div>
                                    <div class="media-content">
                                      <a href="${url}" target="_blank" class="star-name title is-4">${name} (좋아요: ${like})</a>
                                      <p class="subtitle is-6">${recentWork}</p>
                                    </div>
                                  </div>
                                </div>
                                <footer class="card-footer">
                                  <a href="#" onclick="likeStar('${name}')" class="card-footer-item has-text-info">
                                    위로!
                                    <span class="icon">
                                      <i class="fas fa-thumbs-up"></i>
                                    </span>
                                  </a>
                                  <a href="#" onclick="deleteStar('${name}')" class="card-footer-item has-text-danger">
                                    삭제
                                    <span class="icon">
                                      <i class="fas fa-ban"></i>
                                    </span>
                                  </a>
                                </footer>
                              </div>`

                        // 7. #star-box에 temp_html을 붙입니다.
                        $('#star-box').append(tempHtml)
                    }
                }
            });
        }

        function likeStar(name) {
            // 1. 서버에 1) POST 방식으로, 2) /api/like 라는 url에, 3) name_give라는 이름으로 name을 전달합니다.
            // 참고) POST 방식이므로 data: {'name_give': name} 과 같은 양식이 되어야합니다!
            $.ajax({
                type: "POST",
                url: "/api/like",
                data: {'name_give': name},
                success: function (response) {
                    if (response['result'] == 'success') {
                        // 2. '좋아요 완료!' 얼럿을 띄웁니다.
                        alert('좋아요 완료!')
                        // 3. 변경된 정보를 반영하기 위해 새로고침합니다. 중요!
                        window.location.reload()
                    }
                }
            });
        }

        function deleteStar(name) {
            // 1. 서버에 1) POST 방식으로, 2) /api/delete 라는 url에, 3) name_give라는 이름으로 name을 전달합니다.
            // 참고) POST 방식이므로 data: {'name_give': name} 과 같은 양식이 되어야합니다!
            $.ajax({
                type: "POST",
                url: "/api/delete",
                data: {'name_give': name},
                success: function (response) {
                    if (response['result'] == 'success') {
                        // 2. '삭제 완료! 안녕!' 얼럿을 띄웁니다.
                        alert('삭제 완료! 안녕!')
                        // 3. 변경된 정보를 반영하기 위해 새로고침합니다.
                        window.location.reload()
                    }
                }
            });
        }

    </script>
</head>
<body>
<section class="hero is-warning">
    <div class="hero-body">
        <div class="container center">
            <h1 class="title">
                마이 페이보릿 무비스타😆
            </h1>
            <h2 class="subtitle">
                순위를 매겨봅시다
            </h2>
        </div>
    </div>
</section>
<div class="star-list" id="star-box">
    <div class="card">
        <div class="card-content">
            <div class="media">
                <div class="media-left">
                    <figure class="image is-48x48">
                        <img
                                src="https://search.pstatic.net/common/?src=https%3A%2F%2Fssl.pstatic.net%2Fsstatic%2Fpeople%2Fportrait%2F201807%2F20180731143610623-6213324.jpg&type=u120_150&quality=95"
                                alt="Placeholder image"
                        />
                    </figure>
                </div>
                <div class="media-content">
                    <a href="#" target="_blank" class="star-name title is-4">김다미 (좋아요: 3)</a>
                    <p class="subtitle is-6">안녕, 나의 소울메이트(가제)</p>
                </div>
            </div>
        </div>
        <footer class="card-footer">
            <a href="#" onclick="likeStar('김다미')" class="card-footer-item has-text-info">
                위로!
                <span class="icon">
              <i class="fas fa-thumbs-up"></i>
            </span>
            </a>
            <a href="#" onclick="deleteStar('김다미')" class="card-footer-item has-text-danger">
                삭제
                <span class="icon">
              <i class="fas fa-ban"></i>
            </span>
            </a>
        </footer>
    </div>
</div>
</body>
</html>

 

결과

 

 

 

'SCC 9기' 카테고리의 다른 글

[SCC 9기] - 6주차  (0) 2020.08.22
[SCC 9기] - Project 개발 일지 : 프로젝트 기획안  (0) 2020.08.13
[SCC 9기] 4주차  (0) 2020.08.11
[SPC 9기] 3주차  (0) 2020.07.25
[SPC 9기] 2주차  (0) 2020.07.24

+ Recent posts