개발자/파이썬 Python

파이선 웹 스크래퍼 만들어 보자. 코드 2

지구빵집 2022. 11. 22. 22:38
반응형

 

 

앞의 코드 1 에서 작성한 코드를 재사용성을 높이고 파일로 별도 보관하기 위해 분리한다.

폴더 구조는 아래와 같고 main.py 코드는 아래와 같다.

 

 

replit.com 사이트에서 실습

 

from requests import get
from bs4 import BeautifulSoup
from extractors.wwr import extract_wwr_jobs

jobs = extract_wwr_jobs("python")
print(jobs)

 

위 폴더 구조 이미지에서 폴더 extractors 를 만들고 이전 작업한 코드를 wwr.py 파일로 분리하여 만들었다. wwr.py 코드는 아래와 같다.

 

from requests import get
from bs4 import BeautifulSoup

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

 

 

여기까지 리팩토링하고 main.py 에서 시작한다. 

 

우선 indeed.com 사이트에서 python으로 검색하여 결과가 나오는 것을 확인하고 URL 주소를 우리가 이용할 수 있도록 가져온다. 그러면 주소는 아래와 같이 얻는다.

 

https://kr.indeed.com/jobs?q=python&l=&vjk=bcb41b925b56a584

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

 

초반에 403 메시지가 떠서 금지된 페이지라고 뜬다. 그러니까 지금 코드를 봇이라고 파악하고 데이터를 보내지 않는다. 문제를 잡기 위해 Selenium 사이트에서 문제를 해결하기로 한다. Selenium은 실제 브라우저를 띄워 원하는 사이트에 접근하도록 돕는 일을 한다. 결과적으로 봇으로 인식하지 않게 만들어 준다. 아래는 replit을 사용하지 않는 사람은 참고한다. 강의동영상 주소 에서 시작하고, Selenium 에 대해 자세히 공부하고 싶은 사람은 마찬가지로 사이트를 참고한다. 

 

local에서 하시는 분들은 참고하세요!! (VS code 등..)

셀레니움 설치
pip install selenium (혹은 pip3 install selenium)

드라이버 설치
크롬 : https://sites.google.com/a/chromium.org/chromedriver/downloads
파이어폭스 : https://github.com/mozilla/geckodriver/releases
사파리 : https://webkit.org/blog/6900/webdriver-support-in-safari-10/
(mac은 brew가 편해요 brew install chromedriver)

나머지는 운영체제와 사용할 프로그램에 맞게 검색해서 쓰시는 것을 추천드려요!!

 

 

진행한 코드는 아래와 같다.

 

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

options = Options()
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")

browser = webdriver.Chrome(options=options)

browser.get("https://xxxxxxxxx/jobs?q=python&limit=50")

print(browser.page_source)

 

여기까지 했다면 아래 코드를 따라한다.

 


from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from bs4 import BeautifulSoup
options = Options()
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")

browser = webdriver.Chrome(options=options)

browser.get("https://xxxxxxxxxx/jobs?q=python")

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:
    print("job li")
  else:
    print("mosaic li")

 

None은 무엇인가 있어야 하는데 없다는 것을 나타내는 데이터 타입이다. False와 다르다.

 

여기까지 하고 전체 코드는

 

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

options = Options()
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")

browser = webdriver.Chrome(options = options)

#print(browser.page_source)
base_url = "xxxxxxxxxxxx/jobs?q="
search_term = "python"

browser.get(f"{base_url}{search_term}")
results = []
soup = BeautifulSoup(browser.page_source, "html.parser")
job_list = soup.find('ul', class_= "jobsearch-ResultsList css-0")
jobs = job_list.find_all('li', recursive = False)
#ul 바로밑 li만을 찾아낼 것이다
for job in jobs:
  zone = job.find("div", class_="mosaic-zone")
  #find는 찾은 element를 주거나 None을 준다
  if zone == None:#job li에서 job을 추출한다
    anchor = job.select_one("h2 a")
    title = anchor['aria-label']
    link = anchor['href']
    #print(title, link)
    #print("///////\n///////")
    company = job.find("span",class_="companyName")
    region = job.find("div",class_="companyLocation")
    job_data = {
        'link' : f"https://www.indeed.com{link}",
        'company' : company.string,
        'location' : region.string,
        'position' : title
    }
    results.append(job_data)
for result in results:
  print(result, "\n///////////\n")


#beaifulsoup은 검색결과를 list와 dictionary로 만든다
#print(results)
"""
h2 = job.find("h2",class_="jobTitle")
a = h2.find("a")
else:
print('mosaic li')
#mosaic-zone을 가진 li 구분, 필요없음
#None은 무언가 없을때 사용하는 자료형이다
"""

 

 

 

반응형