https://weworkremotely.com 에서 스크래핑
- 웹사이트에서 python을 검색해보면 Url 끝부분이 다음과 같은 것을 확인할 수 있다.
https://weworkremotely.com/remote-jobs/search?&term=python
따라서 그 부분을 활용하여 스크래핑을 다음과 같이 수행하려 한다.
1. base url을 정의
2. 검색어(search_term)을 정의
3. requests 패키지를 사용하여 get 요청으로 response를 받는다.
4. Html 파서인 BeautifulSoup 패키지를 사용한다.
5. 해당하는 태그만 추출하여 데이터를 가공한다.
6. 데이터를 dictionary 형태로 만들고 return한다.
BeautifulSoup라는 패키지 처음 써봤는데 너무 아름답다(...)
코드는 아래와 같다.
공부용으로 주석을 열심히 달아보았다.
from requests import get
from bs4 import BeautifulSoup
base_url = "https://weworkremotely.com/remote-jobs/search?&term="
search_term = "python" #언제든 바뀔 수 있음
#get 요청
response = get(f"{base_url}{search_term}")
if response.status_code != 200:
print("Can't request website")
else:
results = []
#웹사이트를 구성하는 Html코드를 가져옴
#response.text
soup = BeautifulSoup(response.text, "html.parser")
#find_all html코드에서 해당하는것을 다 찾아줌
#class가 jobs인 section를 모두 찾아줌
#keyword argument class_ = "jobs", 순서 상관없어짐
jobs = soup.find_all('section', class_="jobs")
for job_section in jobs:
#li 태그만 가져옴
job_posts = job_section.find_all('li')
#마지막 li태그에 들어간 view all 부분은 제외해줘야함
job_posts.pop(-1)
for post in job_posts:
#a태그를 다 가져옴
anchors = post.find_all('a')
#a 태그 중 두번째, 필요한 것만 저장
anchor = anchors[1]
#html태그를 bs4 entity로 만들 수 있음
#bs4 덕분에 dictionary 처럼 href에 url이 매칭되어 저장
link = anchor['href']
#회사명,포지션,지역 순서를 알기 때문에 이렇게 하기
company, position, region = anchor.find_all('span', class_="company")
#타이틀 얻기
title = anchor.find('span',class_='title')
#dictionary로 만들고 for Loop 밖에 저장하기
job_data ={
'link' : f"https://weworkremotely.com{link}",
'company':company.string,
'location': location.string,
'position': title.string
}
results.append(job_data)
return results
https://kr.indeed.com 에서 스크래핑
wwr에서는 requests와 bs4만으로 예쁘게 스크래핑을 할 수 있었다.
문제는 indeed에서 발생했다.
아래와 같이 동일한 방법으로 indeed의 채용 정보를 가져오려고 하는데...
base_url = "https://kr.indeed.com/jobs?q="
search_term = "python"
403 오류가 떴다.
bot을 막아놓으면 이렇게 뜬다고 하더라.
그렇다면
당황하지 않고 셀레니움을 사용하는 방법이 있다.
셀레니움이란?
간단히 말하자면 웹 애플리케이션 자동화 및 테스트를 위한 포터블 프레임워크다.
마치 우리가 웹 사이트를 이용하는 것처럼 브라우저를 자동화 할 수 있다.
자세한 것은 따로 포스팅 하기로 하고 일단은 기능 구현을 위해 셀레니움과 웹 드라이버 설치가 필요하다.
1. 로컬에서 설치
pip3 install selenium
brew install chromedriver
MacOS를 쓰고있기 때문에 간단히 명령어로 설치를 했다.
2. replit에서 설치
강의 내용을 그대로 따라하면 된다.
이제 indeed에서도 필요한 채용 정보를 추출할 수 있다.
그런데 또 고민거리가 생겼다.
이대로의 코드라면 1페이지의 정보만 가져온다.
5페이지 정도는 가져와야 데이터의 양이 적절하다는 생각이 들었다.
모든 정보를 요청하면 서버에 무리를 줄 수 있으므로 적정양을 1차 목표로 잡았다.
그렇다면 새로운 기능이 필요하다.
아래와 같이 해결방법을 정의했다.
1. 검색결과 수에 따라 페이지 수는 다르다.
2. 페이지 수를 알아야 한다.
3. 추출은 페이지 수 만큼 반복된다.
4. 페이지는 1페이지일 때 10, 2페이지일 때 20이 url에 표시된다.
indeed에서 페이지 수를 카운트하고, 채용정보를 추출하는 코드는 다음과 같다.
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
#replit에서 돌아가게 하려고 하는 설정
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
browser = webdriver.Chrome(options=options)
def get_page_count(keyword):
base_url = "https://kr.indeed.com/jobs"
#end_url = "&limit=50"
browser.get(f"{base_url}?q={keyword}")
soup = BeautifulSoup(browser.page_source,"html.parser")
pagination = soup.find("nav", role="navigation")
pages = pagination.find_all("div", recursive=False)
count = len(pages)
if count == 0:
return 1
elif 3<=count<=5:
return count-1
elif count >= 6:
return 5
def extract_indeed_jobs(keyword):
pages = get_page_count(keyword)
#print("Found",pages,"pages")
results =[]
for page in range(pages):
base_url = "https://kr.indeed.com/jobs"
#end_url = "&limit=50"
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")
#한 Depth만 검색하고 싶으면 recursive=False
jobs = job_list.find_all('li',recursive=False)
# mosaic-zone은 필요없는 정보
for job in jobs:
zone = job.find("div", class_="mosaic-zone")
if zone == None:
#h2 안에 있는 a 가져옴
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 추출 때와 다른 점이 또 있다.
job_data를 정의할 때 받아 온 company, location, title 값에서 모두 콤마(,)를 없애주었다.
해당 데이터를 최종적으로는 csv 파일로 export 시킬 것이라 값 안에 콤마(,)가 있으면 데이터 가공에 혼란이 오더라.
그래서 replace 메서드를 이용했다.
다음 포스팅에서는 csv파일로 만드는 방법과 flask 맛보기로 웹서버에 웹 스크래퍼가 가져온 데이터를 뿌려볼 것이다.
해당 포스팅은 노마드 코더의 무료 강의 수강 후 개인 공부한 내용입니다.
강의 링크
https://nomadcoders.co/python-for-beginners/lobby
'💻dev > 🐍Python' 카테고리의 다른 글
Python | 파이썬 웹 스크래퍼 만들기 - 04 (0) | 2023.03.09 |
---|---|
Python | 파이썬 웹 스크래퍼 만들기 - 03 (0) | 2023.03.05 |
Python | 웹 크롤링이랑 웹 스크래퍼 뭔 차이임? (0) | 2023.03.04 |
Python | 파이썬 웹 스크래퍼 만들기 - 01 (0) | 2023.03.04 |
Python | 파이썬 기초 문법 (0) | 2023.03.02 |