파이썬으로 ZoomInfo 스크래핑하는 방법

Python으로 ZoomInfo 스크래핑을 마스터하거나 Bright Data의 Scraper API를 활용해 기업 및 직원 인사이트에 쉽게 접근하세요.
5 분 읽기
How to Scrape - ZoomInfo

이 가이드에서는 다음을 배우게 됩니다:

  • ZoomInfo 스크레이퍼란 무엇이며 어떻게 작동하는지
  • ZoomInfo에서 자동 추출 가능한 데이터 유형
  • Python을 사용한 ZoomInfo 스크래핑 스크립트 생성 방법
  • 더 고급 솔루션이 필요한 시점과 이유

자, 시작해 보겠습니다!

ZoomInfo 스크래퍼란 무엇인가요?

ZoomInfo 스크래퍼는 상세한 기업 및 전문가 정보를 제공하는 선도적인 플랫폼인 ZoomInfo에서 데이터를 추출하는 도구입니다. 이 솔루션은 스크래핑 프로세스를 자동화하여 대량의 데이터를 수집할 수 있게 합니다. 스크래퍼는 사이트를 탐색하고 콘텐츠를 검색하기 위해 브라우저 자동화 같은 기술을 활용합니다.

ZoomInfo에서 추출 가능한 데이터

ZoomInfo에서 스크래핑할 수 있는 주요 데이터는 다음과 같습니다:

  • 기업 정보: 이름, 업종, 매출, 본사 위치, 직원 수.
  • 직원 세부 정보: 이름, 직책, 이메일, 전화번호.
  • 산업 인사이트: 경쟁사, 시장 동향, 기업 계층 구조.

Python으로 ZoomInfo 스크래핑하기: 단계별 가이드

이 섹션에서는 ZoomInfo 스크래퍼를 구축하는 방법을 배웁니다.

목표는NVIDIA ZoomInfo 회사 페이지에서 자동으로 데이터를 수집하는 Python 스크립트를 만드는 과정을 안내하는 것입니다.

아래 단계를 따르세요!

1단계: 프로젝트 설정

시작하기 전에 컴퓨터에 Python 3이 설치되어 있는지 확인하세요. 설치되어 있지 않다면, 마법사를 따라 다운로드하고 설치하세요.

이제 다음 명령어를 사용하여 프로젝트 폴더를 생성하세요:

mkdir zoominfo-scraper

zoominfo-scraper 디렉터리는 Python ZoomInfo 스크레이퍼의 프로젝트 폴더를 나타냅니다.

이 디렉터리로 이동하여 가상 환경을 초기화하세요:

cd zoominfo-scraper
python -m venv env

선호하는 Python IDE에서 프로젝트 폴더를 로드하세요. Python 확장 프로그램이 설치된 Visual Studio Code나 PyCharm Community Edition을 사용하면 됩니다.

프로젝트 폴더 내에 scraper.py 파일을 생성하세요. 아래와 같은 파일 구조를 갖춰야 합니다:

A new scraper.py file in the ZoomInfo scraper folder

현재 scraper.py는 빈 Python 스크립트입니다. 곧 원하는 스크래핑 로직이 포함될 것입니다.

IDE 터미널에서 가상 환경을 활성화하세요. Linux 또는 macOS에서는 다음 명령어를 실행합니다:

./env/bin/activate

Windows에서는 다음과 같이 실행하세요:

env/Scripts/activate

훌륭합니다! 이제 웹 스크래핑을 위한 Python 환경이 준비되었습니다!

2단계: 스크래핑 라이브러리 선택

코딩에 착수하기 전에 목표 달성에 가장 적합한 도구가 무엇인지 이해해야 합니다. 이를 위해 먼저 대상 사이트를 분석하기 위한 예비 테스트를 수행해야 합니다. 방법은 다음과 같습니다:

  1. 브라우저의 시크릿 모드에서 대상 페이지를 엽니다. 이렇게 하면 미리 저장된 쿠키와 기본 설정이 분석에 영향을 미치지 않습니다.
  2. 페이지 아무 곳에서나 마우스 오른쪽 버튼을 클릭하고 “검사”를 선택하여 브라우저 개발자 도구를 엽니다.
  3. “네트워크” 탭으로 이동하세요.
  4. 페이지를 다시 로드하고 “Fetch/XHR” 탭에서 활동을 확인하세요.

이를 통해 웹페이지가 렌더링 시점에 어떻게 동작하는지 파악할 수 있습니다:

Information about the page rendering - the "network" tab under dev tools

이 섹션에서는 페이지가 수행한 모든 동적 AJAX 요청을 확인할 수 있습니다. 각 요청을 검사해 보면 관련 데이터가 포함된 요청이 하나도 없다는 것을 알 수 있습니다. 이는 페이지의 대부분의 정보가 서버에서 반환된 HTML 문서에 이미 내장되어 있음을 의미합니다.

결과적으로 ZoomInfo 스크래핑에는 HTTP 클라이언트와 HTML 파서를 채택하게 될 것입니다. 그러나 해당 사이트는 브라우저에서 발생하지 않은 대부분의 자동화된 요청을 차단하는 강력한 안티봇 기술을 사용합니다. 이를 우회하는 가장 간단한 방법은 Selenium과 같은 브라우저 자동화 도구를 사용하는 것입니다!

Selenium을 사용하면 웹 브라우저를 프로그래밍 방식으로 제어하여 실제 사용자가 수행하는 것처럼 웹 페이지에서 특정 작업을 지시할 수 있습니다. 이제 설치하고 시작해 보세요!

3단계: Selenium 설치 및 구성

파이썬에서는 Selenium을 selenium pip 패키지를 통해 사용할 수 있습니다. 활성화된 파이썬 가상 환경에서 다음 명령어로 설치하세요:

pip install -U selenium

도구 사용법에 대한 안내는 Selenium을 활용한 웹 스크래핑 튜토리얼을 참고하세요.

scraper.py에서 Selenium을 임포트하고 Chrome 인스턴스를 제어할 WebDriver 객체를 초기화하세요:

from selenium import webdriver
from selenium.webdriver.chrome.service import Service

# Chrome 웹 드라이버 인스턴스 생성
driver = webdriver.Chrome(service=Service())

위 코드는 Chrome에서 작동할 WebDriver 인스턴스를 생성합니다. ZoomInfo는 헤드리스 브라우저를 차단하는 안티 스크래핑 기술을 사용하므로 --headless 플래그를 설정할 수 없습니다. 대안으로 Playwright Stealth를 고려해 보세요.

스크레이퍼의 마지막 줄에서 웹 드라이버를 반드시 종료하세요:

driver.quit()

훌륭합니다! 이제 ZoomInfo 스크래핑을 시작할 모든 준비가 완료되었습니다.

4단계: 대상 페이지 연결

Selenium WebDriver 객체의 get() 메서드를 사용하여 브라우저가 원하는 페이지를 방문하도록 지시하세요:

driver.get("https://www.zoominfo.com/c/nvidia-corp/136118787")

이제 scraper.py 파일에 다음 코드 줄이 포함되어야 합니다:

from selenium import webdriver
from selenium.webdriver.chrome.service import Service

# Chrome 웹 드라이버 인스턴스 생성
driver = webdriver.Chrome(service=Service())

# 대상 페이지 연결
driver.get("https://www.zoominfo.com/c/nvidia-corp/136118787")

# 스크래핑 로직...

# 브라우저 닫기
driver.quit()

마지막 줄에 디버깅 중단점을 설정하고 스크립트를 실행하세요. NVIDIA 회사 페이지로 이동해야 합니다.

“Chrome is being controlled by automated test software.” 메시지는 Selenium이 예상대로 Chrome을 제어하고 있음을 확인해 줍니다. 잘하셨습니다!

5단계: 일반 회사 정보 스크래핑

필요한 데이터를 스크래핑하는 방법을 이해하려면 페이지의 DOM 구조를 분석해야 합니다. 목표는 원하는 데이터를 포함하는 HTML 요소를 식별하는 것입니다. 회사 정보 섹션 상단 부분의 요소를 검사하는 것으로 시작하세요:

Inspecting the HTML of the top section elements (company info section)

<app-company-header> 요소는 다음을 포함합니다:

  • 회사 이미지는 class가 company-logo-wrapper인 <div> 내부의 <img> 태그에 있습니다.
  • 회사명은 class company-name을 가진 노드 내에 있습니다.
  • 회사 부제목은 class company-header-subtitle을 가진 노드에 저장됩니다.

Selenium을 사용하여 이러한 요소를 찾아 데이터를 수집하세요:

logo_element = driver.find_element(By.CSS_SELECTOR, ".company-logo-wrapper img")
logo_url = logo_element.get_attribute("src")

name_element = driver.find_element(By.CSS_SELECTOR, ".company-name")
name = name_element.text

subtitle_element = driver.find_element(By.CSS_SELECTOR, ".company-header-subtitle")
subtitle = subtitle_element.text

코드가 작동하도록 하려면 By를 반드시 임포트하세요:

from selenium.webdriver.common.by import By

find_element() 메서드는 지정된 노드 선택 전략을 사용하여 노드를 선택합니다. 위에서는 CSS 선택자를 사용했습니다. XPath와 CSS 선택자의 차이점에 대해 자세히 알아보세요.

그런 다음 text 속성을 통해 노드의 콘텐츠에 접근할 수 있습니다. 속성에 접근하려면 get_attribute() 메서드를 사용하세요.

스크랩된 데이터를 출력합니다:

print(logo_url)
print(name)
print(subtitle)

다음과 같은 결과가 출력됩니다:

https://res.cloudinary.com/zoominfo-com/image/upload/w_120,h_120,c_fit/nvidia.com
NVIDIA
컴퓨터 장비 및 주변기기 · 캘리포니아, 미국 · 29,600명 직원

와! ZoomInfo 스크래퍼가 정말 잘 작동하네요.

6단계: 회사 정보 스크래핑

회사 페이지의 “About” 섹션에 집중하세요:

The "about" section on the company page

<app-about> 노드에는 일반적인 클래스와 무작위로 생성된 듯한 속성을 가진 요소들이 포함되어 있습니다. 이러한 속성은 빌드마다 변경될 수 있으므로, 스크래핑 대상 요소를 지정할 때 이를 의존하지 않는 것이 좋습니다.

이 섹션의 정보를 스크래핑하려면 먼저 <app-about> 노드를 선택하세요:

about_element = driver.find_element(By.CSS_SELECTOR, "app-about")

이제 <app-about> 내부의 모든 .icon-text-container 요소에 집중하세요. 그런 다음 해당 레이블(.icon-label)을 검사하여 관심 있는 특정 요소를 식별합니다. 레이블이 일치하면 .content 요소에서 데이터를 추출하세요. 이 로직을 함수로 캡슐화합니다:

def scrape_about_node(text_container_elements, text_label):
  # 관심 있는 특정 노드에서 데이터를 추출하기 위해 반복 처리
  for text_container_element in text_container_elements:
      label = text_container_element.find_element(By.CSS_SELECTOR, ".icon-label").text.strip()
      if label == text_label:
          # 콘텐츠 요소를 선택하고 데이터를 추출
          content_element = text_container_element.find_element(By.CSS_SELECTOR, ".content")
          return content_element.text

  return None

그런 다음 “About” 정보를 다음과 같이 스크래핑할 수 있습니다:

headquarters = scrape_about_node(text_container_elements, "Headquarters")
phone_number = scrape_about_node(text_container_elements, "Phone Number")
revenue = scrape_about_node(text_container_elements, "Revenue")
stock_symbol = scrape_about_node(text_container_elements, "Stock Symbol")

다음으로, 업종 및 회사 태그를 대상으로 합니다.

h3 .incon-label로 회사 업종을, zi-directories-chips a로 태그를 선택합니다. 다음 코드로 데이터를 추출합니다:

industry_element = about_element.find_element(By.CSS_SELECTOR, "h3.icon-label")
industry = industry_element.text

tag_elements = about_element.find_elements(By.CSS_SELECTOR, "zi-directories-chips a")
tags = [tag_element.text for tag_element in tag_elements]

대단합니다! ZoomInfo 데이터 스크래핑 로직이 완성되었습니다.

7단계: 스크래핑된 데이터 수집

현재 수집된 데이터가 여러 변수에 분산되어 있습니다. 해당 데이터로 새로운 회사 객체를 생성하세요:

company = {
    "logo_url": logo_url,
    "name": name,
    "subtitle": subtitle,
    "headquarters": headquarters,
    "phone_number": phone_number,
    "revenue": revenue,
    "stock_symbol": stock_symbol,
    "industry": industry,
    "tags": tags
}

스크랩한 데이터를 출력하여 원하는 정보가 포함되었는지 확인하세요

print(items)

다음과 같은 출력이 생성됩니다:

{'logo_url': 'https://res.cloudinary.com/zoominfo-com/image/upload/w_120,h_120,c_fit/nvidia.com', 'name': 'NVIDIA', 'subtitle': '컴퓨터 장비 및 주변기기 · 미국 캘리포니아 · 직원 29,600명', 'headquarters': '2788 San Tomas Expy, Santa Clara, California, 95051, United States', 'phone_number': '(408) 486-2000', 'revenue': '$798억 달러', 'stock_symbol': 'NVDA', 'industry': '본사', 'tags': ['컴퓨터 네트워킹 장비', '네트워크 보안 하드웨어 및 소프트웨어', '컴퓨터 장비 및 주변기기', '제조업']}

훌륭합니다! 이제 이 정보를 JSON과 같은 사람이 읽을 수 있는 파일로 내보내기만 하면 됩니다.

단계 #8: JSON으로 내보내기

다음과 같이 회사를 company.json 파일로 내보냅니다:

with open("company.json", "w") as json_file:
  json.dump(company, json_file, indent=4)

먼저 open()company.json 출력 파일을 생성합니다. 그런 다음 json.dump()company를 JSON 표현으로 변환하여 출력 파일에 기록합니다.

Python 표준 라이브러리에서 json을 임포트하는 것을 잊지 마세요:

import json

9단계: 모든 것을 통합하기

아래는 최종 scraper.py 파일입니다:

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
import json

def scrape_about_node(text_container_elements, text_label):
    # 특정 관심 노드에서 데이터를 스크래핑하기 위해 반복 처리
    for text_container_element in text_container_elements:
        label = text_container_element.find_element(By.CSS_SELECTOR, ".icon-label").text.strip()
        if label == text_label:
            # 콘텐츠 요소를 선택하고 데이터를 추출
            content_element = text_container_element.find_element(By.CSS_SELECTOR, ".content")
            return content_element.text

    return None

# Chrome 웹 드라이버 인스턴스 생성
driver = webdriver.Chrome(service=Service())

# 대상 페이지에 연결
driver.get("https://www.zoominfo.com/c/nvidia-corp/136118787")

# 회사 정보 스크래핑
logo_element = driver.find_element(By.CSS_SELECTOR, ".company-logo-wrapper img")
logo_url = logo_element.get_attribute("src")

name_element = driver.find_element(By.CSS_SELECTOR, ".company-name")
name = name_element.text

subtitle_element = driver.find_element(By.CSS_SELECTOR, ".company-header-subtitle")
subtitle = subtitle_element.text

# "About" 섹션에서 데이터 추출
about_element = driver.find_element(By.CSS_SELECTOR, "app-about")

text_container_elements = about_element.find_elements(By.CSS_SELECTOR, ".icon-text-container")

headquarters = scrape_about_node(text_container_elements, "Headquarters")
phone_number = scrape_about_node(text_container_elements, "Phone Number")
revenue = scrape_about_node(text_container_elements, "Revenue")
stock_symbol = scrape_about_node(text_container_elements, "Stock Symbol")

# 회사 업종 및 태그 스크래핑
industry_element = about_element.find_element(By.CSS_SELECTOR, "h3.icon-label")
industry = industry_element.text

tag_elements = about_element.find_elements(By.CSS_SELECTOR, "zi-directories-chips a")
tags = [tag_element.text for tag_element in tag_elements]

# 수집된 데이터 모음
company = {
    "logo_url": logo_url,
    "name": name,
    "subtitle": subtitle,
    "headquarters": headquarters,
    "phone_number": phone_number,
    "revenue": revenue,
    "stock_symbol": stock_symbol,
    "industry": industry,
    "tags": tags
}

# 수집한 데이터를 JSON으로 내보내기
with open("company.json", "w") as json_file:
  json.dump(company, json_file, indent=4)
  
# 브라우저 종료
driver.quit()

70줄이 조금 넘는 코드로 Python으로 ZoomInfo 데이터 스크래핑 스크립트를 완성했습니다!

다음 명령어로 스크레이퍼를 실행하세요:

python3 script.py

또는 Windows에서는:

python script.py

프로젝트 폴더에 company.json 파일이 생성됩니다. 파일을 열면 다음과 같은 내용을 확인할 수 있습니다:

{
    "logo_url": "https://res.cloudinary.com/zoominfo-com/image/upload/w_120,h_120,c_fit/nvidia.com",
    "name": "NVIDIA",
    "subtitle": "컴퓨터 장비 및 주변기기 · 미국 캘리포니아 · 직원 29,600명",
    "headquarters": "2788 San Tomas Expy, Santa Clara, California, 95051, United States",
    "phone_number": "(408) 486-2000",
    "revenue": "$79.8 Billion",
    "주식_기호": "NVDA",
    "산업": "본사",
    "태그": [
        "컴퓨터 네트워킹 장비",
        "네트워크 보안 하드웨어 및 소프트웨어",
        "컴퓨터 장비 및 주변기기",
        "제조업"
    ]
}

축하합니다, 미션 완료!

ZoomInfo 데이터 손쉽게 활용하기

ZoomInfo는 단순한 기업 개요를 넘어 풍부한 유용한 정보를 제공합니다. 문제는 ZoomInfo 도메인 내 대부분의 페이지가 봇 방지 조치로 보호되어 해당 데이터를 스크래핑하는 것이 상당히 어렵다는 점입니다.

Selenium이나 기타 브라우저 자동화 도구를 사용해 이러한 페이지에 접근하면, 시도 자체를 차단하는 CAPTCHA 페이지에 부딪힐 가능성이 높습니다.

첫 단계로, Python에서 CAPTCHA 우회 방법에 대한 저희 가이드를 따르는 것을 고려해 보세요. 그러나 사이트의 엄격한 속도 제한으로 인해 여전히 429 Too Many Requests 오류가 발생할 수 있습니다. 이러한 경우 Selenium에 프록시를 통합하여 출구 IP를 회전시킬 수 있습니다.

이러한 문제들은 적절한 도구 없이 ZoomInfo를 스크래핑하는 과정이 얼마나 좌절감을 주는지 잘 보여줍니다. 또한 헤드리스 브라우저를 사용할 수 없다는 점은 스크래핑 스크립트를 느리게 만들고 많은 자원을 소모하게 합니다.

해결책은? Bright Data의 전용 ZoomInfo 스크레이퍼 API를 사용해 차단당하지 않고 간단한 API 호출만으로 대상 사이트에서 데이터를 가져오는 것입니다!

결론

이 단계별 튜토리얼에서 ZoomInfo 스크레이퍼의 정의와 수집 가능한 데이터 유형을 학습했습니다. 또한 100줄 미만의 코드로 ZoomInfo의 기업 개요 데이터를 스크레이핑하는 Python 스크립트를 구축했습니다.

문제는 ZoomInfo가 CAPTCHA, 브라우저 지문 인식, IP 차단 등 자동화된 스크립트를 차단하기 위한 엄격한 반봇(anti-bot) 조치를 시행한다는 점입니다. 저희 ZoomInfo 스크레이퍼 API를 사용하면 이러한 모든 문제를 잊어버리셔도 됩니다.

웹 스크래핑은 부담스럽지만 기업 또는 직원 데이터에 관심이 있으시다면, 저희 ZoomInfo 데이터셋을 살펴보세요!

스크레이퍼 API를 사용해 보거나 데이터셋을 살펴보려면 지금 바로 Bright Data 무료 계정을 생성하세요.