API를 통해 캐나다 건설업자 면허 데이터를 가져오는 방법 (2026)
요약
퀘벡의 방대한 건설업자 면허 오픈 데이터를 효율적으로 처리하는 방법을 소개합니다. 대규모 CSV 파일을 직접 정규화하는 대신, Apify의 호스팅 스크래퍼를 사용하여 API를 통해 구조화된 데이터를 가져오는 가이드를 제공합니다.
핵심 포인트
- 92만 행의 복잡한 오픈 데이터를 정규화하는 기술적 난제 해결
- Apify Actor를 활용한 데이터 스크래핑 및 API 호출 방법
- Python을 이용한 데이터 수집 및 MCP 에이전트 연동 가능성
- 데이터 정규화, 디코딩, 그룹화 과정을 자동화하는 워크플로우
Quebec(퀘벡)은 활성 건설업자(construction contractors)의 전체 등록부를 오픈 데이터 (open data)로 공개합니다. 지붕 수리공, 전기 기술자, 일반 건축업자, 굴착업자 등 주 내의 모든 면허 보유 건설업자가 하나의 파일에 담겨 있으며, 매일 업데이트되고 Creative Commons 라이선스에 따라 무료로 사용할 수 있습니다.
다운로드하기 전까지는 아주 좋게 들립니다. 약 10.8 MB 크기의 zip 파일입니다. 그 안에는 **924,000개의 행 (rows)**과 프랑스어로 된 열 헤더 (column headers)가 포함된 CSV 파일이 들어 있습니다. 한 명의 건설업자가 여러 행에 걸쳐 나타나기 때문에 (면허 카테고리당 한 행), 원본 파일은 건설업자 목록이 아니라 사용자가 직접 그룹화해야 하는 건설업자-카테고리 쌍의 목록입니다. 만약 단순히 "전화번호와 이메일이 포함된 퀘벡의 지붕 수리업자"와 같이 쿼리가 가능한 깔끔한 목록을 원한다면, 오픈 데이터는 기술적으로는 이용 가능하지만 실질적으로는 매우 고통스럽습니다.
이 포스트에서는 이러한 고통을 건너뛰고, 본인의 코드나 MCP를 통한 AI 에이전트로부터 직접 API를 통해 해당 데이터를 가져오는 방법을 보여줍니다. 우리는 원본 RBQ 덤프를 구조화되고 중복이 제거된 레코드 (records)로 변환하는 Apify의 작은 호스팅 스크래퍼 (hosted scraper)를 사용할 것입니다.
데이터 소스: RBQ의 활성 면허 목록
데이터는 건설업자에게 면허를 부여하는 주 정부 기관인 **Régie du bâtiment du Québec (RBQ)**에서 제공합니다. 이들의 "Liste des licences actives" 데이터셋은 Données Québec 오픈 데이터 포털에 있으며, 매일 갱신되고 CC-BY 4.0 (출처 표기 시 무료 사용 가능) 조건으로 게시됩니다. 이는 민간 포털을 스크래핑한 것이 아니라 공식 정부 오픈 데이터입니다.
직접 구현(DIY)하는 경로를 원하신다면, 몇 줄의 Python 코드로 가능합니다:
import io, zipfile, requests, pandas as pd
# Données Québec 데이터셋 페이지의 리소스 URL
...
그 후에도 여전히 다음 작업들을 수행해야 합니다: 프랑스어/액센트가 포함된 열 이름 정규화, 면허-카테고리 코드 디코딩, 약 924,000개의 행을 약 54,000개의 고유 건설업자로 그룹화, 그리고 최신 상태를 유지하기 위해 매일 전체 과정을 다시 실행하기. 가능은 하지만, 이는 한 줄로 끝나는 작업이 아니라 유지보수가 필요한 작업입니다.
API 경로
대신, 다운로드, 정규화 (normalization), 카테고리 디코딩 (category decoding) 및 그룹화 (grouping)를 수행하고 면허당 하나의 깔끔한 레코드를 반환하는 호스팅된 Actor인 truenorthdata/canada-contractor-licenses를 호출합니다. 일반적인 REST API처럼 호출하면 됩니다.
가장 편리한 엔드포인트는 Apify의 **run-sync-get-dataset-items**입니다. 이 엔드포인트는 Actor를 시작하고, 완료될 때까지 기다린 후, 하나의 HTTP 응답으로 데이터셋 항목을 반환합니다. (동기식 실행 (Synchronous runs)은 300초로 제한되어 있으므로, 결과 집합을 필터링된 상태로 유지하세요.)
Python
import requests
APIFY_TOKEN = "YOUR_APIFY_TOKEN"
...
Actor ID의 물결표(~)에 주의하세요 (truenorthdata~canada-contractor-licenses) — API는 사용자 이름과 Actor 이름을 구분하기 위해 / 대신 ~를 사용합니다.
curl
셸(shell)에서 동일하게 호출합니다:
curl -X POST \
"https://api.apify.com/v2/acts/truenorthdata~canada-contractor-licenses/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
-H "Content-Type: application/json" \
...
계약자 레코드가 담긴 JSON 배열을 받게 됩니다. zip 처리, latin-1 디코딩, 그룹화 작업이 필요 없습니다 — Actor가 이미 모두 수행했기 때문입니다.
MCP 경로: AI 에이전트에서 직접 호출하기
LLM (Large Language Models)을 사용하여 구축하고 있다면, REST 호출조차 필요하지 않습니다. Apify는 **Model Context Protocol (MCP)**를 통해 Actor를 노출하므로, AI 에이전트가 이 스크래퍼를 도구 (tool)로 호출하고 동일한 턴 내에서 결과에 대해 추론할 수 있습니다.
MCP 클라이언트를 다음으로 지정하세요:
다음과 같은 형태의 Claude Desktop / Claude Code 스타일 설정에서:
{
"mcpServers": {
"contractor-licenses": {
...
연결이 완료되면, 에이전트에게 평이한 언어로 _"이메일과 전화번호를 모두 보유한 퀘벡의 활성 지붕 공사 계약자를 찾아줘"_라고 요청할 수 있습니다. 그러면 에이전트가 Actor를 호출하고, 구조화된 레코드를 가져와서, 여러분을 위해 필터링해 줄 것입니다. 이것이 API 우선 (API-first) 접근 방식의 진정한 이점입니다. 동일한 데이터 소스가 중간의 글루 코드 (glue code) 없이도 야간 Python 작업과 대화형 에이전트 모두에서 작동합니다.
한 명의 건설업자 검증하기
또 다른 흔한 작업은 리드 생성 (lead-gen)이 아니라 검증 (verification) 입니다. 누군가 RBQ 번호를 건네주었을 때, 해당 번호가 활성 상태인지 확인하고 어떤 범위를 커버하는지 알고 싶은 경우입니다. 동일한 엔드포인트(endpoint)를 사용하며, 번호로 검색하기만 하면 됩니다:
payload = {"keywords": ["5678-1234-01"], "maxResults": 1}
resp = requests.post(url, params={"token": APIFY_TOKEN}, json=payload, timeout=60)
match = resp.json()
...
기저 데이터셋(underlying dataset)에는 활성 (active) 라이선스만 나열되어 있기 때문에, 결과가 비어 있다는 것 자체가 하나의 신호입니다. 즉, 아무것도 반환하지 않는 번호는 현재 유효한 활성 라이선스가 아닙니다.
레코드의 형태
각 항목은 하나의 활성 라이선스이며, RBQ의 필드들이 깔끔한 키 (key)로 매핑되어 있습니다 (25개의 소스 필드 중 24개가 그대로 유지됩니다). 리드 생성 및 검증에 유용한 필드들은 다음과 같습니다:
- licenceNumber — RBQ 라이선스 번호 (건설업자가 인용하는 기본 키 (primary key))
- companyName — 법인명 / 운영명
- categories — 디코딩된 라이선스 카테고리 (실제로 건설이 허용된 범위)
- email 및 phone — RBQ가 공개한 연락처 정보
- address, city, postal code — 주소, 도시, 우편번호
- bondClaims — 해당 건설업자를 대상으로 한 보증 청구 (bond claims) 횟수 (대략적인 리스크 신호)
- restrictions — 라이선스에 부과된 제한 사항
레코드는 이미 라이선스 번호별로 그룹화되어 있으므로, 한 명의 건설업자는 수십 개의 행에 흩어져 있는 것이 아니라 모든 카테고리가 배열 (array)에 담긴 하나의 레코드로 나타납니다.
비용
이 Actor는 이벤트당 결제 (pay-per-event) 방식으로 수익을 창출합니다. 소액의 시작 비용(실행당 약 $0.005)에 더해, 반환된 건설업자 라이선스 레코드 1,000개당 $6가 부과됩니다. 가져온 만큼만 지불하면 되며, 필터링된 쿼리(예: 특정 지역의 지붕 수리업자)는 단 몇 센트의 비용이 듭니다. 구독료도 없고 실행을 위한 인프라도 필요하지 않습니다. Actor와 일일 데이터 갱신은 Apify에서 운영됩니다.
RBQ 소스가 매일 갱신되므로, Actor가 바라보는 데이터도 마찬가지로 매일 갱신됩니다. 자체 데이터베이스를 유지 관리하고 있다면, 가장 저렴한 패턴은 정해진 일정(매일 밤, 매주)에 따라 필터링된 쿼리를 실행하고 licenceNumber를 기준으로 upsert(업서트)하는 것입니다. 이렇게 하면 매번 전체 레지스트리를 다시 가져올 필요 없이 신규 및 업데이트된 건설업자 데이터를 얻을 수 있습니다.
어떤 경로를 사용할 것인가
- REST API (
run-sync-get-dataset-items) — 스크립트, cron 작업(cron jobs), 파이프라인(pipelines)에 가장 적합합니다. 300초의 동기화(sync) 시간 내에 실행이 완료되도록keywords/maxResults로 필터링하세요. 매우 방대한 양을 가져와야 한다면, 비동기(async) 실행을 시작한 후 나중에 데이터셋(dataset)을 읽으십시오. - MCP — 별도의 래퍼 코드(wrapper code) 없이 AI 에이전트가 직접 데이터를 가져오고 추론해야 할 때 가장 적합합니다.
- Raw open data (가공되지 않은 오픈 데이터) — 924,000개의 행 전체가 진정으로 필요하며, 데이터 정규화(normalization)와 일일 갱신을 직접 관리하는 것에 동의한다면 가장 적합합니다. 소스는 무료이며 CC-BY 라이선스입니다. Actor는 단지 데이터 파이프라인 구축(plumbing)의 수고를 덜어줄 뿐입니다.
직접 시도해보기
이 스크레이퍼(scraper)는 Apify Store에 canada-contractor-licenses (truenorthdata/canada-contractor-licenses)로 출시되어 있습니다. Apify 토큰을 가져와 위에서 제공한 Python 스니펫(snippet)을 넣기만 하면, 단 한 번의 호출로 깨끗한 퀘벡(Quebec) 건설업자 데이터를 얻을 수 있습니다.
로드맵의 다음 단계: 온타리오(Ontario)의 HCRA 건설업자 디렉토리를 추가하여, 동일한 Actor가 두 개 주(province)의 면허를 가진 건설업자를 모두 커버할 수 있도록 할 예정입니다. 이것이 유용할 것 같다면 댓글로 알려주세요.
데이터 소스: Régie du bâtiment du Québec — Liste des licences actives, Données Québec 제공, CC-BY 4.0 라이선스.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기