ChatGPT 웹개발 진행노트 - 6일차

2024. 2. 2. 16:08스파르타_부트캠프/웹개발

강의 자료 

3주차 강의 자료

3주차

13. Flask로 로또 추천 사이트 만들기 2

로또 당첨 기능 구현하기

두개의 리스트 중 일치하는 숫자의 개수를 반환하는 함수를 구현한다.

def count_common_elements(list1, list2):
    common = set(list1) & set(list2)
    return len(common)

 

test_app.py의 단위 테스트에서 검증한다.

class Test(unittest.TestCase):
    def test_count_common_elements(self):
        self.assertEqual(0, count_common_elements([1, 2, 3], [4, 5, 6]))
        self.assertEqual(1, count_common_elements([1, 2], [1, 3]))
        self.assertEqual(3, count_common_elements([1, 2, 3], [1, 2, 3]))

 

정상 구현된 것을 확인하였다. 이제 lotto와 random_lotto의 일치 개수를 계산하여 context에 key, value로 설정 후 전달한다.

common_count = count_common_elements(lotto, lotto_numbers)

context = {
    "name": name,
    "lotto": lotto,
    "random_lotto": lotto_numbers,
    "common_count": common_count
}

 

index.html의 body 태그에 다음과 같이 값을 추가한다.

<body>
<h1>안녕, {{data.name}}</h1>
<h2>로또 번호:, {{data.lotto}}</h2>
<h3>랜덤 로또 번호:, {{data.random_lotto}}</h3>

{% if data.common_count == 6 %}
<h2>{{ data.common_count }}개 맞았습니다! 로또 1등입니다.</h2>
{% elif data.common_count == 5 %}
<h2>{{ data.common_count }}개 맞았습니다! 로또 2등입니다.</h2>
{% elif data.common_count == 4 %}
<h2>{{ data.common_count }}개 맞았습니다! 로또 3등입니다.</h2>
{% elif data.common_count == 3 %}
<h2>{{ data.common_count }}개 맞았습니다! 로또 4등입니다.</h2>
{% else %}
<h2>{{ data.common_count }}개 맞았습니다! 탈락입니다...😥😥</h2>
{% endif %}
</body>

다음과 같이 결과가 출력된다.

CSS추가하여 완성하기

html의 style에 다음을 추가한다.

<style>
    .ball {
      display: inline-block;
      width: 30px;
      height: 30px;
      border-radius: 50%;
      background-color: #FFD700;
      color: #FFFFFF;
      text-align: center;
      line-height: 30px;
      margin-right: 5px;
    }
    .randomball {
      display: inline-block;
      width: 30px;
      height: 30px;
      border-radius: 50%;
      background-color: red;
      color: #FFFFFF;
      text-align: center;
      line-height: 30px;
      margin-right: 5px;
    }
  </style>

 

이후 index.html에 다음과 같이 코드를 수정한다.

<h1>로또 번호</h1>
{% for num in data.lotto %}
    <div class="ball">{{ num|e }}</div>
{% endfor %}

<h1>랜덤 로또 번호</h1>
{% for num in data.random_lotto %}
    <div class="randomball">{{ num|e }}</div>
{% endfor %}

다음과 같이 화면에 출력된다.

Flask 이미지 삽입하기

다음 링크에서 이미지를 다운 받은 후 프로젝트에서 static/image 폴더 생성 후 해당 폴더에 저장한다.

https://s3.ap-northeast-2.amazonaws.com/materials.spartacodingclub.kr/webjong/coinman.png

 

html 반영을 위해 index.html 에 다음 코드를 추가한다.

.coinman {
	height: 100px;
}

<img class="coinman" src="{{ url_for('static', filename='image/coinman.png') }}" alt="">

 

다음과 같이 화면에 출력되는 것을 확인할 수 있다.

14. 영화 검색 사이트 만들기

movie 페이지 보여주기

/movie 경로로 접속할 시 movie.html을 보여준다.

 

app.py에 다음 코드를 추가한다.

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

 

movie.html에 다음 코드를 추가한다.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <h1>영화 검색</h1>
</body>
</html>

 

127.0.0.1:5001/movie에 다음과 같이 화면이 추가되었다.

 

영화 검색 기능 만들기

form 생성

영화 검색을 위한 html form을 생성한다. movie.html의 body 태그에 다음값을 추가한다.

<form action="{{ url_for('movie') }}">
  <input type="text" name="query">
  <button type="submit">검색</button>
</form>

 

app.py의 movie 항목에 다음 코드를 추가한다.

@app.route('/movie')
def movie():
    print(flask.request.args.get('query'))
    return flask.render_template('movie.html')

검색 클릭시 다음과 같이 콘솔에 출력된다.

 

검색 기능 구현

 

영화진흥원 API URL 끝에 &movieNm=기생충 을 추가한 후 주소창에 입력하면 다음과 같은 포맷으로 json을 반환한다.

http://kobis.or.kr/kobisopenapi/webservice/rest/movie/searchMovieList.json?key=f5eef3421c602c6cb7ea224104795888&movieNm=기생충
{
  "movieListResult": {
    "totCnt": 4,
    "source": "영화진흥위원회",
    "movieList": [
      {
        "movieCd": "20236433",
        "movieNm": "사랑하는 기생충",
        "movieNmEn": "Parasite in Love",
        "prdtYear": "2021",
        "openDt": "20240116",
        "typeNm": "장편",
        "prdtStatNm": "개봉",
        "nationAlt": "일본",
        "genreAlt": "드라마",
        "repNationNm": "일본",
        "repGenreNm": "드라마",
        "directors": [
          {
            "peopleNm": "카키모토 켄사쿠"
          }
        ],
        "companys": []
      },
      ...
      ]
    }
}

 

이를 통해 movieNm에 입력값 query를 추가하여 url을 생성하여 결과를 가져온다.

app.py에 다음 코드를 추가한다.

@app.route('/movie')
def movie():
    query = flask.request.args.get('query')
    URL = (f"http://kobis.or.kr/kobisopenapi/webservice/rest/movie/"
           f"searchMovieList.json?key=f5eef3421c602c6cb7ea224104795888&movieNm={query}")
    res = requests.get(URL)
    rjson = res.json()
    movie_list = rjson["movieListResult"]["movieList"]

    return flask.render_template('movie.html', data=movie_list)

 

movie.html에 데이터를 출력하도록 기능을 구현한다.

<body>
  <h1>영화 검색</h1>
  <form action="{{ url_for('movie') }}">
    <input type="text" name="query">
    <button type="submit">검색</button>
  </form>
  {% for movie in data %}
      <!-- <p>{{ movie }}</p> -->
      <p>영화 제목: {{ movie.movieNm }}</p>
      <p>타입: {{ movie.typeNm }}</p>
      {% if movie.directors %}
        <p>감독: {{ movie.directors[0].get('peopleNm') }}</p>
      {% endif %}
      <hr>
  {% endfor %}

</body>

 

검색 시 다음과 같이 결과가 출력된다.

15. Homework

검색 날짜에 따라(YYYYMMDD 포맷) 1~10등까지 영화 등수, 영화명, 영화 개봉일, 누적 관객 수를 출력한다. 

/answer경로에 해당 페이지를 추가한다.

검색어가 없는 경우 20230601을 디폴트로 한다.

 

영화 박스오피스 API 주소

http://kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchWeeklyBoxOfficeList.json?key=f5eef3421c602c6cb7ea224104795888&targetDt=20230601

 

해당 URL에 접근시 다음과 같은 json 반환

{
    "boxOfficeResult": {
        "boxofficeType": "주말 박스오피스",
        "showRange": "20230602~20230604",
        "yearWeekTime": "202322",
        "weeklyBoxOfficeList": [
            {
                "rnum": "1",
                "rank": "1",
                "rankInten": "1",
                "rankOldAndNew": "OLD",
                "movieCd": "20226411",
                "movieNm": "범죄도시3",
                "openDt": "2023-05-31",
                "salesAmt": "28690098096",
                "salesShare": "87.6",
                "salesInten": "25444261553",
                "salesChange": "783.9",
                "salesAcc": "44614489126",
                "audiCnt": "2817135",
                "audiInten": "2511765",
                "audiChange": "822.5",
                "audiAcc": "4512223",
                "scrnCnt": "2582",
                "showCnt": "42571"
            },
            ...
        ]
    }
}

 

 

app.py 코드

@app.route('/answer')
def answer():
    query = flask.request.args.get('query')
    if len(query) == 0:
        query = '20230611'
    URL = (f"http://kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/"
           f"searchWeeklyBoxOfficeList.json?key=f5eef3421c602c6cb7ea224104795888&targetDt={query}")
    res = requests.get(URL)
    rjson = res.json()
    movie_list = rjson["boxOfficeResult"]["weeklyBoxOfficeList"]

    return flask.render_template('answer.html', data=movie_list)

 

answer.html 코드

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

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"
    integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
</head>

<body>
  <h1>박스오피스 검색</h1>
  <p>20230501 형식으로 검색하세요.</p>
  <form action="{{ url_for('answer') }}">
    <input type="text" name="query">
    <button type="submit">검색</button>
  </form>

  <table class="table">
    <thead>
      <tr>
        <th scope="col">랭킹</th>
        <th scope="col">영화명</th>
        <th scope="col">영화개봉일</th>
        <th scope="col">누적관객수</th>
      </tr>
    </thead>
    <tbody>
      {% for movie in data %}
      <tr>
        <th>{{ movie.rank }}</th>
        <td>{{ movie.movieNm }}</td>
        <td>{{ movie.openDt }}</td>
        <td>{{ movie.audiAcc }}명</td>
      </tr>
      {% endfor %}

    </tbody>
  </table>


  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"
    integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz"
    crossorigin="anonymous"></script>
</body>

</html>

 

다음과 같이 출력된다.