Flask
Python으로 웹사이트를 만들 수 있게 해주는 micro-framework
공식문서 / 한글화된 공식문서
url에 따른 구조



폴더 구조

venv 폴더와 requirements.txt 파일은 가상환경 사용하면서 생성함
완성 코드
main.py
from flask import Flask, render_template, request, redirect, send_file
from scrapper import get_jobs, save_to_file
app = Flask("SuperScrapper")
db = {}
# 데코레이터를 통해, 해당 루트로 접근하면 함수가 자동으로 실행됨
# 데코레이터 아래에는 함수만! 변수는 X
@app.route('/')
def home():
return render_template('home.html')
@app.route('/contact')
def contact():
return 'Contact me!'
# Dynamic URL
@app.route('/<username>')
def greeting(username):
return f'Hello {username}, how are you?'
# Query Arguments
@app.route('/report')
def report():
word = request.args.get('word')
if word:
word = word.lower()
from_db = db.get(word)
if from_db:
jobs = from_db
else:
jobs = get_jobs(word)
db[word] = jobs
else:
return redirect('/')
return render_template('report.html', resultsCount=len(jobs), word=word, jobs=jobs)
@app.route('/export')
def export():
try:
word = request.args.get('word')
if not word:
# exception(error)이 발생하면 try 블록 중단하고 except 블록 실행
raise Exception()
word = word.lower()
jobs = db.get(word)
if not jobs:
raise Exception()
save_to_file(jobs)
return send_file('jobs.csv')
except:
return redirect('/')
app.run()
scrapper.py
import requests # url로 get 요청 보내서 html 받아오기
from bs4 import BeautifulSoup # 응답으로 받은 html에서 필요한 데이터 추출하기
import csv
# -----------------------------------------------------
# Part 1. Scrapping
def extract_jobkorea_pages(url):
response = requests.get(url)
# 마지막 페이지 번호가 안 보이기 때문에 전체 공고 수를 이용
soup = BeautifulSoup(response.text, 'html.parser')
dev_tot = soup.find('strong', {'class': 'dev_tot'}).string
counts = ''
for item in dev_tot:
if '0' <= item <= '9':
counts += item
counts = int(counts)
# 한 페이지에 보여지는 공고 수 20을 이용하여 마지막 페이지 번호 구하기
max_page = counts // 20 + 1 if counts % 20 != 0 else counts // 20
return max_page
def extract_jobkorea_jobs(max_page, url):
jobs = []
for page in range(1, max_page + 1):
print(f'Scrapping page {page}')
response = requests.get(f'{url}&Page_No={page}')
soup = BeautifulSoup(response.text, 'html.parser')
posts = soup.find_all('div', {'class': 'post'})
for post in posts:
# 한 페이지의 posts 중 공고 post를 다 가져온 뒤 공고가 아닌 post를 만나면 종료
try:
title = post.find('a', {'class': 'title'})['title'].strip()
company = post.find('a', {'class': 'name'})['title'].strip()
location = post.find('span', {'class': 'loc long'}).string.strip()
link = post.find('a', {'class': 'title'})['href'].strip()
# 잡코리아 링크의 일부분이 아닌 전체 링크를 가지고 있을 경우 대비
if link[:4] != 'http':
link = "https://www.jobkorea.co.kr" + link
job = {'title': title, 'company': company, 'location': location, 'link': link}
jobs.append(job)
except:
break
return jobs
# --------------------------------------------------------
# Part 2. Saving to CSV file
# Comma Seperated Value, column은 ,로 row는 new line으로 구분
# excel 프로그램이 있어야 하는 xls와 달리 다양한 환경에서 사용할 수 있음
def save_to_file(jobs):
file = open('jobs.csv', mode="w") # 쓰기 전용으로 파일 열기
writer = csv.writer(file)
writer.writerow(['title', 'company', 'location', 'link'])
for job in jobs:
writer.writerow(list(job.values()))
return
# --------------------------------------------------------
# Part 3. Run
def get_jobs(word):
JOBKOREA_URL = f"https://www.jobkorea.co.kr/Search/?stext={word}&tabType=recruit"
last_jobkorea_page = extract_jobkorea_pages(JOBKOREA_URL)
jobkorea_jobs = extract_jobkorea_jobs(last_jobkorea_page, JOBKOREA_URL)
return jobkorea_jobs
templates/home.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Job Search</title>
</head>
<body>
<h1>Job Search</h1>
<form action="/report" method="get">
<input type="text" placeholder="Which job do you want to search?" required name="word">
<button>Search</button>
</form>
</body>
</html>
templates/report.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Job Search</title>
<style>
section {
display: grid;
gap: 20px;
grid-template-columns: repeat(4, 1fr);
}
</style>
</head>
<body>
<h1>Search Results</h1>
<h3>Found {{resultsCount}} results for {{word}}</h3>
<a href="/export?word={{word}}">Export to CSV</a>
<section>
<h4>Title</h4>
<h4>Company</h4>
<h4>Location</h4>
<h4>Link</h4>
{% for job in jobs %}
<span>{{job.title}}</span>
<span>{{job.company}}</span>
<span>{{job.location}}</span>
<a href="{{job.link}}" target="_blank">Apply</a>
{% endfor %}
</section>
</body>
</html>
결과물
/

/report?word=Vue

/export?word=Vue

jobs.csv
246.1 kB
'Clone Coding > Python으로 웹 스크래퍼 만들기' 카테고리의 다른 글
#3 Get Ready for Django(More about Python) (0) | 2022.07.04 |
---|---|
#2 Building a Web Scrapper (0) | 2022.07.04 |
#1 Python Theory (0) | 2022.07.04 |