Programming/Python 웹 스크래퍼 만들기

Python 웹 스크래퍼 & Flask 웹 사이트 구축 정리

2023. 1. 11. 21:00

Python 을 활용해서 indeed 와 wwr 웹 사이트의 구인정보들을 스크랩 하고

스크랩한 구인정보들을 Flask 로 구축한 웹 사이트로 구현해 보았다.

 

제작했던 전체 파일

전체 파일

extractors 폴더에 indeed.py 와 wwr.py ( indeed 와 wwr 웹 사이트의 구인정보를 스크랩 하는 파일 )

templates 폴더에 home.html 과 search.html ( Flask 웹 사이트 구축을 위한 template )

chromedriver.exe 는 indeed 웹 사이트를 스크랩 하기 위해 필요한 프로그램 → 관련 게시물

( webdriver 는 Python에서 브라우저를 시작할 수 있게 해준다. )

file.py 는 파일을 어떤 방식으로 저장하고 어떤 데이터를 가져와서 저장하는지 → 관련 게시물

main.py 는 각 파일들로 부터 필요한 함수들을 import 하고 Flask 로 함수를 만들어 웹 사이트와 연결.

 

 

 

< indeed.py >

from requests import get
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

def get_page_count(keyword):
    options = Options()
    options.add_experimental_option('excludeSwitches', ['enable-logging'])
    browser = webdriver.Chrome(options=options)

    base_url = 'https://kr.indeed.com/jobs?q='

    browser.get(f'{base_url}{keyword}')
    soup = BeautifulSoup(browser.page_source,'html.parser')
     
    search_count = soup.find('div',class_='jobsearch-JobCountAndSortPane-jobCount')  

    if search_count == None:
        print('검색 결과 없음')  
    else:
        search_count2 = search_count.find('span')
        print(search_count2.string)
                            
    pagination = soup.find('nav',{'aria-label':'pagination'})  
    pages = pagination.select('div a')

    count = len(pages)+1

    for page in pages:
        if page['aria-label'] == "Previous Page":
            count = count - 1
        if page['aria-label'] == "Next Page":
            count = count - 1

    if count >= 5:
        return 5
    else:
        return count


def extract_indeed_jobs(keyword):
    
    options = Options()
    options.add_experimental_option('excludeSwitches', ['enable-logging'])
    browser = webdriver.Chrome(options=options)
    pages = get_page_count(keyword)
    print("Found", pages, "pages")
    results = []
    
    for page in range(pages):
        base_url = 'https://kr.indeed.com/jobs'
        final_url = f'{base_url}?q={keyword}&start={page*10}'
        print('Requesting', final_url)
        browser.get(final_url)
       
        soup = BeautifulSoup(browser.page_source,'html.parser')
        job_list = soup.find('ul', class_='jobsearch-ResultsList')
        jobs = job_list.find_all('li', recursive=False)
        for job in jobs:
            zone = job.find('div', class_='mosaic-zone')
            if zone == None:
                anchor = job.select_one('h2 a')
                title = anchor['aria-label']
                link = anchor['href']
                company = job.find('span',class_='companyName')
                location = job.find('div',class_='companyLocation')
                job_data = {
                    'link':f'https://kr.indeed.com{link}',
                    'company': company.string.replace(","," "),
                    'location': location.string.replace(","," "),
                    'position': title.replace(","," ")
                }
                results.append(job_data)
              
    return results

 

< wwr.py >

from requests import get
from bs4 import BeautifulSoup

def extract_wwr_jobs(keyword):
    base_url = "https://weworkremotely.com/remote-jobs/search?utf8=%E2%9C%93&term="

    response = get(f'{base_url}{keyword}')
    if response.status_code != 200:
        print("Can't request website")
    else:
        results =[]
        soup = BeautifulSoup(response.text,'html.parser')
        jobs = soup.find_all('section', class_="jobs")
        for job_section in jobs:
            job_posts = job_section.find_all('li')
            job_posts.pop(-1)
            for post in job_posts:
                anchors = post.find_all('a')
                anchor = anchors[1]
                link = anchor['href']
                company, kind, region = anchor.find_all('span',class_='company')
                title = anchor.find('span', class_='title')
                job_data = {
                    'link': f"https://weworkremotely.com/{link}" ,
                    'company': company.string.replace(","," "),
                    'location': region.string.replace(","," "),
                    'position': title.string.replace(","," ")
                }
                results.append(job_data)
        return results

 

< 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 Scrapper</title>
    <link rel="stylesheet" href="https://unpkg.com/@picocss/pico@latest/css/pico.min.css">
</head>
<body>
    <main class="container">
        <h1>Job Scrapper</h1>
        <h4>What job do you want?</h4>
        <form action="/search" method="get">
            <input type="text" name="keyword" placeholder="Write keyword please" />
            <button>Search</button>
        </form>
    </main>   
</body>
</html>

 

< search.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 Scrapper</title>
    <link rel="stylesheet" href="https://unpkg.com/@picocss/pico@latest/css/pico.min.css">
</head>
<body>
    <main class="container">
        <h1>Search Results for "{{keyword}}":</h1>
        <hgroup>
            <a target="_blank" href="export?keyword={{keyword}}">Export to file</a>
        </hgroup>
        <figure><table role="grid">
            <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></figure>      
    </main>
</body>
</html>

 

< file.py >

def save_to_file(file_name, jobs):
    file = open(f'{file_name}.csv','w',encoding='utf-8-sig')
    file.write('Postition,Company,Location,URL\n')

    for job in jobs:
        file.write(f"{job['position']},{job['company']},{job['location']},{job['link']}\n")

    file.close()

 

< main.py >

from flask import Flask, render_template, request, redirect, send_file
from extractors.indeed import extract_indeed_jobs
from extractors.wwr import extract_wwr_jobs
from file import save_to_file

app = Flask("JobScrapper")

db = {}

@app.route("/")
def home():
    return render_template("home.html", name="james", age=20)

@app.route("/search")
def search():
    keyword = request.args.get("keyword")
    if keyword == None:
        return redirect("/")
    if keyword == "":
        return redirect("/")
    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 )

@app.route("/export")
def export():
    keyword = request.args.get("keyword")
    if keyword == None:
        return redirect("/")
    if keyword == "":
        return redirect("/")
    if keyword not in db:
        return redirect(f"/search?keyword={keyword}")
    save_to_file(keyword, db[keyword])
    return send_file(f"{keyword}.csv", as_attachment=True)

app.run("127.0.0.1")

 

main.py 코드 실행 시 콘솔창

 

크롬 ( 브라우저  ) 열고 url 에 127.0.0.1:5000 입력하여 Job Scrapper 웹사이트 접속

 

python 검색

 

 

python 검색 결과 ( indeed 와 wwr 웹 사이트에서 구인정보들 스크랩 해서 Flask 웹 사이트로 구현 )

 

 

Apply now 클릭 시 새 창이 열리면서 해당 구인공고로 이동

 

 

Export to file 클릭 시 "python" 검색어로 검색했던 indeed 와 wwr 웹 사이트 구인정보를 스크랩 하여 csv 파일로 저장.

 

 

저장된 python.csv 파일을 엑셀로 열면 Position, Company, Location, URL 이 정리되어 있다.

 

 

 

 

 

 

 


python 참고 강의

https://nomadcoders.co/python-for-beginners/lobby

'Programming > Python 웹 스크래퍼 만들기' 카테고리의 다른 글

Python Flask 웹 사이트 다운로드 버튼 만들기  (1) 2023.01.10
Python Flask 가짜 DB 만들어서 웹사이트 속도 향상 시키기  (0) 2023.01.09
Flask 웹 사이트 Pico CSS 사용해서 꾸미기  (0) 2023.01.06
Python Flask 로 HTML 에서 For 문 사용  (0) 2023.01.05
Python Flask Arguments  (0) 2023.01.02
'Programming/Python 웹 스크래퍼 만들기' 카테고리의 다른 글
  • Python Flask 웹 사이트 다운로드 버튼 만들기
  • Python Flask 가짜 DB 만들어서 웹사이트 속도 향상 시키기
  • Flask 웹 사이트 Pico CSS 사용해서 꾸미기
  • Python Flask 로 HTML 에서 For 문 사용
Security Engineer
Security Engineer
IT 공부
IT-logIT 공부
Security Engineer
IT-log
Security Engineer
전체
오늘
어제
  • 분류 전체보기 (171) N
    • Programming (39)
      • Python 웹 스크래퍼 만들기 (39)
    • IT 지식 (64) N
      • IT 정보 (27)
      • CS 기초 (24)
      • 운영체제 (8)
      • IT 인프라 기초 (5) N
    • 보안 (45)
      • 악성코드 분석 (10)
      • Bandit 워게임 (25)
      • 취미로 해킹 2 (6)
      • 환경 구축 (4)
    • 웹 해킹 (23)
      • 웹 기초 지식 (8)
      • SQL 기본 (2)
      • 웹 해킹 및 시큐어 코딩 기초 (13)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • Web
  • flask
  • webScrapper
  • 취미로 해킹
  • Selenium
  • 시큐어 코딩
  • 워게임
  • 컴퓨터
  • 웹 개발
  • 웹 해킹
  • 취미로해킹
  • overthewire
  • WarGame
  • Beautifulsoup
  • Python
  • IT 인프라
  • 해킹
  • 파이썬
  • 모의해킹
  • 운영체제
  • CSS
  • 악성코드 분석
  • 리눅스
  • 악성코드
  • bandit
  • Def
  • 웹
  • CS
  • CS 기초
  • HTML

최근 댓글

최근 글

hELLO · Designed By 정상우.
Security Engineer
Python 웹 스크래퍼 & Flask 웹 사이트 구축 정리
상단으로

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.