SeleniumBase를 사용한 하나의 범용 스크립트로 ZoomInfo 스크래핑

발행: (2025년 12월 10일 오후 11:47 GMT+9)
6 min read
원문: Dev.to

Source: Dev.to

시작하기 전에

ZoomInfo는 간단하고 안정적인 방법으로 스크래핑할 수 있습니다. 사이트는 핵심 데이터를 application/json 블록 안에 저장하므로 복잡한 CSS 선택자를 사용하지 않고도 검색 결과, 프로필 및 회사 상세 정보를 추출할 수 있습니다.

사전 요구 사항 및 설정

ZoomInfo는 자동화된 행동을 의심하면 누르고 있기 캡차를 표시합니다. 단순 요청 라이브러리나 헤드리스 Selenium/Playwright는 작동하지 않습니다. 지문, 헤더를 패치하고 헤드리스 모드를 숨기는 도구가 필요합니다. 예: SeleniumBase, Playwright Stealth, Patchright.

우리는 UC 모드의 SeleniumBase(Undetectable Browser 기반)를 사용할 것입니다. 다음 명령으로 설치합니다:

pip install seleniumbase

사용 가능한 데이터 포인트

페이지 유형주요 데이터 포인트비고
검색 페이지이름, 직함, 프로필 링크, 회사 링크처음 5페이지만. 이메일/전화/이미지는 보통 누락됨. 일부 필드는 비어 있거나 null일 수 있음.
인물 프로필전체 이름, 직함, 사진, 소개, 마스킹된 이메일/전화, 근무 주소, 소셜 링크, 학력·경력, 고용주 정보, 동료, 유사 프로필, 웹 언급, AI 신호대부분의 데이터가 완전함. 연락처 정보는 부분적으로 숨겨짐.
회사 페이지법인명, 규모, 직원 수, 기술 스택, 재무 정보, 경쟁사, 임원진, 주소, 소셜 링크, 뉴스, 인수·합병, 조직도, 이메일 패턴, 채용 트렌드, 인텐트 신호, 수상 내역, 비교 대상일부 연락처 정보, 과거 재무 데이터, 이메일 샘플, 인텐트 데이터는 부분적으로 누락되거나 마스킹될 수 있음.

범용 스크래핑 스크립트

이 스크립트는 검색 페이지, 인물 프로필, 회사 페이지 모두에서 동작합니다. <script> 태그 안의 JSON 데이터를 추출하고, 불필요한 키를 제거한 뒤 파일에 저장합니다.

from seleniumbase import SB
from selenium.webdriver.common.by import By
import time, json

# 페이지 기본 URL (검색, 인물, 또는 회사)
base_url = "https://www.zoominfo.com/people-search/"  # 또는 person/company URL
pages = 5  # 검색 페이지용; 단일 프로필/회사는 1로 설정
all_data = []

with SB(uc=True, test=True) as sb:
    for page in range(1, pages + 1):
        url = f"{base_url}?pageNum={page}" if pages > 1 else base_url
        sb.uc_open_with_reconnect(url, 4)
        time.sleep(1)  # JSON 스크립트가 렌더링될 때까지 대기
        try:
            scripts = sb.find_elements('script[type="application/json"]', by=By.CSS_SELECTOR)
            for el in scripts:
                content = el.get_attribute("innerHTML")
                data = json.loads(content)
                data.pop("__nghData__", None)
                data.pop("cta_config", None)
                all_data.append(data)
        except Exception as e:
            print(f"Page {page} error:", e)

# 데이터 저장
with open("zoominfo_data.json", "w", encoding="utf-8") as f:
    json.dump(all_data, f, ensure_ascii=False, indent=2)

생성된 JSON에는 거의 모든 사용 가능한 데이터가 포함됩니다:

  • 검색 페이지: 이름, 직함, 프로필 링크, 회사 링크. 이메일, 전화, 이미지 등은 대부분 숨겨짐.
  • 인물 페이지: 전체 개인 정보, 마스킹된 연락처, 학력·경력, 동료, AI 신호 등.
  • 회사 페이지: 법인명, 직원 수, 기술 스택, 재무 정보, 임원, 뉴스, 인수·합병, 채용 트렌드, 수상 내역 등. 일부 필드는 부분적으로 마스킹됨.

안티‑스크래핑 방어책

ZoomInfo는 강력한 안티‑봇 보호를 적용합니다. 데이터를 파싱하기 전에 HTTP 상태 코드를 확인하고 상황에 맞게 처리하세요.

상태 코드의미복구 방법
200성공계속 진행
429속도 제한30‑60초 대기 후 재시도
403금지 (IP 차단)IP/프록시 교체 후 다음 날 재시도
503서비스 이용 불가5분 후 재시도
200 (empty)허니팟IP 교체
Redirect /error스크래퍼 감지지연 추가, 프록시 회전

봇 마스킹, 프록시 회전, 일시 정지 삽입, 오류 시 장시간 대기 등을 통해 오류, 캡차, 차단을 완화할 수 있습니다.

참고

전체 단계별 설명, 시각 자료 및 팁이 포함된 자세한 가이드는 블로그의 전체 글을 확인하세요: Read the Full Article

모든 예제는 GitHub 저장소에서도 확인할 수 있습니다.

Back to Blog

관련 글

더 보기 »