Python/Web Scraping

[Python] #2.13 StackOverflow Finish (#코딩공부)

함께 공부해요 2020. 2. 24. 23:59

https://youtu.be/Ag57YaOl-IQ


<복습>

https://wook-2124.tistory.com/42

 

[Python] #2.11 StackOverflow extract job / #2.12 part Two (#코딩공부)

https://youtu.be/IbCsBC11hWs <복습> https://wook-2124.tistory.com/40 [Python] #2.10 StackOverflow extract jobs (#코딩공부) https://youtu.be/KE6_1Idtc6c <복습> https://wook-2124.tistory.com/38 [Pytho..

wook-2124.tistory.com


<준비물>

https://repl.it/

 

The world's leading online coding platform

Powerful and simple online compiler, IDE, interpreter, and REPL. Code, compile, and run code in 50+ programming languages: Clojure, Haskell, Kotlin (beta), QBasic, Forth, LOLCODE, BrainF, Emoticon, Bloop, Unlambda, JavaScript, CoffeeScript, Scheme, APL, Lu

repl.it

https://github.com/psf/requests

 

psf/requests

A simple, yet elegant HTTP library. Contribute to psf/requests development by creating an account on GitHub.

github.com

https://www.crummy.com/software/BeautifulSoup/

 

Beautiful Soup: We called him Tortoise because he taught us.

 

www.crummy.com


<코드기록>

# return 값을 잘 불러오긴 하지만 <span> 값이 같이 출력되서 번잡함
import requests
from bs4 import BeautifulSoup

URL = f"https://stackoverflow.com/jobs?q=python&sort=i"

def get_last_page():
  result = requests.get(URL)
  soup = BeautifulSoup(result.text, "html.parser")
  pages = soup.find("div", {"class":"s-pagination"}).find_all("a")
  last_page = pages[-2].get_text(strip=True)
  return int(last_page)

def extract_job(html):
  title = html.find("h2", {"class":"fs-body3"}).find("a")["title"]
  company, location = html.find("h3", {"class":"fs-body1"}).find_all("span", recursive=False)
  company.get_text(strip=True)
  location.get_text(strip=True).strip("-").strip(" \r").strip("\n")
  job_id = html["data-jobid"]
  return {"title": title, "company": company, "location": location, "link": f"https://stackoverflow.com/jobs/{job_id}"}

def extract_jobs(last_page):
  jobs = []
  for page in range(last_page):
    result = requests.get(f"{URL}&pg={page + 1}")
    soup = BeautifulSoup(result.text, "html.parser")
    results = soup.find_all("div", {"class":"-job"})
    for result in results:
      job = extract_job(result)
      print(job)
      jobs.append(job)
  return jobs

def get_jobs():
  last_page = get_last_page()
  jobs = extract_jobs(last_page)
  return jobs


# company.string / location.string을 붙여서 return해줌
# 결과는 나쁘지 않지만 여전히 띄어쓰기가 복잡함
def extract_job(html):
  title = html.find("h2", {"class":"fs-body3"}).find("a")["title"]
  company, location = html.find("h3", {"class":"fs-body1"}).find_all("span", recursive=False)
  company.get_text(strip=True)
  location.get_text(strip=True)
  job_id = html["data-jobid"]
  return {"title": title, "company": company.string, "location": location.string, "link": f"https://stackoverflow.com/jobs/{job_id}"}


# sof.py 최종 코드
import requests
from bs4 import BeautifulSoup

URL = f"https://stackoverflow.com/jobs?q=python&sort=i"

def get_last_page():
  result = requests.get(URL)
  soup = BeautifulSoup(result.text, "html.parser")
  pages = soup.find("div", {"class":"s-pagination"}).find_all("a")
  last_page = pages[-2].get_text(strip=True)
  return int(last_page)

def extract_job(html):
  title = html.find("h2", {"class":"fs-body3"}).find("a")["title"]
  company, location = html.find("h3", {"class":"fs-body1"}).find_all("span", recursive=False)
  company.get_text(strip=True)
  location.get_text(strip=True)
  job_id = html["data-jobid"]
  return {"title": title, "company": company.string, "location": location.string, "link": f"https://stackoverflow.com/jobs/{job_id}"}

def extract_jobs(last_page):
  jobs = []
  for page in range(last_page):
    print(f"Scrapping SOF: Page: {page}")
    result = requests.get(f"{URL}&pg={page + 1}")
    soup = BeautifulSoup(result.text, "html.parser")
    results = soup.find_all("div", {"class":"-job"})
    for result in results:
      job = extract_job(result)
      jobs.append(job)
  return jobs

def get_jobs():
  last_page = get_last_page()
  jobs = extract_jobs(last_page)
  return jobs


# indeed.py 최종 코드
import requests
from bs4 import BeautifulSoup

LIMIT = 50
URL = f"https://www.indeed.com/jobs?q=python&limit={LIMIT}"

def get_last_page():
    result = requests.get(URL)
    soup = BeautifulSoup(result.text, "html.parser")
    pagination = soup.find("div", {"class": "pagination"})

    links = pagination.find_all('a')
    pages = []
    for link in links[:-1]:
        pages.append(int(link.string))

    max_page = pages[-1]
    return max_page

def extract_job(html):
    title = html.find("div", {"class": "title"}).find("a")["title"]
    company = html.find("span", {"class": "company"})
    company_anchor = company.find("a")
    if company:
      if company_anchor is not None:
          company = str(company_anchor.string)
      else:
          company = str(company.string)
      company = company.strip()
    else:
      company = None
    location = html.find("div", {"class": "recJobLoc"})["data-rc-loc"]
    job_id = html["data-jk"]
    return {
        'title': title,
        'company': company,
        'location': location,
        "link": f"https://www.indeed.com/viewjob?jk={job_id}"
    }

def extract_jobs(last_page):
  jobs = []
  for page in range(last_page):
    print(f"Scrapping Indeed: Page: {page}")
    result = requests.get(f"{URL}start={page * LIMIT}")
    soup = BeautifulSoup(result.text, "html.parser")
    results = soup.find_all("div", {"class": "jobsearch-SerpJobCard"})
    for result in results:
      job = extract_job(result)
      jobs.append(job)
  return jobs

def get_jobs():
  last_page = get_last_page()
  jobs = extract_jobs(last_page)
  return jobs


# main.py 최종 코드
from indeed import get_jobs as get_indeed_jobs
from sof import get_jobs as get_sof_jobs

indeed_jobs = get_indeed_jobs()
sof_jobs = get_sof_jobs()

jobs = indeed_jobs + sof_jobs
print(jobs)

1. URL링크(지원링크) 가져오기

URL링크를 찾기 위해서 F12(inspection, 검사)를 통해서 살펴봤다.

 

a(anchor) href 안에 URL 링크가 들어있는 것을 확인하고,

 

훨씬 상위 class(father class)의 div data-jobid="351229"를 지원링크에서도 찾을 수 있는지 확인해보자.

 

URL 지원링크에서 jobs뒤의 숫자가 data-jobid의 값과 일치하는 것을 알 수 있다.

 

그리고 URL링크 숫자 뒤에 python-software-engineer-revolut은 google 검색을 위한 것이다.

이걸 지우고 숫자까지만 입력해도 이 지원링크 페이지로 이동된다.


2. link 추출하기

job_id = html["data-jobid"] 변수명을 정하고, link는 f(format)으로 {job_id}을 arguments(인자화)해준 뒤 추출시작!

 

오류없이 출력이 됐지만, span으로 인해 깔끔하지 않은 모습이다. 때문에 .strip으로 수정하는 코드 3개를 적고 다시 출력해봤지만 결과는 동일했다.

 

떄문에 .string을 company와 location 뒤에 붙여서 출력했는데, 빈칸과 몇 개의 값이 잘 나오지 않았다.

 

깔끔하게 추출하게 추출하면 좋겠지만, 결과를 보기 위해서 일단 그대로 진행하기로 했다.


3. 최종 출력하기

일단 결과를 보기 위해 그대로 진행함에 따라 indeed 추출과 동일하게 제시문이 먼저 출력 되게끔 문장을 추가했다.

 

 indeed.py 역시 제시문이 먼저 출력되게끔 수정해줬다.

 

main.py에서 sof와 겹쳐서 출력되지 않도록 주석처리 해두었던 indeed 주석처리를 해제하고, 두 개의 리스트를 함께 출력해보자..!!

 

Page가 0부터 시작하지만 잘 돌아간다! {page + 1} 코드문으로 나중에 손 봐야겠다.

 

Indeed + StackOverFlow Web Scraping 성공!! :)


※ 신종 코로나 바이러스 조심하세요!!!!