Номера телефонов из LinkedIn можно находить с помощью Python: достаточно передать публичные URL профилей вида
linkedin.com/in/... в Waterfall Phone Finder API от Datablist.
API последовательно проверяет подходящих поставщиков телефонных данных и возвращает
найденные номера в международном формате с кодами стран.
В этом руководстве мы воспользуемся библиотекой Requests и создадим полноценную интеграцию на Python. Затем на основе полученных результатов подготовим локальный список для обзвона, сохранив имя каждого потенциального клиента, URL профиля LinkedIn и ответственного менеджера.
📌 Кратко для тех, кто спешит
Используйте один API, чтобы найти номера телефонов по списку публичных URL профилей LinkedIn, а затем подготовьте локальный список для обзвона с именами потенциальных клиентов и ответственными менеджерами. Waterfall Phone Finder последовательно обращается к подходящим поставщикам и сохраняет найденные номера для проверки вашей командой.
- Входные данные: записи потенциальных клиентов с публичным URL профиля LinkedIn.
- Результат: локальный список для обзвона с найденными международными номерами, кодами стран, именами и ответственными менеджерами.
💡 Предпочитаете решение без кода? Используйте Waterfall Phone Finder, чтобы находить номера телефонов по URL профилей LinkedIn без программирования.
Если у вас есть имена, но нет URL профилей, сначала воспользуйтесь no-code-сценарием поиска телефона по имени или найдите профили LinkedIn по именам с помощью Python.
Настройка Python, Requests и API-ключа Datablist
В этом примере на Python используется пакет requests. Создайте папку проекта,
активируйте виртуальное окружение, установите Requests и создайте файл скрипта:
mkdir waterfall-phone-lookup
cd waterfall-phone-lookup
python -m venv .venv
source .venv/bin/activate
python -m pip install requests
touch find_phone_numbers.py
export DATABLIST_API_KEY="your-api-key"Создайте Personal API Key в своём
аккаунте Datablist и укажите его в DATABLIST_API_KEY. Доступ к REST API входит
в тариф Growth. Расход кредитов за успешный поиск мы разберём далее в руководстве.
Поиск номеров одной готовой функцией Python
В примере используются три редактируемые записи потенциальных клиентов. В каждой есть
постоянный prospect_id, имя, публичный URL LinkedIn и ответственный менеджер,
который должен проверить результат:
- Florian Poullin —
https://www.linkedin.com/in/florianpoullin/ - Satya Nadella —
https://www.linkedin.com/in/satyanadella/ - Reid Hoffman —
https://www.linkedin.com/in/reidhoffman/
В API нужно передавать только постоянный ID и URL LinkedIn. Имя и ответственный менеджер остаются в локальной исходной записи. Такой подход сокращает запрос, но сохраняет бизнес-данные, которые понадобятся команде после получения результата.
Вставьте этот скрипт целиком в find_phone_numbers.py:
import json
import os
import time
import uuid
import requests
def find_phone_numbers(prospects, api_key, settings):
"""Submit one phone lookup task, wait, and return every result."""
tasks_url = "https://api.datablist.com/v1/enrichments/tasks"
headers = {"X-API-Key": api_key}
inputs = [
{
"inputId": prospect["prospect_id"],
"data": {"profileUrl": prospect["linkedin_url"]},
}
for prospect in prospects
]
unique_id = str(uuid.uuid4())
print(f"Task uniqueId: {unique_id}", flush=True)
payload = {
"enrichmentId": "waterfall-phone-finder",
"uniqueId": unique_id,
"settings": settings,
"inputs": inputs,
}
response = requests.post(tasks_url, headers=headers, json=payload)
response.raise_for_status()
task = response.json()
task_id = task["@id"]
task_url = f"{tasks_url}/{task_id}"
while task["status"] not in ("completed", "failed", "stopped"):
time.sleep(3)
response = requests.get(task_url, headers=headers)
response.raise_for_status()
task = response.json()
if task["status"] != "completed":
raise RuntimeError(
f"Task {task_id} {task['status']}: {task.get('error')}"
)
results = []
results_url = f"{task_url}/results"
params = {"limit": 100}
while True:
response = requests.get(results_url, headers=headers, params=params)
response.raise_for_status()
page = response.json()
results.extend(page["results"])
next_cursor = page["nextCursor"]
if next_cursor is None:
break
params["cursor"] = next_cursor
return results
if __name__ == "__main__":
api_key = os.environ.get("DATABLIST_API_KEY")
if not api_key:
raise SystemExit("Set DATABLIST_API_KEY before running this script.")
prospects = [
{
"prospect_id": "prospect-florian-poullin",
"name": "Florian Poullin",
"linkedin_url": "https://www.linkedin.com/in/florianpoullin/",
"account_owner": "Habib",
},
{
"prospect_id": "prospect-satya-nadella",
"name": "Satya Nadella",
"linkedin_url": "https://www.linkedin.com/in/satyanadella/",
"account_owner": "Florian",
},
{
"prospect_id": "prospect-reid-hoffman",
"name": "Reid Hoffman",
"linkedin_url": "https://www.linkedin.com/in/reidhoffman/",
"account_owner": "Habib",
},
]
settings = {"cacheAge": "30"}
phone_results = find_phone_numbers(prospects, api_key, settings)
print(json.dumps(phone_results, indent=2, ensure_ascii=False))Запустите файл:
python find_phone_numbers.pyТакже можно скачать поддерживаемый Datablist синхронный пример для Requests. Приведённый выше скрипт работает в том же простом порядке: создаёт задачу, ждёт её завершения и получает все страницы с результатами.
Отправка запроса на поиск телефона
Генератор списка преобразует каждую исходную запись в формат входных данных API.
Значение prospect_id становится inputId, а linkedin_url —
data.profileUrl. Используйте публичный URL личного профиля с путём
linkedin.com/in/.... Это обогащение не поддерживает URL Sales Navigator.
Функция генерирует uniqueId и выводит его перед POST-запросом. Вместе с этим
значением запрос передаёт ID обогащения waterfall-phone-finder, настройку кеша
и входные данные. При успешной отправке API возвращает HTTP 202 Accepted и
@id задачи, а обработка продолжается в фоновом режиме.
В документации Waterfall Phone Finder API перечислены актуальные настройки, входные и выходные поля, стоимость в кредитах и ограничения.
Для одного потенциального клиента тело запроса выглядит так:
{
"enrichmentId": "waterfall-phone-finder",
"uniqueId": "generated-uuid",
"settings": {
"cacheAge": "30"
},
"inputs": [
{
"inputId": "prospect-florian-poullin",
"data": {
"profileUrl": "https://www.linkedin.com/in/florianpoullin/"
}
}
]
}Публичный URL профиля служит входным значением для поиска. inputId — это ключ
сопоставления, который связывает результат с именем и ответственным менеджером
в исходной записи. Выберите ID, который остаётся неизменным в вашей системе и
уникален в пределах задачи.
Ожидание фоновой задачи
Клиент Requests локально блокирует выполнение и проверяет задачу каждые три
секунды. При этом задача Datablist продолжает выполняться в фоновом режиме. Когда
её статус меняется на completed, функция переходит к получению результатов.
Статус failed или stopped вызывает ошибку с ID задачи, чтобы вы могли её проверить.
Получение всех страниц результатов
Запрос результатов получает до 100 строк за один раз. Страницы загружаются до тех
пор, пока nextCursor не станет равен null. Каждый результат содержит исходный
inputId, поэтому его можно сопоставить с нужным потенциальным клиентом независимо
от порядка ответов.
Как Waterfall находит номер телефона
В примере параметру cacheAge присвоено значение "30". Сначала Datablist ищет
подходящий результат не старше 30 дней. Если он существует, API может использовать
его повторно. Настройка разрешает брать данные из кеша, но не гарантирует их наличие.
Если профиль не найден, управляемый Waterfall последовательно обращается к подходящим поставщикам телефонных данных. Если поставщик не возвращает пригодный номер, обработка записи продолжается. Как только номер найден, последовательность для этой записи останавливается.
Преимущества Waterfall для разных стран и рынков
Datablist не зависит от одного поставщика телефонных данных. Поставщики используют разные наборы данных, а их покрытие различается в зависимости от страны и рынка. Если у одного поставщика номера нет, его может найти другой. Datablist управляет всеми поставщиками через одну API-интеграцию.
Для отдела продаж, который формирует список для обзвона на нескольких рынках, это означает меньше потерянных потенциальных клиентов после неудачного ответа одного поставщика. Ваш Python-код отправляет одну задачу и получает результаты в едином формате — создавать и поддерживать отдельную интеграцию для каждого поставщика не придётся.
Установите cacheAge в "0", если вашему процессу требуются исключительно свежие
результаты. В этом примере сохраните значение "30", чтобы можно было повторно
использовать подходящий результат из кеша.
Чтение полного результата API
Ниже приведён один результат для Florian Poullin. Номер телефона скрыт.
{
"inputId": "prospect-florian-poullin",
"status": "success",
"outputs": {
"finderProvider": "wizleads",
"phoneNumber": "+33 • •• •• •• ••",
"phoneNumberCountry": "FR"
},
"creditsUsed": "500",
"error": null
}Если номер доступен, поле phoneNumber содержит его в международном формате.
Префикс +33 и значение phoneNumberCountry: "FR" указывают на французский номер.
В finderProvider указан сервис, который нашёл этот результат. На строку было
потрачено 500 кредитов, а error: null означает, что API не вернул ошибку для строки.
Подготовка проверенного списка для обзвона
Получив phone_results, можно подготовить локальный список для проверки отделом
продаж. Добавьте следующий блок после вывода результатов в том же файле. Он
повторно использует уже полученные данные и не выполняет второй API-запрос:
results_by_id = {
result["inputId"]: result
for result in phone_results
}
call_list = []
for prospect in prospects:
result = results_by_id.get(prospect["prospect_id"])
if not result or result["status"] != "success":
continue
phone_number = result.get("outputs", {}).get("phoneNumber")
if not phone_number:
continue
call_list_record = prospect.copy()
call_list_record["result"] = result
call_list.append(call_list_record)
print(json.dumps(call_list, indent=2, ensure_ascii=False))Индекс результатов использует inputId как ключ сопоставления, поэтому каждый
результат остаётся связанным с исходной записью независимо от позиции в списке.
В payload API передаются ID и URL профиля каждого потенциального клиента, а
исходный список prospects хранит имя и ответственного менеджера для списка обзвона.
В строке Florian значение prospect-florian-poullin связывает полученный результат
с исходными name, linkedin_url и account_owner. Команда получает номер и код
страны FR из result.outputs. Полный объект API, включая статус, кредиты и ошибку,
остаётся доступен в поле result.
Цикл формирования списка сохраняет порядок записей из prospects. Перед добавлением
result каждая выбранная запись копируется, поэтому исходный список остаётся
доступен для исправлений или другого канала коммуникации.
Запись без результата, с ошибкой или пустым номером остаётся в неизменном списке
prospects, но не попадает в call_list. Код создаёт локальный список для обзвона,
который затем можно проверить.
Расчёт стоимости Waterfall Phone Finder API
Каждый новый номер, найденный стандартным управляемым Waterfall без использования
кеша, стоит 500 кредитов. Подходящий результат из кеша стоит 0 кредитов, как и
поиск, не давший результата. Чтобы узнать фактические расходы, проверяйте
creditsUsed в каждой полученной строке, а не умножайте число всех отправленных
профилей на 500.
Для планирования используйте формулу:
количество новых номеров, найденных без кеша × 500 кредитов
Сорок новых номеров обойдутся в 20 000 кредитов, сто — в 50 000 кредитов. По текущему базовому тарифу пополнения в долларах США $20 дают 20 000 кредитов, поэтому 500 кредитов стоят $0,50. Подписка Growth, предоставляющая доступ к REST API, оплачивается отдельно. Актуальные тарифы и пакеты кредитов приведены на странице цен Datablist.
Рассмотрим пример: из 100 профилей получено 20 новых номеров, 5 подходящих номеров
из кеша и 75 записей без результата. Оплачиваются только 20 новых номеров, поэтому
поиск расходует 10 000 кредитов. При этом список для обзвона может содержать все
25 найденных номеров. В калькуляторе укажите 20, а не все 100 входных записей
или все 25 найденных номеров. Этот пример показывает принцип расчёта стоимости,
а не ожидаемый процент успешного поиска.
Исправление ошибок и восстановление задачи
- Переменная
DATABLIST_API_KEYотсутствует: скрипт остановится до отправки запроса. Экспортируйте переменную и снова запустите файл. - API отклоняет ключ:
raise_for_status()сообщит об HTTP-ошибке. Скопируйте Personal API Key ещё раз и убедитесь, что запрос передаёт его в заголовкеX-API-Key. - URL профиля не поддерживается: замените пустой, некорректный URL, ссылку на
компанию или Sales Navigator публичной ссылкой на личный профиль с путём
linkedin.com/in/.... - Недостаточно кредитов: проверьте баланс аккаунта и количество доступных кредитов перед отправкой новых задач.
- Задача получила статус
failedилиstopped: проверьте её ошибку, доступные результаты и расход кредитов, прежде чем решать, что нужно запустить повторно. - В строке нет результата или возникла ошибка: сохраните исходную запись для исправления или связи через другой канал. Сама строка не объясняет, какой именно поставщик, регион или условие видимости повлияли на результат.
Если POST-ответ потерян, используйте uniqueId, выведенный перед отправкой.
Получите список задач, прежде чем отправлять запрос повторно. Замените
your-api-key в следующем запросе, а затем найдите задачу, uniqueId которой
совпадает с выведенным значением:
curl --get "https://api.datablist.com/v1/enrichments/tasks" \
--header "X-API-Key: your-api-key" \
--data-urlencode "enrichmentId=waterfall-phone-finder" \
--data-urlencode "limit=100"Если задачи нет на первой странице, переходите дальше с помощью nextCursor из
ответа со списком задач. Скопируйте @id нужной задачи, замените TASK_ID ниже
и проверьте её статус либо получите существующие результаты:
curl "https://api.datablist.com/v1/enrichments/tasks/TASK_ID" \
--header "X-API-Key: your-api-key"
curl --get "https://api.datablist.com/v1/enrichments/tasks/TASK_ID/results" \
--header "X-API-Key: your-api-key" \
--data-urlencode "limit=100"В документации Task API описаны статусы задач, пагинация результатов и поведение при прерывании.
Следующие шаги
Теперь у вас есть переиспользуемая функция Requests для публичных URL профилей LinkedIn и механизм объединения по постоянному ID, который подготавливает найденные номера к проверке отделом продаж.
Замените редактируемые примеры небольшим набором квалифицированных потенциальных клиентов. Сохраните их постоянные ID и ответственных менеджеров, а затем проверяйте каждый найденный номер, прежде чем передавать подготовленный список в процесс обзвона. Начните с небольшой партии, чтобы проверить сопоставление ID и возвращаемые поля. Если вам нужна неблокирующая параллельная обработка, воспользуйтесь поддерживаемым асинхронным примером для HTTPX.


