Блог AST-SoftPro
Парсинг контактных данных: как найти клиентов через веб-скрейпинг на Python
Поиск клиентов через веб-скрейпинг
Поиск потенциальных клиентов — одна из самых затратных задач для бизнеса. Менеджеры тратят часы на ручной сбор контактных данных с сайтов, каталогов и площадок объявлений. Python позволяет автоматизировать этот процесс полностью: от сбора данных до формирования готовой базы для обзвона или рассылки.
В статье рассматриваются практические приёмы парсинга контактной информации: извлечение email, телефонов и сайтов компаний из открытых источников. Примеры основаны на реальном проекте автоматизированного сбора контактов.
Инструменты для парсинга
Для задач скрейпинга существует несколько подходов в зависимости от сложности целевого сайта:
| Инструмент | Тип сайтов | Сложность | Пример использования |
|---|---|---|---|
| requests + BeautifulSoup | Статические HTML-страницы | Низкая | Каталоги, справочники компаний |
| Selenium | Страницы с JavaScript | Средняя | SPA-приложения, динамические каталоги |
| Playwright | Современные сайты с JS | Средняя | Любые сайты, включая SPA |
| Scrapy | Масштабные проекты | Высокая | Парсинг тысяч страниц, распределённый сбор |
Для большинства задач поиска контактов достаточно requests + BeautifulSoup. Эти библиотеки покрывают 80% случаев, когда данные доступны в HTML без выполнения JavaScript.
Пример: сбор контактов из каталога компаний
Рассмотрим типичный сценарий: нужно собрать контактные данные компаний из отраслевого каталога.
import requests
from bs4 import BeautifulSoup
import csv
def parse_company_catalog(base_url, page_count=10):
"""Сбор контактов из каталога компаний."""
contacts = []
for page in range(1, page_count + 1):
url = f"{base_url}/page/{page}"
response = requests.get(url, headers={'User-Agent': 'Mozilla/5.0'})
soup = BeautifulSoup(response.text, 'html.parser')
for card in soup.select('.company-card'):
company = {
'name': card.select_one('.company-name').text.strip(),
'phone': card.select_one('.phone').text.strip() if card.select_one('.phone') else '',
'email': card.select_one('.email').text.strip() if card.select_one('.email') else '',
'website': card.select_one('.website a')['href'] if card.select_one('.website a') else '',
'address': card.select_one('.address').text.strip() if card.select_one('.address') else '',
}
contacts.append(company)
return contacts
# Использование
contacts = parse_company_catalog('https://catalog.example.com/companies')
print(f"Собрано контактов: {len(contacts)}")
Сохранение результатов в CSV и SQLite
После сбора данных важно сохранить их в удобном формате. CSV подходит для экспорта в Excel, SQLite — для дальнейшей обработки и дедупликации.
import sqlite3
def save_to_csv(contacts, filename='contacts.csv'):
"""Сохранение контактов в CSV для Excel."""
if not contacts:
return
keys = contacts[0].keys()
with open(filename, 'w', newline='', encoding='utf-8-sig') as f:
writer = csv.DictWriter(f, fieldnames=keys)
writer.writeheader()
writer.writerows(contacts)
print(f"Сохранено {len(contacts)} записей в {filename}")
def save_to_sqlite(contacts, db_path='contacts.db'):
"""Сохранение в SQLite с дедупликацией по email."""
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS contacts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT, phone TEXT, email TEXT UNIQUE,
website TEXT, address TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''')
for c in contacts:
try:
cursor.execute(
'INSERT OR IGNORE INTO contacts (name, phone, email, website, address) VALUES (?, ?, ?, ?, ?)',
(c['name'], c['phone'], c['email'], c['website'], c['address'])
)
except Exception:
pass
conn.commit()
conn.close()
print(f"Записи сохранены в {db_path}")
Работа с пагинацией и динамическими страницами
Не все каталоги имеют простую пагинацию. Некоторые загружают данные через AJAX или используют бесконечную прокрутку. В таких случаях пригодится Playwright:
from playwright.sync_api import sync_playwright
def parse_dynamic_catalog(url):
"""Парсинг каталога с динамической загрузкой."""
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
page.goto(url, wait_until='networkidle')
# Прокрутка для загрузки всех элементов
for _ in range(5):
page.evaluate('window.scrollBy(0, 500)')
page.wait_for_timeout(500)
contacts = []
for card in page.query_selector_all('.company-card'):
contacts.append({
'name': card.inner_text().strip(),
'phone': card.query_selector('.phone').inner_text() if card.query_selector('.phone') else '',
})
browser.close()
return contacts
Извлечение email и телефонов с помощью регулярных выражений
Иногда контакты не выделены в отдельные элементы HTML — они «спрятаны» в тексте страницы. В таких случаях на помощь приходят регулярные выражения:
import re
def extract_emails(text):
"""Поиск email-адресов в тексте."""
pattern = r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}'
return re.findall(pattern, text)
def extract_phones(text):
"""Поиск российских номеров телефонов."""
pattern = r'(?:\+7|8)[\s\-]?\(?\d{3}\)?[\s\-]?\d{3}[\s\-]?\d{2}[\s\-]?\d{2}'
return re.findall(pattern, text)
# Пример
page_text = soup.get_text()
emails = extract_emails(page_text)
phones = extract_phones(page_text)
print(f"Email: {emails}, Телефоны: {phones}")
Ответственный скрейпинг: правила и ограничения
Автоматизация сбора данных требует соблюдения этики и законодательства:
| Правило | Рекомендация |
|---|---|
| robots.txt | Проверяйте /robots.txt целевого сайта перед парсингом |
| Задержки | Добавляйте time.sleep(1-3) между запросами, не перегружайте сервер |
| User-Agent | Указывайте корректный User-Agent, не скрывайте бота |
| Персональные данные | Соблюдайте 152-ФЗ (РФ) и GDPR (ЕС) при сборе персональных данных |
| Коммерческое использование | Проверяйте условия использования сайта — данные могут быть защищены авторским правом |
Важно: собирайте только общедоступные контактные данные компаний (B2B), а не персональные данные физических лиц.
Заключение
Веб-скрейпинг на Python — мощный инструмент для автоматизации поиска клиентов. Комбинация requests + BeautifulSoup + re покрывает большинство задач сбора контактной информации. Для сложных сайтов с JavaScript используйте Playwright.
Ключевые шаги:
-
Выбор инструмента в зависимости от типа сайта;
-
Извлечение данных из HTML-структуры или текста страницы;
-
Сохранение в CSV/SQLite с дедупликацией;
-
Соблюдение правил ответственного скрейпинга.
Начните с простых каталогов, отладьте скрипт, а затем масштабируйте на более сложные источники.