이 글에서 알아볼 내용:
- 인디드 스크레이퍼란 무엇이며 어떻게 작동하는지
- Indeed에서 자동 추출 가능한 데이터 유형
- 파이썬을 사용한 인디드 스크래핑 스크립트 구축 방법
- 더 고급 솔루션이 필요한 시점과 이유
시작해 보겠습니다!
인디드 스크레이퍼란 무엇인가요?
인디드 스크레이퍼는 인디드 웹사이트에서 구인 목록 및 관련 데이터를 자동으로 추출합니다. 이는 구직 검색 페이지를 탐색하는 인간의 상호작용을 모방하여 작동합니다. 이후 직무 제목, 회사명, 지역, 설명 등 특정 요소를 식별합니다. 마지막으로스크레이핑 봇이해당 데이터에서 정보를 추출하여 분석을 위해 내보냅니다.
인디드에서 찾을 수 있는 데이터
인디드는 시장 분석, 채용 또는 연구 목적에 매우 유용한 구직 관련 데이터의 보고입니다. 다음은 인디드에서 스크래핑할 수 있는 주요 데이터 포인트 목록입니다:
- 직무명: 공고에 게시된 역할 또는 직위.
- 회사명: 회사 프로필을 포함한 고용주 정보.
- 근무지: 채용 공고가 게시된 도시, 주 또는 국가.
- 직무 설명: 역할, 책임, 요구 사항에 대한 상세 정보.
- 급여 범위: 공고된 급여 수준(제공되는 경우).
- 근무 형태: 정규직, 파트타임, 계약직, 인턴십 등.
- 게시일: 채용 공고 게시일.
- 태그 및 속성: “긴급 채용” 또는 “원격 근무”와 같은 키워드.
- 평가 및 리뷰: 고용주 평점 및 직원 피드백.
- 지원 옵션: “간편 지원” 가능 여부와 같은 지표.
직무 포지션에 집중하고 있다면, 채용 공고 스크래핑 방법에 대한 가이드를 따르세요.
인디드 스크래핑 방법: 단계별 가이드
이 튜토리얼 섹션에서는 인디드 스크레이퍼를 만드는 방법을 확인하실 수 있습니다. 인디드의 “데이터 과학자” 채용 공고 페이지를 스크레이핑하는 파이썬 스크립트를 구축하는 과정을 안내해 드립니다:

지침을 따라 인디드 스크래핑 방법을 배워보세요!
1단계: 프로젝트 설정
시작하기 전에 컴퓨터에 Python 3이 설치되어 있는지 확인하세요. 설치되어 있지 않다면 다운로드하여 설치하세요.
이제 터미널에서 아래 명령어를 실행하여 프로젝트 디렉터리를 생성하세요:
mkdir indeed_scraper
indeed_scraper 디렉터리에 Python 인디드 스크레이퍼가 저장됩니다.
터미널에 입력하고, 해당 디렉터리 내에서 가상 환경을 초기화하세요:
cd indeed_scraper
python -m venv env
다음으로 선호하는 Python IDE에 프로젝트 폴더를 불러옵니다. Python 확장 기능이 설치된 Visual Studio Code나 PyCharm Community Edition이 모두 좋은 선택입니다.
프로젝트 디렉터리에 scraper.py 파일을 생성하세요. 이제 다음과 같은 파일 구조가 생성됩니다:

scraper.py에는 곧 원하는 스크래핑 로직이 포함될 것입니다.
이제 IDE 터미널에서 가상 환경을 활성화할 차례입니다. Linux 또는 macOS에서는 다음 명령어로 수행하세요:
./env/bin/activate
Windows에서는 다음과 같이 실행하세요:
env/Scripts/activate
훌륭합니다! 이제 Indeed 웹 스크래핑을 위한 Python 환경이 준비되었습니다.
2단계: 적합한 스크래핑 라이브러리 선택
다음 단계는 Indeed가 동적 페이지인지 정적 페이지인지 확인하는 것입니다. 이를 위해 브라우저의 시크릿 모드에서 Indeed 대상 페이지를 열고 탐색해 보세요. 쉽게 알 수 있듯이 페이지의 대부분의 데이터는 동적으로 로드됩니다:

이는 Indeed를 효과적으로 스크래핑하려면 Selenium과 같은 브라우저 자동화 도구가 필요하다는 것을 의미합니다. 이 과정에 대한 자세한 안내는 Selenium 웹 스크래핑 가이드를 참고하세요.
Selenium을 사용하면 웹 브라우저를 프로그래밍 방식으로 제어하여 사용자 상호작용을 시뮬레이션하고 JavaScript로 렌더링된 콘텐츠를 스크래핑할 수 있습니다. 이제 설치하고 시작해 보세요!
3단계: Selenium 설치 및 구성
활성화된 가상 환경에서 다음 명령어를 실행하여 Selenium을 설치하세요:
pip install -U selenium
scraper.py 에 Selenium을 임포트하고 WebDriver 객체를 설정합니다:
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
# 제어 가능한 Chrome 인스턴스 설정
driver = webdriver.Chrome(service=Service())
위 코드는 Chrome 인스턴스를 제어하는 데 필요한 요소를 초기화합니다.
참고: Indeed는 헤드리스 브라우저가 페이지에 접근하는 것을 차단하기 위해 안티 스크래핑 방어책을 구현했습니다. 따라서 --headless 플래그를 설정하면 스크립트가 실패할 수 있습니다. 대안으로 Playwright Stealth를 살펴보세요.
스크립트의 마지막 줄에서 웹 드라이버를 종료하는 것을 잊지 마세요:
driver.quit()
대단합니다! 이제 인디드 스크래핑을 위한 모든 설정이 완료되었습니다.
4단계: 대상 페이지 방문
Selenium의 get() 메서드를 사용하여 제어되는 브라우저가 대상 페이지를 방문하도록 지시하세요:
driver.get("https://www.indeed.com/jobs?q=data+scientist&l=New+York%2C+NY&from=searchOnHP%2Cwhatautocomplete&vjk=45d1ba700870fbef")
이제scraper.py 파일에는 다음 코드 줄이 포함됩니다:
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
# 제어 가능한 Chrome 인스턴스 설정
driver = webdriver.Chrome(service=Service())
# 브라우저에서 대상 페이지 열기
driver.get("https://www.indeed.com/jobs?q=data+scientist&l=New+York%2C+NY&from=searchOnHP%2Cwhatautocomplete&vjk=45d1ba700870fbef")
# logc 스크래핑...
# 웹 드라이버 종료
driver.quit()
마지막 줄에 디버깅 중단점을 추가하세요. 디버거와 함께 스크립트를 실행하면 아래와 같은 결과를 볼 수 있습니다:

참고: “Chrome이 자동화된 테스트 소프트웨어에 의해 제어되고 있습니다.” 알림은 Selenium이 예상대로 Chrome을 제어하고 있음을 알려줍니다.
잘하셨습니다!
5단계: 채용 공고 요소 선택
인디드(Indeed) 채용 검색 페이지에는 수많은 채용 공고가 표시됩니다. 모든 공고를 스크래핑할 계획이므로, 스크래핑된 데이터를 저장할 배열을 초기화하세요:
jobs = []
다음으로 페이지의 채용 공고 HTML 요소를 분석하여 선택 방법을 파악합니다:

여기서 각 채용 정보 요소는 #mosaic-provider-jobcards 컨테이너 내부의 slider_item 노드입니다.
일반적으로 페이지의 요소를 선택할 때는 CSS 클래스를 사용합니다. 그러나 이 클래스들은 빌드 시점에 무작위로 생성된 것으로 보입니다. 안정성을 보장하려면 자주 변경될 가능성이 적은 id 및 data-testid 속성을 대상으로 하는 것이 더 좋습니다.
Selenium을 활용하여 채용 공고 요소를 선택합니다:
jobs_container_element = driver.find_element(By.CSS_SELECTOR, "#mosaic-provider-jobcards")
job_elements = jobs_container_element.find_elements(By.CSS_SELECTOR, "[data-testid="slider_item"]")
find_elements() 메서드는 지정된 선택기 전략을 적용하여 페이지에서 일치하는 모든 요소를 검색합니다. 이 경우 선택기 전략은 CSS 선택기입니다.
이 기능이 작동하려면 By를 반드시 임포트하세요:
from selenium.webdriver.common.by import By
이제 선택된 요소들을 반복 처리하며 각 요소에서 데이터를 추출할 준비를 합니다:
for job_element in job_elements:
# 각 채용 공고에서 데이터 스크래핑
훌륭합니다! 이제 Indeed에서 채용 공고를 스크래핑할 준비가 되었습니다.
6단계: 채용 공고 주요 정보 스크래핑
카드 요소를 검사하여 카드 상단 섹션의 정보에 집중하세요:

여기서 스크랩할 수 있는 항목은 다음과 같습니다:
<h2>태그 내의 직무 제목- 직무 제목
<h2>내부의<a>태그에서 직무 페이지 URL [data-testid="company-name"]노드에서 회사명[data-testid="text-location"]요소에서 회사 위치
위의 정보를 스크래핑 로직으로 변환하면 다음과 같습니다:
title_element = job_element.find_element(By.CSS_SELECTOR, "h2.jobTitle")
title = title_element.text
url_element = title_element.find_element(By.CSS_SELECTOR, "a")
url = url_element.get_attribute("href")
company_element = job_element.find_element(By.CSS_SELECTOR, "[data-testid="company-name"]")
company = company_element.text
location_element = job_element.find_element(By.CSS_SELECTOR, "[data-testid="text-location"]")
location = location_element.text
find_element()는 주어진 선택자와 일치하는 첫 번째 요소를 선택합니다. 노드를 얻은 후에는 text 속성을 사용하여 해당 텍스트 콘텐츠에 접근할 수 있습니다. 노드의 HTML 속성 값을 얻으려면 get_attribute() 메서드를 사용해야 합니다.
좋아요! 인디드 스크래핑 로직의 기초를 마련하셨습니다. 하지만 아직 스크래핑할 유용한 데이터가 남아 있습니다.
7단계: 채용 공고 세부 정보 스크래핑
구직 포지션 카드의 세부 정보 섹션에 집중하세요:

이번에 스크래핑할 정보는 다음과 같습니다:
.jobMetaDataGroup<div>내부에 있는 하나 이상의[data-testid="attribute_snippet_testid"]요소들 속의 직무 위치 태그- 인디드(Indeed)를 통해 간편하게 지원할 수 있는 옵션이 있는지 여부
[role="presentation"]<div>내부의 하나 이상의ul li요소들 속 설명 항목들
태그 추출부터 시작해 보겠습니다. 다음 코드로 모두 추출할 수 있습니다:
tags = []
tags_container_element = job_element.find_element(By.CSS_SELECTOR, ".jobMetaDataGroup")
tag_elements = tags_container_element.find_elements(By.CSS_SELECTOR, "[data-testid="attribute_snippet_testid"]")
for tag_element in tag_elements:
tag = tag_element.text
tags.append(tag)
먼저, 검색된 모든 태그를 저장할 배열을 초기화해야 합니다. 이는 단일 채용 공고 카드에 여러 태그가 포함될 수 있기 때문입니다. 태그를 선택한 후, 이를 반복 처리하여 텍스트를 추출하고 배열에 태그를 추가합니다.
“간편 지원” 정보 스크래핑도 까다롭습니다. 문제는 해당 기능을 나타내는 HTML 요소가 모든 채용 공고에 존재하지 않는다는 점입니다. 분명히 “간편 지원” 옵션이 지원되는 곳에만 존재합니다.
페이지에 존재하지 않는 요소를 선택하려고 하면 Selenium은 NoSuchElementException을 발생시킵니다. 따라서 이를 활용하여 “간편 지원” 체크박스를 효과적으로 스크래핑할 수 있습니다:
try:
job_element.find_element(By.CSS_SELECTOR, "[data-testid="indeedApply"]")
easily_apply = True
except NoSuchElementException:
easily_apply = False
[data-testid="indeedApply"] 노드가 페이지에 존재하지 않으면 Selenium이 NoSuchElementException을 발생시킵니다. 이 예외는 인터셉트되어 easily_apply가 False로 설정됩니다.
설명 항목의 경우, 태그 처리와 동일한 방식으로 모두 스크래핑할 수 있습니다:
description = []
description_container_element = job_element.find_element(By.CSS_SELECTOR, "[role="presentation"]")
description_elements = description_container_element.find_elements(By.CSS_SELECTOR, "ul li")
for description_element in description_elements:
description_item_text = description_element.text
# 빈 설명 문자열은 무시
if (description_item_text != ""):
description.append(description_item_text)
와! 인디드 스크래퍼가 거의 완성됐네요.
단계 #8: 스크랩된 데이터 수집
각 직무 포지션에서 스크랩한 데이터로 직무 사전(dictionary)을 채웁니다:
job = {
"title": title,
"url": url,
"company": company,
"location": location,
"tags": tags,
"easily_apply": easily_apply,
"description": description
}
그런 다음 jobs 배열에 추가합니다:
jobs.append(job)
for 루프가 끝날 때쯤 products에는 다음과 같은 내용이 포함되어야 합니다:
[{'title': 'Data Scientist', 'url': 'https://www.indeed.com/rc/clk?jk=efc7b7f4a8be2882&bb=NM368jsOPyYGAfEtQk2NNae8tSeBHdJ8Y9tImVa1Q9GAipGe0zzddcUozFEL0Na_pYCR4W6ljgljsBxWTUrluVuL8Gom7x7UZlgMzs0spo3NRgisrZ7meuaPfaEcjWoe&xkcb=SoD767M34WNyEaSTwx0FbzkdCdPP&fccid=8678bc4e64c24580&vjs=3', 'company': 'GQR', 'location': 'New York, NY', 'tags': [], 'easily_apply': False, 'description': ['업계 동향과 신기술을 지속적으로 파악하여 경쟁 우위를 확보합니다.', '통계 및 머신러닝 기법을 적용하여 투자 성과를 개선합니다…']},
# 간결함을 위해 생략...
{'title': '데이터 사이언티스트, 금융 범죄 - USDS', 'url': 'https://www.indeed.com/rc/clk?jk=aaa16dfd1cc6ef01&bb=NM368jsOPyYGAfEtQk2NNdxizAZQnHpzRrlr6WgbV1RtxmXz4vto1qiiqGiIj9CJFQQCV6cW59nE4hGw1yeNdokPfu8Fgl3EALBx5zdWjPm4COEu78DCFh4KTUMIFWkh&xkcb=SoAT67M34WNyEaSTwx0pbzkdCdPP&fccid=caed318a9335aac0&vjs=3', 'company': 'TikTok', 'location': '뉴욕, NY 하이브리드 근무', 'tags': [], 'easily_apply': False, 'description': ['금융 범죄 데이터 과학자로서, 머신 러닝, 분석 및 시각화 기술을 활용하여 당사의...']}]
훌륭합니다! 이제 이 데이터를 더 나은 형식으로 변환하기만 하면 됩니다.
9단계: 스크랩한 데이터를 CSV로 내보내기
스크랩한 데이터를 접근 및 공유 가능하게 하려면 사람이 읽을 수 있는 형식으로 내보내는 것이 좋습니다. 예를 들어 CSV 파일로 작성하세요. 이를 위해 다음 코드 줄을 사용하세요:
csv_file = "scraped_jobs.csv"
csv_headers = ["title", "url", "company", "location", "tags", "easily_apply", "description"]
with open(csv_file, mode="w", newline="", encoding="utf-8") as file:
writer = csv.DictWriter(file, fieldnames=csv_headers)
writer.writeheader()
for job in jobs:
writer.writerow({
"title": job["title"],
"url": job["url"],
"company": job["company"],
"location": job["location"],
"tags": ";".join(job["tags"]),
"easily_apply": job["easily_apply"] == True: "Yes", False: "No",
"description": ";".join(job["description"])
})
open() 함수는 출력 CSV 파일을 생성하며, 이후 csv.DictWriter로 데이터를 채웁니다. 태그와 설명 필드는 배열이므로, join() 을 사용하여 요소를 ;로 구분한 단일 문자열로 평탄화합니다.
Python 표준 라이브러리에서 csv를 반드시 임포트하세요:
import csv
자, 이제 완성되었습니다! 인디드 스크레이퍼가 완성되었습니다.
10단계: 모든 것을 합치기
최종 scraper.py 파일은 다음과 같이 구성됩니다:
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.common import NoSuchElementException
import csv
# 제어 가능한 Chrome 인스턴스 설정
driver = webdriver.Chrome(service=Service())
# 브라우저에서 대상 페이지 열기
driver.get("https://www.indeed.com/jobs?q=data+scientist&l=New+York%2C+NY&from=searchOnDesktopSerp")
# 스크랩된 채용 공고를 저장할 데이터 구조
jobs = []
# 페이지에서 채용 공고 요소 선택
jobs_container_element = driver.find_element(By.CSS_SELECTOR, "#mosaic-provider-jobcards")
job_elements = jobs_container_element.find_elements(By.CSS_SELECTOR, "[data-testid="slider_item"]")
# 페이지의 각 채용 공고 스크랩
for job_element in job_elements:
title_element = job_element.find_element(By.CSS_SELECTOR, "h2.jobTitle")
title = title_element.text
url_element = title_element.find_element(By.CSS_SELECTOR, "a")
url = url_element.get_attribute("href")
company_element = job_element.find_element(By.CSS_SELECTOR, "[data-testid="company-name"]")
company = company_element.text
location_element = job_element.find_element(By.CSS_SELECTOR, "[data-testid="text-location"]")
location = location_element.text
tags = []
tags_container_element = job_element.find_element(By.CSS_SELECTOR, ".jobMetaDataGroup")
tag_elements = tags_container_element.find_elements(By.CSS_SELECTOR, "[data-testid="attribute_snippet_testid"]")
for tag_element in tag_elements:
tag = tag_element.text
tags.append(tag)
# 페이지에 "Easy Apply" 요소가 있는지 확인
try:
job_element.find_element(By.CSS_SELECTOR, "[data-testid="indeedApply"]")
easily_apply = True
except NoSuchElementException:
easily_apply = False
description = []
description_container_element = job_element.find_element(By.CSS_SELECTOR, "[role="presentation"]")
description_elements = description_container_element.find_elements(By.CSS_SELECTOR, "ul li")
for description_element in description_elements:
description_item_text = description_element.text
# 빈 설명 문자열은 무시
if (description_item_text != ""):
description.append(description_item_text)
# 스크랩한 데이터 저장
job = {
"title": title,
"url": url,
"company": company,
"location": location,
"tags": tags,
"easily_apply": easily_apply,
"description": description
}
jobs.append(job)
# 스크랩한 데이터를 출력 CSV 파일로 내보내기
csv_file = "jobs.csv"
csv_headers = ["title", "url", "company", "location", "tags", "easily_apply", "description"]
with open(csv_file, mode="w", newline="", encoding="utf-8") as file:
writer = csv.DictWriter(file, fieldnames=csv_headers)
writer.writeheader()
for job in jobs:
writer.writerow({
"title": job["title"],
"url": job["url"],
"company": job["company"],
"location": job["location"],
"tags": ";".join(job["tags"]),
"easily_apply": job["easily_apply"] == True: "Yes", else: "No",
"description": ";".join(job["description"])
})
# 웹 드라이버 종료
driver.quit()
100줄 미만의 코드로 Python으로 Indeed 스크레이퍼를 구축했습니다!
다음 명령어로 스크레이퍼를 실행하세요:
python3 script.py
또는 Windows에서는:
python script.py
프로젝트 폴더에 jobs.csv 파일이 생성됩니다. 파일을 열면 다음과 같은 내용을 확인할 수 있습니다:

자, 이제 완료되었습니다!
인디드 데이터 손쉽게 활용하기
인디드는 자사 데이터의 가치를 잘 알고 있으며 이를 보호하기 위해 강력한 조치를 취하고 있습니다. 따라서 셀레늄과 같은 브라우저 자동화 도구를 사용하여 인디드 페이지와 상호작용할 때 CAPTCHA를 마주칠 가능성이 높습니다:

첫 단계로, Python에서 CAPTCHA 우회 방법에 대한 가이드를 참고하세요. 다만 사이트가 추가적인 봇 방지 조치로 시도를 차단할 수 있다는 점을 유의하십시오. 봇 방지 기법에 관한 웨비나에서 모든 방법을 확인하세요.
이러한 문제들은 적절한 도구 없이 인디드 데이터를 스크래핑하는 것이 얼마나 좌절스럽고 비효율적인지 보여줍니다. 게다가 헤드리스 브라우저를 사용할 수 없으면 스크래핑 스크립트가 더 느려지고 리소스 소모가 커집니다.
해결책은? Bright Data의 인디드 스크레이퍼 API입니다. 이 도구를 사용하면 간단한 API 호출만으로 인디드에서 데이터를 원활하게 추출할 수 있습니다—캡차, 차단, 번거로움 없이!
결론
이 단계별 가이드에서는 인디드 스크레이퍼의 정의, 수집 가능한 데이터 유형, 파이썬으로 스크레이퍼를 구축하는 방법을 배웠습니다. 약 100줄의 코드로 인디드에서 자동으로 데이터를 수집하는 스크립트를 만들었습니다.
그러나 인디드 스크래핑에는 어려움이 따릅니다. 플랫폼은 CAPTCHA를 포함한 강력한 반봇(anti-bot) 조치를 시행합니다. 이를 우회하기 어렵고 스크래핑 속도를 늦춰 효율성을 떨어뜨릴 수 있습니다. 저희 인디드 스크레이퍼 API로 이러한 모든 어려움을 잊으세요.
웹 스크래핑은 부담스럽지만 채용 공고 데이터에는 관심이 있으신가요? 바로 사용 가능한 인디드 데이터셋을 확인해 보세요!
스크레이퍼 API를 사용해 보거나 데이터셋을 살펴보려면 지금 바로 Bright Data 무료 계정을 생성하세요.