Flask로 기초적인 웹페이지 제작
Flask로 웹페이지 제작 기초적인 html 작성 scrape 기능 모듈화 및 적용 csv 파일 작성 및 저장 기능 모듈화 및 적용 html 요소 추가
- 모듈화는 모든 기능이 keyword 기준으로 작동하게 진행
Flask
flask 설치
source myenv/bin/activate
pip install flask
- flask 모듈 적용
- flask는 많은 모듈과 함께 사용하기에 용이
- 충돌 방지를 위해 가상환경에서 제작 추천
from flask import Flask, # app 객체 생성
render_template, # html 페이지 렌더링 # html 파일 필요
request, # 요청에 대한 정보
redirect, # url로 이동(정적) # url_for(변동 가능)
send_file # file 다운로드
flask 기본 구조 작성
__name__개념:
직접 실행된 모듈 = __main__
import된 모듈 = __파일명__
처음 실행한 스크립트 파일의 __name__은 __main__
어떤 스크립트든 main으로도 모듈로도 쓰일 수 있기 떄문에 중요
app = Flask(__name__) # app 생성
@app.route('/')
# / 는 홈페이지를 뜻함
# 데코레이터 = 홈페이지에서 실행 할 함수를 보여줌
def home():
return render_template('home.html')
if __name__== '__main__':
# flask 실행되는 스크립트가 시작점(main)인지 모듈로 사용되는지 판단
app.run(debug=True)
# debug=Ture =코드를 갱신할 때마다 서버 갱신
html 작성
- meta 데이터 설정이 많이 복잡함
- html 설정은 버전에 따라 지원하는 기능이 다를 수 있음
scrap 모듈화
- 기능을 keyword 중심으로 통합
- .find()의 None type 에러 예외처리 탐색 결과가 None 일 때 no result를 출력하도록 설정
import requests
from requests import get
from bs4 import BeautifulSoup
# 여러개의 함수로 기능했던 것을 하나의 함수로 정리
def b_scrap(keyword):
url = f'https://berlinstartupjobs.com/skill-areas/{keyword}/'
response = requests.get(url, headers={"User-Agent": "Mozilla/5.0"})
soup = BeautifulSoup(response.content, 'html.parser')
all_jobs = []
search_result = soup.find('ul', class_ = 'jobs-list-items')
# 검색 과정에서 Attribut Error 가 발생하던 것 예외처리
if search_result is not None:
jobs = soup.find('ul', class_ = 'jobs-list-items').find_all('li')
for job in jobs:
position = job.find('h4', class_ = 'bjs-jlid__h').text,
company = job.find('a', class_ = 'bjs-jlid__b').text,
location = job.find('div', class_ = 'bjs-jlid__description').text,
link = job.find('div', class_ = 'links-box').text
job_data = {'position' : position, 'company' : company, 'location' : location, 'link' : link}
all_jobs.append(job_data)
# 잘못된 탐색이나 탐색 결과값이 없어서 None type Error를 발생시키는 경우
# '결과없음' 결과값으로 유도하여 예외처리
else:
job_data = {
'position' : 'Brl has no result',
'company' : 'Brl has no result',
'location' : 'Brl has no result',
'link' : 'Brl has no result'
}
all_jobs.append(job_data)
return all_jobs
# keyword를 입력하면 탐색된 직업들의 리스트를 반환
csv 파일 작성 및 저장 모듈화
- keyword를 파일명으로 keyword에 따라 탐색된 jobs를 내용으로 작성
- 반드시 file.close()로 닫아줘야 한다
def save_to_file(file_name, jobs):
file = open(f'/Users/사용자이름/myenv/JobScrapper/{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()
html 요소 추가 ¶
- Github Pages : Jekyll 사용
- post 내부에 html 코드가 포함되면 markdown을 html로 변환하는 과정에 오류 발생
- 별도의 링크로 연결하여 내용 대체
검색기능 추가
- main, container 사용하여 컨텐츠가 중앙에 맞춰 공간을 사용하도록 설정
- 검색 버튼과 텍스트를 받는 input 추가
- action을 통해 검색결과로 이동
db 설정 & 검색 결과 기능 작성
- 검색 결과를 저장할 db설정(같은 내용 호출 시 빠르게 반응)
db = {}
# cache data
# 한번 추출한 데이터를 보관하여 다른 사용자가 왔을 때 제공
# 사이트를 새로고침 할때마다 다시 불러오지 않도록
# function들 밖에 위치시킴
- 사용자가 입력한 keyword를 request 로 받아옴
- keyword를 통해 jobs 탐색(db에 있으면 바로 호출)
@app.route('/search')
def search():
keyword = request.args.get("keyword")
# python으로 검색할 경우 request.args로 keyword python 두가지 인자를 얻음
# keyword를 get으로 가져옴 keyword = python
if keyword == None:
return redirect("/")
# search 입력값이 없을 경우 홈페이지로 이동
if keyword in db:
jobs = db[keyword]
# db에 이미 정보가 있는 경우 그대로 사용
else:
berlin = b_scrap(keyword)
wwr = wwr_scrap(keyword)
web3 = w3_scrap(keyword)
# 이전에 제작한 스크래퍼를 모듈로 가져옴
jobs = berlin + wwr + web3
db[keyword] = jobs
return render_template('search.html', keyword = keyword, jobs = jobs)
# keyword를 html로 보냄
# jobs를 보냄
검색결과 html 작성
- table 기능추가- thead tbody tfoot 구조
- figure 안에 table을 넣으면 크기 반응형(모바일 환경)에 대응 가능
- %% 에사용하고자 하는 파이썬 코드 삽입
csv 파일 추출
- 파일을 추출하려면 탐색과정을 거쳐야 함
- 검색 과정 없이 추출 페이지로 가는 것을 막는 처리가 필요
- keyword를 입력하지 않으면 홈페이지로 이동하도록 설정
- export 버튼을 누르면 파일이 추출되고 다운로드됨
@app.route('/export')
def export():
keyword = request.args.get("keyword")
if keyword == None:
return redirect("/")
if keyword not in db:
return redirect(f'/search?keyword={keyword}')
# db에 해당 데이터가 없을 경우 검색결과 화면으로 이동
save_to_file(keyword, db[keyword])
return send_file(f'{keyword}.csv', as_attachment = True)