How to Build a Bulk Sales Lead Extractor in Python Using AI
Quick Summary
Streamlit·Firecrawl·Pydantic으로 사용자 지정 항목을 여러 웹사이트에서 추출하는 Python 영업 리드 도구를 설명하지만, 제공된 원문은 스크래퍼 초기화에서 끊겨 실제 일괄 추출과 Excel 저장 구현은 확인할 수 없다.
🖼️ 인포그래픽

🖼️ 4컷 인포그래픽

💡 한 줄 요약
Streamlit·Firecrawl·Pydantic으로 사용자 지정 항목을 여러 웹사이트에서 추출하는 Python 영업 리드 도구를 설명하지만, 제공된 원문은 스크래퍼 초기화에서 끊겨 실제 일괄 추출과 Excel 저장 구현은 확인할 수 없다.
📌 핵심 요약
- Sales Lead Extractor는 CSV·TXT로 웹사이트 URL 목록을 받고 사용자가 지정한 회사명·연락처·팀 규모 등의 정보를 수집해 Excel로 제공하는 것을 목표로 한다. 원문은 수작업으로 몇 시간 걸리던 작업을 몇 분으로 줄일 수 있다고 주장하지만, 성능 측정 결과는 제시하지 않는다.
- Firecrawl은 자연어 요청과 JSON 스키마로 구조화된 정보를 추출한다. 예제에서는 Pydantic의 CompanyInfo로 company·email 필드를 정의하고 openai.com에서 추출한 결과를 검증한다.
- Streamlit 화면은 CSV 첫 번째 열이나 TXT의 줄별 URL을 읽고, 추출 필드를 1~10개 입력받는다. 필드명은 소문자와 밑줄 형태로 바꾸며, URL 형식과 업로드 파일의 보안 검증은 설명의 단순화를 위해 생략한다.
- DynamicLeadModel은 사용자 입력을 바탕으로 모든 필드가 문자열인 Pydantic 모델을 생성한다. pandas·openpyxl을 포함한 의존성과 파일 구조를 소개하지만, 제공된 원문은 LeadScraper에서 FirecrawlApp을 초기화하는 부분까지만 담고 있다.
- 2026년 11월 업데이트는 People Data가 2억 5천만 명 이상과 2,600만 개 이상 기업을 대상으로 업무용 이메일·직무·회사 정보를 제공한다고 소개한다. Headless Clay는 이 정보 보강 흐름을 ChatGPT·Claude에서 실행하며 매월 무료 크레딧 1,000개로 시작할 수 있다고 설명한다.
🧩 주요 포인트
- 자연어 설명과 동적 Pydantic 모델의 결합 → 고정된 추출 항목 대신 사용자 요구에 맞춘 구조를 만들지만, 직원 수 같은 항목도 문자열로 정의된다.
- CSV·TXT 업로드와 1~10개 필드 입력 → 일괄 수집 요청을 간단히 구성할 수 있으나, 생략된 URL·파일 검증은 실제 사용 전에 보완할 지점으로 남는다.
- Excel 제공 목표와 LeadScraper 초기화까지만 있는 코드 → 도구의 설계 방향은 파악할 수 있지만, 실제 일괄 추출·Excel 저장의 완성과 동작 여부는 제공된 원문만으로 판단할 수 없다.
🧠 상세 정리
1. 수작업 리드 수집을 줄이려는 도구의 목표
Bex Tuychiev의 글은 영업팀이 웹사이트에서 잠재 고객 정보를 직접 모으는 데 많은 시간을 쓴다는 문제에서 출발하며, 이를 줄일 Sales Lead Extractor를 Python으로 만드는 과정을 소개한다. 사용자는 웹사이트 URL 목록을 업로드하고 회사명, 연락처, 팀 규모처럼 필요한 항목을 직접 지정하며, 앱은 Streamlit 화면과 Firecrawl API를 연결해 정보를 자동 수집하도록 설계된다. 원문은 AI가 웹사이트 내용을 읽어 정돈된 Excel 파일로 바꾸고, 몇 시간의 복사·붙여넣기 작업을 몇 분으로 줄일 수 있다고 설명하지만 이를 뒷받침하는 실행 시간이나 비교 실험은 제시하지 않는다. 따라서 이 글의 출발점은 유연한 수집 도구의 제작 방법과 기대 효과이며, 제공된 코드가 그 목표를 어디까지 구현하는지는 뒤의 구현 범위와 구분해 읽어야 한다.
2. 연락처 수요를 위한 업데이트와 사전 준비
2026년 11월 업데이트는 회사 웹페이지 자체보다 사람의 연락처가 필요한 경우를 별도로 다루며, People Data가 업무용 이메일과 직무·회사 정보를 반환한다고 소개한다. 제시된 데이터 범위는 2억 5천만 명 이상과 2,600만 개 이상 기업이며, Headless Clay는 이러한 정보 보강 흐름을 ChatGPT와 Claude에서 실행하고 매월 무료 크레딧 1,000개로 시작할 수 있다고 설명한다. 이 내용은 본문의 웹사이트 기반 추출 도구와 관련된 추가 안내로 등장하며, 뒤에 나오는 Python 코드에서 People Data나 Headless Clay를 연결하는 과정은 제시되지 않는다. 본격적인 제작에 필요한 사전 조건으로는 API 키가 있는 Firecrawl 계정을 명시하고, Firecrawl을 처음 접하는 독자를 위해 다음 단계에서 기본 사용법부터 설명한다.
3. 자연어와 스키마를 이용하는 Firecrawl 추출
원문은 Firecrawl을 대규모 웹 검색·스크래핑·상호작용을 위한 웹 데이터 API로 소개하고, HTML 선택자나 XPath 대신 자연어 이해로 원하는 내용을 식별하고 추출한다는 점을 강조한다. 기본 예제는 Pydantic의 CompanyInfo 모델에 company와 email을 문자열로 선언한 뒤, model_json_schema()로 Firecrawl에 전달할 JSON 스키마를 만드는 흐름이다. 이어 FirecrawlApp의 scrape_url()에 openai.com 주소와 회사명·연락 이메일을 찾으라는 영어 요청, 추출 형식과 스키마를 전달하며, 반환된 extract 데이터를 CompanyInfo에 넣어 검증한다. 이 예제가 보여주는 핵심은 사용자가 원하는 정보를 자연어로 설명하면서도 반환 구조를 모델로 명시할 수 있다는 점이며, 글은 이 방식을 여러 영업 리드 사이트로 확장하는 도구의 기반으로 삼는다.
4. 개발 환경과 파일 구조 구성
개발 환경은 sales-lead-extractor 작업 디렉터리와 Python 가상환경을 만드는 데서 시작하며, 가상환경 활성화 방법은 일반 환경과 Windows를 나누어 안내한다. 의존성 관리는 Poetry를 사용하고 Python 버전을 묻는 단계에서는 ^3.10을 입력하도록 하며, streamlit·firecrawl-py·pandas·pydantic·openpyxl·python-dotenv를 추가하는 명령을 제시한다. 프로젝트에는 data와 src 디렉터리를 만들고 .gitignore, README.md, .env 및 src 아래 app.py·models.py·scraper.py를 두며, 루트의 .env에 Firecrawl API 키를 넣도록 설명한다. 다만 제공된 본문에는 Poetry 설치·초기화, API 키 설정 예시, Streamlit 실행을 언급하는 일부 대목의 구체적인 명령이나 내용이 빠져 있으므로, 환경 구성이 완전히 재현 가능한 형태로 제시됐다고 보기는 어렵다.
5. Streamlit 업로드 화면과 URL 읽기
앱은 화면과 사용자 흐름을 먼저 만들고 내부 기능을 차례로 붙이는 하향식 접근을 택하며, app.py의 main()에서 제목과 안내문, CSV·TXT 파일을 받는 업로드 컴포넌트를 구성한다. load_urls()는 CSV를 pandas로 헤더 없이 읽어 첫 번째 열을 목록으로 반환하고, TXT는 파일 내용을 디코딩한 뒤 줄바꿈으로 나누고 각 줄의 앞뒤 공백과 빈 줄을 제거한다. 업로드가 있으면 이 함수를 실행해 읽은 URL 개수를 화면에 표시하므로, 사용자는 다음 단계로 가기 전에 입력 규모에 대한 피드백을 받는다. 원문은 두 형식에서 정리된 URL 목록을 얻는다고 설명하지만 제시된 CSV 코드에는 TXT와 같은 명시적 빈 줄 제거 처리가 없으며, URL 형식과 전체 파일의 보안 검증도 단순화를 위해 구현하지 않았다고 밝힌다.
6. 사용자 지정 필드와 추출 시작 흐름
파일 업로드 다음에는 추출할 항목을 정의하는 화면을 배치하고, 필드 수를 최소 1개·최대 10개·기본 3개로 설정해 사용자가 필요한 정보의 범위를 고르게 한다. 각 항목은 두 열에 이름과 설명을 입력하며, 이름은 소문자로 바꾸고 공백을 밑줄로 치환한 뒤 이름과 설명이 모두 있는 쌍만 fields 사전에 저장한다. 설명 예시로는 웹사이트 머리말이나 바닥글의 회사명, About 또는 Company 페이지의 직원 수, 채용 공고나 바닥글의 기술명, 회사 소개에 나타난 주력 산업이 제시되며, 이 설명은 이후 모델과 AI 추출을 안내하는 데 쓰인다. Start Extraction 버튼은 fields가 있을 때 처리 중임을 알리는 스피너를 표시하도록 만들지만, 이 단계의 내부 코드는 pass이므로 버튼을 눌러도 실제 수집은 아직 실행되지 않는다.
7. 필드 정의를 동적 Pydantic 모델로 변환
models.py에서는 BaseModel과 Field를 이용해 사용자 지정 항목을 데이터 검증과 직렬화에 사용할 모델로 바꾸며, DynamicLeadModel 클래스의 create_model()이 그 변환을 담당한다. 메서드는 필드명과 설명으로 이루어진 사전을 받아 각 필드의 타입 주석을 str로 지정하고, Field의 description에 사용자가 입력한 설명을 넣어 모델 메타데이터를 구성한다. 마지막으로 type()을 사용해 BaseModel을 상속하는 LeadData라는 새 모델 클래스를 반환하며, 이 모델은 Firecrawl의 AI 추출에 필요한 항목과 설명을 전달하는 기반이 된다. 여기서 동적으로 바뀌는 것은 필드의 이름과 설명이며 타입은 모두 문자열로 고정되므로, 앞서 예시로 든 직원 수 같은 수치성 항목도 해당 코드에서는 숫자 타입으로 별도 정의되지 않는다.
8. 스크래퍼 초기화와 제공된 구현의 한계
scraper.py로 넘어가면 FirecrawlApp, Dict·List, datetime, pandas와 DynamicLeadModel을 가져오며, 원문은 datetime을 출력 파일의 고유한 타임스탬프 생성에 쓰고 pandas를 수집 데이터의 DataFrame 구성과 Excel 내보내기에 사용한다고 설명한다. 이어 LeadScraper 클래스를 선언하고 생성자에서 self.app = FirecrawlApp()으로 API 객체를 초기화하지만, 제공된 본문은 그 직후 문장이 끊긴 상태로 끝난다. 따라서 여러 URL을 순회해 데이터를 추출하는 실제 처리, 동적 모델을 스크래퍼와 연결하는 호출, 결과를 Excel로 저장하고 화면에 제공하는 완성 코드는 이 자료에서 확인할 수 없다. 글이 제시한 전체 목표와 화면·모델의 설계 흐름은 파악할 수 있으나, 일괄 추출과 파일 출력까지 작동하는 완성 앱이 제공됐다고 단정할 근거는 부족하다.
🧾 핵심 주장 / 시사점
- 사용자가 입력한 필드 설명이 화면 설정에서 끝나지 않고 Pydantic 모델의 메타데이터로 이어지므로, 추출 요구와 데이터 구조를 연결하는 것이 설계의 중심이다.
- Pydantic으로 결과 구조를 검증하는 것과 URL·업로드 파일을 검증하는 것은 별개이며, 원문은 전자를 구현하면서 후자는 생략한다.
- People Data·Headless Clay 업데이트는 사람의 연락처와 정보 보강이라는 추가 선택지를 소개하지만, 제공된 Python 도구에 통합된 기능으로 볼 수는 없다.
✅ 액션 아이템
- 사용자 지정 항목을 DynamicLeadModel에 연결할 때 모든 필드가 문자열이라는 제약을 검토할 필요가 있다.
- CSV·TXT 기반 일괄 수집을 실제 사용할 경우 생략된 URL·파일 검증을 보완할 필요가 있다.
- Excel 제공 목표의 구현 여부를 판단하려면 LeadScraper 초기화 이후의 실제 일괄 추출·Excel 저장 코드를 확인할 필요가 있다.
❓ 열린 질문
- 모든 필드가 문자열인 DynamicLeadModel은 직원 수처럼 수치로 활용할 항목의 요구를 충족하는가?
- CSV·TXT 업로드에서 생략된 URL 형식과 파일 검증은 실제 사용 전에 어떻게 보완할 것인가?
- LeadScraper 초기화 이후의 실제 일괄 추출과 Excel 저장은 어떻게 구현되어 있는가?