Flask: Python을 이용해서 웹사이트를 구축할 수 있는 micro framework
micro framework인 이유: 겁나 작고, 겁나 쉬워서, 어떻게 동작하는지 이해하기가 쉬워, 누구나 10분이면 쓸 수 있기 때문이다.
UI를 구축하는 작업을 한다는데, 다행히 CSS보다는 HTML을 많이 한댄다. 둘 다 극혐하긴 하지만, 그래도 HTML이 조금 더 나은 거 같아서 다행 ㅎㅎ
우리는 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를 방문했을 때 이 함수를 호출해야한다는 것을 알려줌.
그리고 실행 해보면,
잘 나오더라 ㅎㅎ
이제는 사용자에게 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의 코드는 이렇게 적어주자({{}}이 중요)
파이썬이 백엔드 역할을 한다! 개꿀 ㅎㅎ
<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을 하나 더 만들자. 그리고 나서 재실행 해보면,
이렇게 잘 나오더라.
그냥 복습인데, action은 form이 기본적으로 get method를 가지고 있어서 작동하는 것이라고 카카오톡 클론 코딩 강의에서 얘기했었댄다. 난 안배웠는데 ㅎㅎ
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)
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→</a>
</div>
{% endfor %}
</body>
코드를 수정해주고, 재 실행하면,
근데 이것도 조금 그렇다. 그래서 예쁘게 만져줄 예정이다.
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→</a></td>
</tr>
{% endfor %}
</tbody>
</table>
</main>
</body>
search.html 파일의 코드를 이렇게 변경해주고, 실행해보자.
굉장히 예쁘구만... 허허
이제 여기에 grid를 이용하여 가로줄을 추가해볼 것이다.
<table role="grid">
table 부분을 이렇게만 바꿔주면 된다.
그리고, 가로줄을 스크롤하고 싶다면,
<figure></figure>
사이에만 넣으면 된다.
근데, 이건 새로고침 할때마다 새로고침 하고 있어서, 꽤나 느리다. 우리는 가짜 데이터베이스 생성이 가능하므로, 이전에 수집한 정보가 있으면 다시 수집하지 않도록 하여, 웹사이트를 더 빠르게 만들 것이다.
위에서 얘기한 것을, 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문만 구현해주면 된다.
아, 끝났다! 이제 졸작만 내면 이 강의도 안녕이구나.