6.0~6.8 강의 내용 정리

이희범·2022년 9월 8일
1

6.0 Introduction

Flask: Python을 이용해서 웹사이트를 구축할 수 있는 micro framework

micro framework인 이유: 겁나 작고, 겁나 쉬워서, 어떻게 동작하는지 이해하기가 쉬워, 누구나 10분이면 쓸 수 있기 때문이다.

UI를 구축하는 작업을 한다는데, 다행히 CSS보다는 HTML을 많이 한댄다. 둘 다 극혐하긴 하지만, 그래도 HTML이 조금 더 나은 거 같아서 다행 ㅎㅎ

6.1 Hello Flask

우리는 file_name으로 file을 생성하고, file의 header을 작성하고, jobs의 job들에 대해서 동일한 작업을 하고 나서, file을 닫을 것이다.
따라서 기존의 코드인,

file = open(f"{keyword}.csv", "w")
file.write("Position, Company, Location, URL\n")
for job in jobs:
    file.write(
        f"{job['position']}, {job['company']}{job['location']}, {job['link']}\n"
    )
file.close()

를 file.py에 작성해준다.

def save_to_file(file_name, jobs):
    file = open(f"{file_name}.csv", "w")
	file.write("Position, Company, Location, URL\n")
	for job in jobs:
        file.write(
            f"{job['position']}, {job['company']},{job['location']}, {job['link']}\n"
        )
	file.close()

코드는 이렇게 작성될 것이다.

그리고 나서, 기존 파일을

from extractors.indeed import extract_indeed_jobs
from extractors.wwr import extract_wwr_jobs
from file import save_to_file
keyword = input("What do you want to search for?")
indeed = extract_indeed_jobs(keyword)
wwr = extract_wwr_jobs(keyword)
jobs = indeed + wwr
save_to_file(keyword, jobs)

이렇게 작성해주자.

그리고 실행해보면,

당연히 잘된다. 원래 함수를 main.py에 옮기고 불러온 것 뿐이니까, 자 그럼, 이제 flask를 설치해보자. 설치법은 이전 글에 나와 있듯이 큐브 모양 버튼을 클릭하고, flask를 검색하고, +버튼을 누르면 된다.

그 다음,

from flask import Flask

이 코드로 flask를 불러오면 된다.

그리고 나서,

app = Flask("JobScrapper")
app.run("0.0.0.0")

로 app을 빌드해준 뒤, 현재 repl.it에서 코드를 실행중이므로 repl.it에게 웹서버를 실행한다는 것을 알려줘야한다.

하지만 이 코드를 실행해도, 별 특이한 건 없다. 왜냐고? 우리가 방문자를 처리할 코드를 작성하지 않았기 때문이다.
그래서 user가 홈페이지에 방문하면 reply 해주는 코드를 작성해볼 것이다.

@app.route("/")
def home():
  return 'hey there!'

이렇게 작성해주면 된다. 중요한 것은 @이 포함된 코드(이를 decorator 라고 한다.)를 반드시 함수 위에 작성해주어야 한다는 것이다.

decorator의 역할: flask에게 이 주소의 page를 방문했을 때 이 함수를 호출해야한다는 것을 알려줌.

그리고 실행 해보면,

잘 나오더라 ㅎㅎ

6.2 Render Template

이제는 사용자에게 HTML 요소를 반환하는 페이지를 작성해볼 것이다.

우선, 새 페이지를 하나 만들어보자.

@app.route("/hello")
def hello():
    return 'hello you!'

를 작성하고,

이 빨간 버튼을 눌러서 새 창에서 열어주고,

주소에 /hello를 추가해주면, 잘 나온다.

그럼 이제 HTML 요소를 반환해보자.

@app.route("/")
def home():
  return "<h1>hey there!</h1>"

위의 코드를 이렇게 바꾸고 새로고침 해보자.

잘 나온다 ㅎㅎ

@app.route("/")
def home():
  return "<h1>hey there!</h1><a href='/hello'> go to hello</a>"

코드를 이렇게 작성해보면,

👍

그런데 만약 사이트에 HTML 요소가 많다면, 이 방법으로는 사실 힘들 것이다.
그래서 폴더를 하나 생성할 것이다.
폴더 이름은 'templates'이다. 'template'는 안된다! s를 빼먹어서는 안된다. 이유는 flask는 templates라는 폴더를 찾아보기 때문이다. 'templates' 제외 그 어떠한 이름도 안된다. 그리고 templates를 extractor 폴더 안에 만들어서도 안된다.

그리고 안에 home.html이라는 파일을 만들고,

from flask import Flask, render_template
def home():
    return render_template("home.html")

main.py의 코드를 위와 같이 수정해준다.

그리고 다시 실행해보면...!

ㅎㅎㅎㅎ

근데 이건 좀 심심해서, html 파일에 변수를 넣을 것이다. 그러면 flask가 user가 그 변수를 보기 전에 replace 해줄 것이다.

def home():
    return render_template("home.html", name = "nico")

main.py의 코드는 이렇게,

</head>
<body>
  <h1>Hello to you! My name is {{name}}</h1>
</body>
</html>

html의 코드는 이렇게 적어주자({{}}이 중요)

파이썬이 백엔드 역할을 한다! 개꿀 ㅎㅎ

6.3 Form

<body>
  <h1>Job Scrapper</h1>
  <h4>What job do you want?</h4>
  <form>
    <input type="text" name="keyword" 
      placeholder="Write one keyword please" />
    <button>Search</button>
  </form>

html 파일 코드를 이렇게 작성해보자.(새로 배운 내용은 없다)

그리고 새 창으로 가서 파이썬을 입력한 뒤 엔터를 누르면,

주소가 이렇게 바뀌는 것을 볼 수 있다. 이게 처음 부분에 keyword가 중요하다고 한 이유인듯 하다.

근데 우리는 똑같은 페이지에 머물고 싶지 않다. 이럴 땐,

  <form action="/search">
    <input type="text" name="keyword" 
      placeholder="Write one keyword please" />
    <button>Search</button>
  </form>

html 코드를 이렇게 action을 넣어주면 된다고 카카오톡 클론 강의에서 얘기했단다. 난 안배워서 모르겠다. 여튼, 새로고침을 해주면,

Not Found가 떴지만 그게 중요한게 아니고, 주소가 저렇게 바뀌었다는 것에 주목하자. 다른 페이지를 만들 수 있다는게 중요하다. 그래서 이제 keyword를 url에서 추출해서 결과를 표시해볼 건데, 그 전에 search.html이라는 template을 하나 더 만들자. 그리고 나서 재실행 해보면,

이렇게 잘 나오더라.

6.4 Recap

그냥 복습인데, action은 form이 기본적으로 get method를 가지고 있어서 작동하는 것이라고 카카오톡 클론 코딩 강의에서 얘기했었댄다. 난 안배웠는데 ㅎㅎ

6.5 Arguments

url에 있는 keyword 값을 function에서 사용해보자. 그러기 위해선,

from flask import Flask, render_template, request

이렇게 request라는걸 추가로 불러와줘야한다.

request: 브라우저가 홈페이지에게 요청하는 것
def hello():
    print(request.args)
    return render_template("search.html")

코드를 이렇게 수정해주고, 콘솔창을 보면,

ㅇㅎ... 이걸 가져오면 되는구나

그럼, 파이썬 코드를

def hello():
    keyword = request.args.get("keyword")
    return render_template("search.html", keyword=keyword)

이렇게,

<body>
  <h1>Search Results for "{{keyword}}":</h1>
</body>

html 코드를 이렇게 변경하고 재실행해보면,

굿굿 ㅎㅎ

자 그럼, 우리가 만들었던 스크래퍼를 그대로 가져와 보자.

from extractors.indeed import extract_indeed_jobs
from extractors.wwr import extract_wwr_jobs
def search():
    keyword = request.args.get("keyword")
    indeed = extract_indeed_jobs(keyword)
    wwr = extract_wwr_jobs(keyword)
    jobs = indeed + wwr
    return render_template("search.html", keyword=keyword, jobs=jobs)

6.6 For Loops

jobs가 list이기 때문에, for in 문을 사용해줘야하는데, html 상에서 구현해야하므로 그냥 for in이 아니라,

{% for job in jobs %}

이게 html 상의 for in 문이란다. 그럼 여기서 {% %}과 {{}}의 차이가 궁금하다.{% %}은 실행하고 싶은 파이썬 코드를 %와 % 사이에 넣는 것이고, {{}}은 파이썬의 변수를 넣는 것이다. 간단하다.

그래서,

<body>
  <h1>Search Results for "{{keyword}}":</h1>
  {% for job in jobs %}
    <div>{{job.link}}</div>
  {% endfor %}
</body>

search.html 파일의 코드를 이렇게 작성해주고, 실행해보면,

ㅗㅜㅑ.... 근데 이건 좀 보기에 그러니까 수정을 해줄 것이다.

<body>
  <h1>Search Results for "{{keyword}}":</h1>
  {% for job in jobs %}
    <div>
      <span>{{job.position}}</span>
      <span>{{job.company}}</span>
      <span>{{job.location}}</span>
      <a href="{{job.link}}" target="_blank">Apply now&rarr;</a>
    </div>
  {% endfor %}
</body>

코드를 수정해주고, 재 실행하면,

근데 이것도 조금 그렇다. 그래서 예쁘게 만져줄 예정이다.

6.7 Pico

pico css는 일단 갖다 쓰기만 해도 홈페이지를 적당히 예쁘게 만들어준다.
https://picocss.com/ <- 여기에 가서, 'Get Started' 버튼을 눌러준다.
누르면,

<link rel="stylesheet" href="https://unpkg.com/@picocss/pico@latest/css/pico.min.css">

이런 코드가 있는데, html 파일의 head 부분에 추가해주면 끝난다.

다크모드면 자동으로 화면을 어둡게 해주고, 어쨌든 좋은거 같긴하다 ㅎㅎ
그리고 사용할 수 있는 소소한 element들이 있는데, 아이템이 중앙에 있길 원할 시에 container를 사용해주면 된다.

<main class="container"> <- <body></body> 부분에 추가만 해주면 된다.

중앙 정렬 되었다 ㅎㅎ 이 외에도 많은 요소들이 있는데 그건 차차 활용해 볼 것이다.
이렇게 해서 물론 예전보단 보기 좋아졌지만, 그래도 테이블이 보기 좋은 관계로, 결과 값을 전부 테이블로 변경해볼 것이다.

<body>
  <main class="container">
    <h1>Search Results for "{{keyword}}":</h1>
    <table>
      <thead>
        <tr>
          <th>Position</th>
          <th>Company</th>
          <th>Location</th>
          <th>Link</th>
        </tr>
      </thead>
      <tbody>
        {% for job in jobs %}
        <tr>
          <td>{{job.position}}</td>
          <td>{{job.company}}</td>
          <td>{{job.location}}</td>
          <td><a href="{{job.link}}" target="_blank">Apply now&rarr;</a></td>
        </tr>
      {% endfor %}
      </tbody>
    </table>
  </main>
</body>

search.html 파일의 코드를 이렇게 변경해주고, 실행해보자.

굉장히 예쁘구만... 허허

이제 여기에 grid를 이용하여 가로줄을 추가해볼 것이다.

<table role="grid">

table 부분을 이렇게만 바꿔주면 된다.

그리고, 가로줄을 스크롤하고 싶다면,

<figure></figure>

사이에만 넣으면 된다.

근데, 이건 새로고침 할때마다 새로고침 하고 있어서, 꽤나 느리다. 우리는 가짜 데이터베이스 생성이 가능하므로, 이전에 수집한 정보가 있으면 다시 수집하지 않도록 하여, 웹사이트를 더 빠르게 만들 것이다.

6.8 Cache

위에서 얘기한 것을, if-else 문으로 구현해보자.

함수의 바깥에,

db = {}

라는 가짜 데이터베이스를 만들어주고,

def search():
    keyword = request.args.get("keyword")
    if keyword in db:
        jobs = db[keyword]
    else:
        indeed = extract_indeed_jobs(keyword)
        wwr = extract_wwr_jobs(keyword)
        jobs = indeed + wwr
        db[keyword] = jobs
    return render_template("search.html", keyword=keyword, jobs=jobs)

search 함수 안에 이렇게 if문만 구현해주면 된다.

아, 끝났다! 이제 졸작만 내면 이 강의도 안녕이구나.

profile
이희범이라는 사람입니다.

0개의 댓글