어두운 proxyscrape 로고

Web Scraping For Job Postings – An Ultimate 2024 Guide

Python, 스크래핑, 1월-04-20235분 읽기
채용 공고 웹 스크래핑은 구직자가 현재 채용 공고의 데이터베이스를 만들 수 있는 또 다른 지름길입니다. Randstad에 따르면 구직자들은 입사 지원 후 채용이 확정될 때까지 평균 5~6개월 동안 구직 활동을 한다고 합니다. 모든 구직 포털을 샅샅이 뒤져 자신에게 맞는 것을 골라야 하는 부담을 줄일 수 있는 솔루션이 있다면 어떨까요? 

이 글에서는 채용 공고에 대한 웹 스크래핑을 수행하는 방법을 설명합니다. 여러분은 구직 시장에서 최고의 일자리를 찾으려고 노력하고 있습니다. 하지만 더 스마트하게, 더 열심히 일하고 싶으실 겁니다. 채용 공고를 수집하고 파싱하는 웹 스크레이퍼를 만들어 보세요. 한 번 설정해두면 풍부한 데이터를 깔끔한 형식으로 제공하므로 수동으로 반복해서 확인할 필요가 없습니다. 이제 시작해보겠습니다.

채용 공고용 웹 스크래핑이란 무엇인가요?

채용 공고용 웹 스크래핑은 여러 취업 포털에서 데이터를 자동으로 수집하는 솔루션으로, 각 웹사이트에서 데이터를 가져오는 시간을 줄여줍니다. 채용 공고의 전체 데이터베이스를 제공할 수 있는 이러한 도구가 있으면 작업이 몇 배로 간소화됩니다. 자신에게 적합한 채용 정보를 필터링하고 지원 절차를 진행하기만 하면 됩니다. 

그래서 여러분은 구직 시장에서 최고의 직업을 찾으려고 노력하고 있습니다. 하지만 더 스마트하게, 더 열심히 일하고 싶으실 겁니다. 채용 공고를 수집하고 파싱하는 웹 스크레이퍼를 만들어보는 건 어떨까요? 한 번 설정해두면 풍부한 데이터를 깔끔한 형식으로 제공하므로 수동으로 반복해서 확인할 필요가 없습니다. 이제 시작해보세요.

[면책 조항! 많은 웹사이트는 페이지에서 데이터를 스크랩하는 것을 제한할 수 있습니다. 사용자가 정보를 추출하려고 시도하는 위치와 방법에 따라 법적 문제가 발생할 수 있습니다. 따라서 데이터를 보관하는 사이트를 살펴볼 때는 각별히 주의해야 합니다. 예를 들어 페이스북, 링크드인, 크레이그리스트는 페이지에서 데이터를 스크랩할 때 신경을 쓰는 경우가 있습니다. 따라서 스크랩을 하려면 자신의 책임 하에 스크랩하세요.]

이 글은 indeed.com에서 "데이터 과학"과 관련된 직무에 관한 유용한 정보를 추출하여 웹 스크래핑의 기본을 살펴보는 매우 기본적인 글입니다. 작업을 수동으로 여러 번 업데이트하는 놀라운 프로그램을 작성할 것입니다. 이 스크래퍼를 만드는 동안 매우 유용하게 사용할 수 있는 라이브러리는 "requests"와 "BeautifulSoup"입니다.

URL 및 페이지 구조 이해

먼저 실제로 추출할 샘플 페이지를 살펴보겠습니다. 

URL의 구조는 매우 중요합니다:

  • 참고 "q="는 페이지의 "what" 필드에 대한 문자열을 시작하며, 검색어를 "+"로 구분합니다(예: "데이터+과학자" 직업 검색).
  • 급여를 지정할 때 급여 수치에서 쉼표로 구문 분석하므로 급여의 시작 부분에 %24를 앞에 두고 첫 쉼표 앞의 숫자를 %2C로 나누고 나머지 숫자로 계속됩니다(예: %2420%2C000 = $20,000).
  • 참고 "&l="는 관심 도시의 문자열을 시작하며, 도시가 두 단어 이상인 경우 "+"로 검색어를 구분합니다(예: "New+York.").
  • 참고 "&start="는 시작하려는 검색 결과를 표시합니다(예: 10번째 결과부터 시작).

이 URL 구조는 스크래퍼를 계속 구축하고 여러 페이지에서 데이터를 수집하는 데 큰 도움이 될 것입니다. 

Chrome은 페이지를 마우스 오른쪽 버튼으로 클릭하고 요소 검사 옵션을 사용하여 페이지의 HTML 구조를 검사할 수 있습니다. 오른쪽에 메뉴가 나타나고 중첩된 요소 태그도 표시되며 해당 요소에 커서를 놓으면 화면에서 해당 부분이 강조 표시됩니다.  

이 글에서는 태그, div 등과 같은 HTML에 대한 기본 사항을 알고 있다고 가정하지만 다행히도 모든 것을 알 필요는 없습니다. 페이지 구조와 다양한 컴포넌트 계층 구조만 이해하면 됩니다.

스크레이퍼 시작하기

이제 페이지 구조를 분석했습니다. 이렇게 하면 해당 정보에 따라 코드를 작성하여 원하는 데이터를 가져오는 데 도움이 됩니다. 먼저 라이브러리를 가져오는 것으로 시작하겠습니다. 여기에서는 정보를 스크랩할 때 사이트 서버에 과부하가 걸리지 않도록 '시간'도 가져오고 있다는 점에 유의하세요.

요청 가져오기 
import bs4
bs4에서 BeautifulSoup를 가져옵니다.
팬더를 pd로가져 오기
가져오기 시간

먼저 단일 페이지를 타겟팅하여 원하는 각 정보를 철회합니다,

URL = "https://www.indeed.com/jobs?q=data+과학자+%2420%2C000&l=New+York&start=10"
#위에 명시된 URL의 요청을 수행합니다:
page = requests.get(URL)
#html 파서를 사용하여 원하는 형식의 "페이지" 지정 - 이렇게 하면 파이썬이 페이지를 하나의 긴 문자열로 취급하지 않고 페이지의 다양한 구성 요소를 읽을 수 있습니다.
soup = BeautifulSoup(page.text, "html.parser")
#수프를 보다 구조화된 트리 형식으로 인쇄하여 읽기 쉽게 만듭니다.
print(soup.prettify())

프리티파이를 사용하면 페이지의 HTML 코딩에 대한 개요를 쉽게 파악할 수 있으며 다음과 같은 출력을 제공합니다,

 이제 관심 있는 페이지의 모든 정보는 변수 "soup"에 있습니다. 필요한 정보를 캡처하기 위해 다양한 태그와 하위 태그를 반복해서 살펴보기 위해 코드를 더 자세히 살펴봐야 합니다.

데이터의 기본 요소 가져오기

모든 채용 공고의 5가지 핵심 사항은 다음과 같습니다,

  1. 직책.
  2. 회사 이름.
  3. 위치.
  4. 급여.
  5. 직무 요약.

페이지를 살펴보면 15개의 채용 공고가 있습니다. 따라서 코드도 15개의 서로 다른 항목을 생성해야 합니다. 그러나 코드가 이보다 적은 수의 항목을 제공하는 경우 페이지를 다시 참조하여 캡처되지 않는 항목을 확인할 수 있습니다.

직책 얻기

As can be seen, the entirety of each job posting is under <div> tags, with an attribute “class” = “row result.”

Further, we could also see that job titles are under <a> tags, with the attribute “title = (title)”. One can see the value of the tag’s attribute with tag[“attribute”], so I can use it to find each posting’s job title.

요약하면, 우리가 보게 될 함수는 다음 세 단계로 구성됩니다,

  1. Pulling out all the <div> tags with class including “row”.
  2. Identifying <a> tags with attribute “data-tn-element”:”jobTitle”
  3. For each of these <a> tags, find attribute values “title”
def extract_job_title_from_result(soup): 
  jobs = []
  for div in soup.find_all(name="div", attrs={"class":"row"}):
    for a in div.find_all(name="a", attrs={"data-tn-element":"jobTitle"}):
      jobs.append(a["title"])
  return(jobs)
extract_job_title_from_result(soup)

이 코드는 다음과 같은 출력을 생성합니다,

회사 이름 가져오기

Getting company names can be a bit tricky because most of them are appearing in <span> tags, with “class”:” company”.  They are also housed in <span> tags with “class”:” result-link-source”.

각 위치에서 회사 정보를 추출하기 위해 if/else 문을 사용할 것입니다. 회사 이름이 출력될 때 회사 이름 주변의 공백을 제거하기 위해 마지막에 inputting.strip()을 사용하겠습니다.

def extract_company_from_result(soup): 
 companies = []
 for div in soup.find_all(name="div", attrs={"class":"row"}):
   company = div.find_all(name="span", attrs={"class":"company"})
   if len(company) &gt; 0:
    for b in company:
     companies.append(b.text.strip())
   else:
    sec_try = div.find_all(name="span", attrs={"class":"result-link-source"})
    for span in sec_try:
      companies.append(span.text.strip())
 return(companies)
 
extract_company_from_result(soup)

위치 가져오기

Locations are located under the <span> tags. Span tags are sometimes nested within each other, such that the location text may sometimes be within “class”:”location” attributes, or nested in “itemprop”:”addressLocality”. However a simple for loop can examine all span tags for text and retrieve the necessary information.

def extract_location_from_result(soup): 
  locations = []
  spans = soup.findAll('span', attrs={'class': 'location'})
  for span in spans:
    locations.append(span.text)
  return(locations)
extract_location_from_result(soup)

급여 받기

급여는 채용공고에서 추출하기 가장 어려운 부분입니다. 대부분의 채용공고는 연봉 정보를 전혀 게시하지 않는 반면, 게시하는 채용공고의 경우 여러 곳에서 연봉을 선택할 수 있습니다. 따라서 여러 곳에서 여러 급여를 가져올 수 있는 코드를 작성해야 하며, 급여를 찾을 수 없는 경우 급여가 포함되지 않은 모든 채용 공고에 대해 자리 표시자 '찾을 수 없음' 값을 만들어야 합니다. 

Some salaries are under <nobr> tags, while others are under <div> tags, “class”:”sjcl” and are under separate div tags with no attributes. Try/except statement can be helpful while extracting this information. 

def extract_salary_from_result(soup): 
  salaries = []
  for div in soup.find_all(name="div", attrs={"class":"row"}):
    try:
      salaries.append(div.find('nobr').text)
    except:
      try:
        div_two = div.find(name="div", attrs={"class":"sjcl"})
        div_three = div_two.find("div")
        salaries.append(div_three.text.strip())
      except:
        salaries.append("Nothing_found")
  return(salaries)
extract_salary_from_result(soup)

작업 요약 보기

마지막 작업은 채용 요약을 가져오는 것입니다. 그러나 각 특정 직책에 대한 직무 요약은 지정된 Indeed 페이지의 HTML에 포함되어 있지 않으므로 가져올 수 없습니다. 제공된 정보에서 각 직무에 대한 일부 정보를 얻을 수 있습니다. 이를 위해 셀레늄을 사용할 수 있습니다.

But let’s first try this using python. Summaries are located under <span> tags. Span tags are nested within each other such that the location text is within “class”:” location” tags or nested in “itemprop”:” adressLocality”. However, using a simple for loop can examine all span tags for text to retrieve the necessary information.

자주 묻는 질문

1. Why is it necessary to scrape job details?
내 프로필과 일치하는 채용 정보를 알려줄 수 있는 채용 포털은 충분히 많습니다. 하지만 작업 스크래핑 솔루션을 사용하면 전체 작업 목록과 설명을 편리한 데이터베이스로 얻을 수 있습니다. 이렇게 하면 한 곳에서 모든 채용 기회를 더 잘 볼 수 있습니다.
2. How can a proxy help in scraping job details?
웹 스크래핑에는 일반적으로 IP 차단, 지리적 차단, 속도 제한과 같은 특정 문제가 있습니다. 구직 포털에서 채용 정보를 스크래핑할 때도 이러한 문제가 발생합니다. 이러한 모든 문제를 우회하기 위해 프록시 주소를 사용하면 필요한 위치의 IP 주소를 사용하고 익명성을 보장할 수 있습니다.
3. What are the python libraries required to scrape job details?
Requests, BeautifulSoup, and Pandas are quite common python libraries to scrape job-related data from websites. Request library is the most common python library used to send web requests, while BeautifulSoup is responsible for parsing data, and Pandas library will help with the data structure operations.
관련 문서

마무리

이 글에서는 인디드의 웹 페이지에서 채용 데이터를 스크랩하는 실제 사례를 통해 웹 스크래핑이 무엇이며 일상 생활에서 어떻게 유용하게 활용될 수 있는지 살펴보았습니다. 페이지가 동적이기 때문에 시간이 지남에 따라 정보가 계속 변경되므로 실제 결과와 다를 수 있다는 점에 유의하세요. 

웹 스크래핑은 요구사항에 따라 올바르게 수행한다면 놀라운 기술입니다. 모든 채용 공고의 중요한 5가지 측면과 이를 추출하는 방법에 대해 자세히 살펴보았습니다. 이 코드를 직접 사용해 보면 채용공고 데이터를 스크랩할 수 있으며, 수동으로 채용공고를 검색할 필요가 없다는 점이 놀랍습니다. 다른 웹 페이지에도 동일한 기술을 적용할 수 있지만 구조가 다를 수 있습니다. 따라서 그에 따라 코드를 최적화해야 합니다. 하지만 이 글에서 모든 기본 사항을 다루었으므로 다른 페이지도 스크랩하는 데 어려움이 없을 것입니다.

프록시 서비스를 찾고 계신다면 다음 사항을 잊지 마세요. ProxyScrape 주거용프리미엄 프록시를 살펴보세요.