Numery telefonu z LinkedIn możesz znaleźć w Pythonie, wysyłając publiczne adresy profili linkedin.com/in/... do API Waterfall Phone Finder od Datablist. API kolejno sprawdza dostępnych dostawców danych telefonicznych i zwraca znalezione numery w formacie międzynarodowym wraz z kodami krajów.
W tym poradniku wykorzystamy bibliotekę Requests do przygotowania kompletnej integracji w Pythonie. Następnie na podstawie tych samych wyników utworzymy lokalną listę kontaktów do weryfikacji przez zespół sprzedaży. Przy każdym prospekcie zachowamy imię i nazwisko, adres profilu LinkedIn oraz opiekuna konta.
📌 Podsumowanie dla zabieganych
Użyj jednego API, aby znaleźć numery telefonu na podstawie listy publicznych profili LinkedIn, a następnie przygotuj lokalną listę kontaktów zawierającą imiona i nazwiska prospektów oraz opiekunów kont. Waterfall Phone Finder kolejno sprawdza dostępnych dostawców i przekazuje znalezione numery zespołowi do weryfikacji.
- Dane wejściowe: rekordy prospektów z publicznym adresem profilu LinkedIn.
- Wynik: lokalna lista kontaktów ze znalezionymi numerami w formacie międzynarodowym, kodami krajów, imionami i nazwiskami oraz opiekunami kont.
💡 Wolisz rozwiązanie no-code? Użyj Waterfall Phone Finder od Datablist, aby znajdować numery telefonu na podstawie profili LinkedIn bez pisania kodu.
Jeśli dysponujesz imionami i nazwiskami zamiast adresów profili, najpierw skorzystaj z procesu no-code wyszukiwania numerów na podstawie nazwiska albo znajdź profile LinkedIn na podstawie nazwisk w Pythonie.
Skonfiguruj Python, Requests i klucz API Datablist
W tym przykładzie używam pakietu requests. Utwórz folder projektu, aktywuj środowisko wirtualne, zainstaluj Requests i utwórz plik skryptu:
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"Utwórz Personal API Key na swoim koncie Datablist i użyj go jako wartości DATABLIST_API_KEY. Dostęp do REST API jest funkcją planu Growth. Koszt punktów pobieranych za udane wyszukiwania omawiam w dalszej części poradnika.
Znajdź numery telefonu jedną funkcją w Pythonie
Przykład zawiera trzy edytowalne rekordy prospektów. Każdy z nich ma stały prospect_id, imię i nazwisko, publiczny adres LinkedIn oraz opiekuna konta odpowiedzialnego za weryfikację wyniku:
- Florian Poullin:
https://www.linkedin.com/in/florianpoullin/ - Satya Nadella:
https://www.linkedin.com/in/satyanadella/ - Reid Hoffman:
https://www.linkedin.com/in/reidhoffman/
Do API trzeba wysłać tylko stały identyfikator i adres LinkedIn. Imię i nazwisko oraz opiekun konta pozostają w lokalnym rekordzie źródłowym. Dzięki temu zapytanie jest niewielkie, a zespół zachowuje informacje biznesowe potrzebne po otrzymaniu wyniku.
Wklej poniższy kompletny skrypt do pliku 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))Uruchom plik poleceniem:
python find_phone_numbers.pyMożesz także pobrać utrzymywany przez Datablist synchroniczny przykład wykorzystujący Requests. Powyższy skrypt zachowuje tę samą prostą kolejność działań: wysyła jedno zadanie, czeka na jego zakończenie i pobiera wszystkie strony wyników.
Wyślij zapytanie o numer telefonu
List comprehension przekształca każdego prospekta źródłowego w format danych wejściowych API. Wartość prospect_id staje się inputId, a linkedin_url — data.profileUrl. Użyj publicznego adresu profilu osoby ze ścieżką linkedin.com/in/.... To enrichment nie obsługuje adresów URL z Sales Navigator.
Funkcja generuje uniqueId i wyświetla go przed żądaniem POST. Zapytanie przesyła tę wartość wraz z identyfikatorem enrichmentu waterfall-phone-finder, ustawieniem cache i danymi wejściowymi. Prawidłowe zgłoszenie zwraca HTTP 202 Accepted oraz @id zadania, które jest dalej przetwarzane w tle.
Dokumentacja API Waterfall Phone Finder zawiera aktualne ustawienia, pola wejściowe, dane wyjściowe, koszty punktowe i limity.
Dla jednego prospekta body zapytania ma następującą strukturę:
{
"enrichmentId": "waterfall-phone-finder",
"uniqueId": "generated-uuid",
"settings": {
"cacheAge": "30"
},
"inputs": [
{
"inputId": "prospect-florian-poullin",
"data": {
"profileUrl": "https://www.linkedin.com/in/florianpoullin/"
}
}
]
}Publiczny adres profilu jest daną wejściową wyszukiwania. inputId to klucz łączenia, który przypisuje wynik do imienia i nazwiska oraz opiekuna konta w rekordzie źródłowym. Wybierz identyfikator, który jest stały w Twoim systemie i unikalny w obrębie zadania.
Poczekaj na zakończenie zadania w tle
Klient Requests lokalnie blokuje działanie programu i co trzy sekundy sprawdza stan zadania. Samo zadanie Datablist nadal działa w tle. Gdy jego status zmieni się na completed, funkcja rozpocznie pobieranie wyników. Status failed lub stopped spowoduje zgłoszenie błędu z identyfikatorem zadania, co ułatwi jego sprawdzenie.
Pobierz wszystkie strony wyników
Zapytanie o wyniki pobiera maksymalnie 100 wierszy jednocześnie. Kolejne strony są pobierane do momentu, gdy nextCursor przyjmie wartość null. Każdy wynik zawiera źródłowy inputId, dlatego możesz przypisać go do właściwego prospekta bez polegania na kolejności odpowiedzi.
Jak waterfall wyszukuje numer telefonu
W przykładzie ustawiamy cacheAge na "30". Datablist najpierw sprawdza, czy istnieje odpowiedni wynik mający nie więcej niż 30 dni. Jeśli tak, API może wykorzystać go ponownie. Ustawienie pozwala użyć wyniku z cache, ale nie gwarantuje, że taki wynik będzie dostępny.
Jeśli profil nadal nie ma przypisanego numeru, zarządzany waterfall kolejno sprawdza dostępnych dostawców danych telefonicznych. Gdy dostawca nie zwróci użytecznego numeru, rekord przechodzi do następnego źródła. Znalezienie prawidłowego numeru kończy sekwencję dla danego rekordu.
Dlaczego waterfall zwiększa zasięg na wielu rynkach
Datablist nie opiera się na jednym dostawcy danych telefonicznych. Poszczególni dostawcy korzystają z różnych zbiorów danych, a ich pokrycie zależy od kraju i rynku. Jeśli jedno źródło nie ma numeru telefonu, inne może go znaleźć. Datablist zarządza wszystkimi dostawcami w ramach jednej integracji API.
Dla zespołu sprzedaży budującego listę kontaktów na kilku rynkach oznacza to mniej pominiętych prospektów po nieudanym wyszukiwaniu u jednego dostawcy. Kod w Pythonie wysyła jedno zadanie i odczytuje wyniki w jednym formacie, więc nie musisz tworzyć ani utrzymywać osobnej integracji z każdym źródłem.
Ustaw cacheAge na "0", jeśli Twój proces wymaga nowego wyszukiwania. W tym przykładzie pozostaw "30", aby umożliwić ponowne wykorzystanie odpowiedniego wyniku z cache.
Odczytaj pełny wynik
Poniżej znajduje się przykładowy wynik dla Floriana Poullina. Numery telefonu zostały zamaskowane.
{
"inputId": "prospect-florian-poullin",
"status": "success",
"outputs": {
"finderProvider": "wizleads",
"phoneNumber": "+33 • •• •• •• ••",
"phoneNumberCountry": "FR"
},
"creditsUsed": "500",
"error": null
}phoneNumber zawiera numer w formacie międzynarodowym, jeśli udało się go znaleźć. Prefiks +33 oraz phoneNumberCountry: "FR" wskazują numer francuski.
finderProvider określa źródło, które zwróciło ten wynik. Wiersz wykorzystał 500 punktów, a error: null oznacza, że API nie zgłosiło błędu na poziomie wiersza.
Przygotuj zweryfikowaną listę kontaktów sprzedażowych
Gdy zmienna phone_results jest już dostępna, możesz przygotować lokalną listę do sprawdzenia przez zespół sprzedaży. Dodaj poniższy blok w tym samym pliku, za kodem wyświetlającym wyniki. Wykorzystuje on istniejące dane i nie wykonuje drugiego wywołania 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))Indeks wyników wykorzystuje inputId jako klucz łączenia, dzięki czemu każdy wynik pozostaje przypisany do rekordu źródłowego niezależnie od pozycji na liście. Payload API zawiera identyfikator i adres profilu każdego prospekta, natomiast oryginalna lista prospects przechowuje imię i nazwisko oraz opiekuna konta potrzebnych na liście kontaktów.
W wierszu Floriana identyfikator prospect-florian-poullin łączy zwrócony wynik z pierwotnymi polami name, linkedin_url i account_owner. Zespół odczytuje numer oraz kod kraju FR z result.outputs. Kompletny obiekt API — wraz ze statusem, wykorzystanymi punktami i błędem — pozostaje dostępny w polu result.
Pętla tworząca listę zachowuje kolejność elementów w prospects. Przed dodaniem pola result kopiuje każdy uwzględniony rekord, dzięki czemu pierwotna lista źródłowa nadal może służyć do nanoszenia poprawek lub obsługi innego kanału follow-up.
Rekord bez wyniku, z błędem lub pustym numerem pozostaje na niezmienionej liście prospects, ale nie trafia do call_list. Kod przygotowuje lokalną listę kontaktów do weryfikacji przez zespół sprzedaży.
Oszacuj koszt API Waterfall Phone Finder
Każdy nowy numer telefonu znaleziony poza cache przez domyślny zarządzany waterfall kosztuje 500 punktów. Za zaakceptowany wynik z cache oraz wyszukiwanie bez rezultatu pobierane jest 0 punktów. Aby ustalić rzeczywisty koszt, odczytaj creditsUsed w każdym zwróconym wierszu — nie mnoż liczby wszystkich przesłanych profili przez 500.
Do planowania użyj wzoru:
liczba nowych numerów znalezionych poza cache × 500 punktów
Czterdzieści nowych numerów kosztuje 20 000 punktów, a sto — 50 000 punktów. Przy aktualnej bazowej cenie doładowania w USD za 20 USD otrzymasz 20 000 punktów, więc 500 punktów odpowiada 0,50 USD. Subskrypcja Growth zapewniająca dostęp do REST API jest rozliczana osobno. Aktualne plany i pakiety punktów znajdziesz w cenniku Datablist.
Załóżmy, że ze 100 profili uzyskasz 20 nowych numerów, 5 zaakceptowanych numerów z cache i 75 rekordów bez wyniku. Opłata obejmie 20 nowych numerów, więc wyszukiwanie wykorzysta 10 000 punktów. Lista kontaktów może zawierać wszystkie 25 znalezionych numerów. W kalkulatorze wpisz 20, a nie wszystkie 100 rekordów wejściowych ani wszystkie 25 znalezionych numerów. Ten przykład pokazuje sposób rozliczania, a nie przewidywany success rate.
Napraw typowe błędy i odzyskaj istniejące zadanie
- Brakuje
DATABLIST_API_KEY: skrypt zatrzyma się przed wysłaniem zapytania. Wyeksportuj zmienną i ponownie uruchom plik. - API odrzuca klucz:
raise_for_status()zgłosi błąd HTTP. Ponownie skopiuj Personal API Key i sprawdź, czy zapytanie wysyła go w nagłówkuX-API-Key. - Adres profilu nie jest obsługiwany: zastąp pusty, nieprawidłowy, firmowy lub pochodzący z Sales Navigator adres publicznym profilem osoby ze ścieżką
linkedin.com/in/.... - Brakuje punktów: przed wysłaniem kolejnych zadań sprawdź saldo konta i liczbę dostępnych punktów.
- Zadanie ma status
failedlubstopped: zanim zdecydujesz, co uruchomić ponownie, sprawdź błąd, dostępne wyniki i wykorzystane punkty. - Wiersz nie zawiera wyniku lub ma błąd: zachowaj prospekta źródłowego do korekty lub kontaktu innym kanałem. Sam wiersz nie wyjaśnia, który dostawca, rynek lub warunek widoczności wpłynął na rezultat.
Jeśli odpowiedź na żądanie POST zaginie, użyj wartości uniqueId wyświetlonej przed wysłaniem. Wyświetl listę zadań, zanim prześlesz je ponownie. Zastąp your-api-key w poniższym zapytaniu, a następnie znajdź zadanie, którego uniqueId odpowiada wyświetlonej wartości:
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"Jeśli zadania nie ma na pierwszej stronie, przechodź dalej zgodnie z wartością nextCursor w odpowiedzi zawierającej listę zadań. Skopiuj @id pasującego zadania, zastąp nim TASK_ID poniżej, a następnie sprawdź jego status lub pobierz istniejące wyniki:
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"Dokumentacja API zadań opisuje statusy zadań, paginację wyników i zachowanie po przerwaniu procesu.
Co dalej
Masz teraz jedną funkcję Requests wielokrotnego użytku, która obsługuje publiczne adresy profili LinkedIn, oraz mechanizm łączenia po stałym identyfikatorze, który przygotowuje znalezione numery do weryfikacji przez sprzedaż.
Zastąp edytowalne przykłady niewielką grupą zakwalifikowanych prospektów. Zachowaj ich stałe identyfikatory i opiekunów kont, a następnie sprawdź każdy znaleziony numer przed przekazaniem gotowej listy do procesu telefonicznego swojego zespołu. Zacznij od małej partii, aby zweryfikować mapowanie identyfikatorów i zwracane pola. Jeśli potrzebujesz nieblokującej współbieżności, skorzystaj z utrzymywanego przykładu async HTTPX.


