Du kan hitta telefonnummer från LinkedIn i Python genom att skicka offentliga profil-URL:er av typen linkedin.com/in/... till Datablists Waterfall Phone Finder API. API:et kontrollerar tillgängliga leverantörer av telefondata i tur och ordning och returnerar hittade nummer i internationellt format med landskod.

Den här guiden använder biblioteket Requests för att skapa en komplett integration i Python. Därefter återanvänder vi samma resultat för att ta fram en lokal ringlista som innehåller varje prospects namn, LinkedIn-URL och kontoansvarig.

📌 Snabb sammanfattning

Använd ett enda API för att hitta telefonnummer från en lista med offentliga LinkedIn-profiler. Skapa sedan en lokal ringlista med varje prospects namn och kontoansvarig. Waterfall Phone Finder testar tillgängliga leverantörer i tur och ordning och gör de hittade numren redo för teamets granskning.

  • Input: Prospect-poster med en offentlig LinkedIn-profil.
  • Output: En lokal ringlista med hittade internationella telefonnummer, landskoder, namn och kontoansvariga.

💡 Föredrar du en no-code-lösning? Använd Datablists Waterfall Phone Finder för att hitta telefonnummer från LinkedIn-profiler utan att skriva kod.

Om du börjar med namn i stället för profil-URL:er kan du först följa vårt no-code-flöde från namn till telefonnummer eller hitta LinkedIn-profiler från namn i Python.

Konfigurera Python, Requests och din Datablist API-nyckel

I det här Python-exemplet använder jag paketet requests. Skapa en projektmapp, aktivera en virtuell miljö, installera Requests och skapa skriptfilen:

shell
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"

Skapa en Personal API Key i ditt Datablist-konto och använd den som DATABLIST_API_KEY. Åtkomst till REST API är en funktion i Growth-planen. Längre fram i guiden går jag igenom hur många credits en lyckad sökning använder.

Hitta telefonnummer med en komplett Python-funktion

Exemplet innehåller tre prospect-poster som du kan redigera. Varje post har ett beständigt prospect_id, ett namn, en offentlig LinkedIn-URL och den kontoansvariga som ska granska resultatet:

  • Florian Poullin på https://www.linkedin.com/in/florianpoullin/
  • Satya Nadella på https://www.linkedin.com/in/satyanadella/
  • Reid Hoffman på https://www.linkedin.com/in/reidhoffman/

Endast det beständiga ID:t och LinkedIn-URL:en behöver skickas till API:et. Namnet och den kontoansvariga stannar i din lokala källpost. Uppdelningen håller lookup-requesten liten samtidigt som den affärsinformation teamet behöver finns kvar när resultatet returneras.

Klistra in hela skriptet i find_phone_numbers.py:

python
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))

Kör filen med:

shell
python find_phone_numbers.py

Du kan även ladda ned Datablists underhållna synkrona Requests-exempel. Skriptet ovan följer samma enkla ordning: skicka in en task, vänta tills den är klar och hämta samtliga resultatsidor.

Skicka telefonuppslaget

List comprehension-uttrycket omvandlar varje prospect i källdatan till API:ets input-format. Ditt prospect_id blir inputId, medan linkedin_url blir data.profileUrl. Använd en offentlig personprofil med sökvägen linkedin.com/in/.... Sales Navigator-URL:er stöds inte av denna enrichment.

Funktionen genererar uniqueId och skriver ut det före POST-anropet. Requesten skickar värdet tillsammans med enrichment-ID:t waterfall-phone-finder, cache- inställningen och all input. En lyckad inskickning returnerar HTTP 202 Accepted och ett @id för tasken, medan bearbetningen fortsätter i bakgrunden.

API-dokumentationen för Waterfall Phone Finder listar aktuella inställningar, input-fält, output, credits och begränsningar.

För en prospect har request body följande struktur:

json
{
"enrichmentId": "waterfall-phone-finder",
"uniqueId": "generated-uuid",
"settings": {
"cacheAge": "30"
},
"inputs": [
{
"inputId": "prospect-florian-poullin",
"data": {
"profileUrl": "https://www.linkedin.com/in/florianpoullin/"
}
}
]
}

Den offentliga profil-URL:en används som input för sökningen. inputId är den join key som kopplar resultatet till namnet och den kontoansvariga i din källpost. Välj ett ID som är beständigt i ditt eget system och unikt inom tasken.

Vänta på bakgrundstasken

Requests-klienten blockerar lokalt medan den kontrollerar tasken var tredje sekund. Datablist-tasken fortsätter samtidigt att köras i bakgrunden. När statusen blir completed börjar funktionen hämta resultaten. Statusen failed eller stopped utlöser ett fel med task-ID:t så att du kan undersöka vad som hänt.

Hämta alla resultatsidor

Resultatanropet begär upp till 100 rader åt gången. Det fortsätter att hämta sidor tills nextCursor är null. Varje resultat innehåller sitt ursprungliga inputId, så att du kan mappa det till rätt prospect utan att förlita dig på svarens ordning.

Så hittar ett hanterat waterfall-flöde telefonnummer

I exemplet sätts cacheAge till "30". Datablist kontrollerar först om det finns ett tillgängligt resultat som är högst 30 dagar gammalt. Om ett sådant finns kan API:et återanvända det. Inställningen tillåter en cache-träff, men garanterar inte att en finns.

Om profilen fortfarande inte har gett något resultat testar det hanterade waterfall-flödet tillgängliga leverantörer av telefondata i tur och ordning. Om en leverantör inte returnerar något användbart nummer går posten vidare. När ett användbart nummer hittas stoppas sekvensen för den posten.

Waterfall-sökningen fortsätter efter ett tomt resultat och stoppas när ett telefonnummer hittas
Waterfall-sökningen fortsätter efter ett tomt resultat och stoppas när ett telefonnummer hittas

Därför fungerar waterfall bättre i flera länder och marknader

Datablist förlitar sig inte på en enda leverantör av telefondata. Leverantörerna använder olika datamängder, och deras täckning varierar mellan länder och marknader. När en leverantör saknar ett telefonnummer kan en annan hitta det. Datablist hanterar dessa leverantörer via samma API-integration.

För ett säljteam som bygger en ringlista för flera marknader innebär det att färre prospects faller bort när en enskild leverantör inte hittar något. Din Python-kod skickar en task och läser ett enda resultatformat, så du slipper bygga och underhålla en separat integration för varje leverantör.

Sätt cacheAge till "0" när ditt arbetsflöde uttryckligen kräver en helt ny sökning. Behåll "30" i exemplet så att ett tillgängligt cachelagrat resultat kan återanvändas.

Läs hela resultatet

Här är ett resultat för Florian Poullin. Telefonnumret är maskerat nedan.

json
{
"inputId": "prospect-florian-poullin",
"status": "success",
"outputs": {
"finderProvider": "wizleads",
"phoneNumber": "+33 • •• •• •• ••",
"phoneNumberCountry": "FR"
},
"creditsUsed": "500",
"error": null
}

phoneNumber innehåller det internationella numret när ett sådant är tillgängligt. Prefixet +33 och phoneNumberCountry: "FR" visar att det är ett franskt nummer.

finderProvider anger vilken finder som rapporterats för resultatet. Raden använde 500 credits, och error: null innebär att API:et inte returnerade något fel på radnivå.

Skapa en granskad ringlista för säljteamet

När phone_results är tillgängligt kan du skapa en lokal lista som säljteamet kan granska. Lägg till blocket nedan efter utskriften av resultatet i samma fil. Det återanvänder de befintliga resultaten och gör inget ytterligare API-anrop:

python
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))

Resultatindexet använder inputId som join key, så varje resultat förblir kopplat till sin källpost utan att vara beroende av listpositionen. API-payloaden innehåller varje prospects ID och profil-URL, medan den ursprungliga listan prospects behåller namnet och den kontoansvariga som behövs i ringlistan.

För Florians rad kopplar prospect-florian-poullin det returnerade resultatet till det ursprungliga name, linkedin_url och account_owner. Teamet hämtar telefonnumret och landskoden FR från result.outputs. Det fullständiga API-objektet, inklusive status, credits och eventuella fel, ligger kvar under result.

Loopen för ringlistan följer ordningen i prospects. Den kopierar varje prospect som ska tas med innan result läggs till. Därmed finns den ursprungliga källistan kvar för korrigeringar eller en annan uppföljningskanal.

En rad utan resultat, med fel eller utan telefonnummer ligger kvar oförändrad i listan prospects, men läggs inte till i call_list. Koden skapar en lokal ringlista som säljteamet kan granska.

Beräkna kostnaden för Waterfall Phone Finder API

Varje nytt, icke-cachelagrat telefonnummer som hittas av det förvalda hanterade waterfall-flödet kostar 500 credits. Ett godkänt cachelagrat resultat kostar 0 credits, och en sökning utan resultat kostar också 0 credits. Läs creditsUsed på varje returnerad rad för att se den faktiska kostnaden, i stället för att multiplicera varje inskickad profil med 500.

Använd följande formel för budgetering:

nya icke-cachelagrade telefonnummer som hittas × 500 credits

Fyrtio nya nummer kostar 20 000 credits. Hundra nya nummer kostar 50 000 credits. Med det nuvarande grundpriset för påfyllning i USD ger 20 dollar 20 000 credits, vilket innebär att 500 credits motsvarar 0,50 dollar. Growth-prenumerationen som ger åtkomst till REST API tillkommer separat. Se Datablists priser för aktuella planer och credit-paket.

Anta som planeringsexempel att 100 profiler ger 20 nya nummer, 5 godkända cachelagrade nummer och 75 sökningar utan träff. Den debiterbara mängden är de 20 nya numren, så sökningen använder 10 000 credits. Ringlistan kan innehålla alla 25 hittade nummer. Ange 20 i kalkylatorn, inte samtliga 100 input-poster eller alla 25 hittade nummer. Exemplet visar hur debiteringen beräknas, inte en förväntad träffsäkerhet.

Loading pricing…

Lös vanliga fel och återställ en befintlig task

  • DATABLIST_API_KEY saknas: skriptet stoppas innan någon request skickas. Exportera variabeln och kör filen igen.
  • API:et avvisar nyckeln: raise_for_status() visar HTTP-felet. Kopiera din Personal API Key igen och kontrollera att requesten skickar den i headern X-API-Key.
  • Profil-URL:en stöds inte: ersätt en tom, felaktig, företags- eller Sales Navigator-URL med en offentlig personprofil som använder sökvägen linkedin.com/in/....
  • Du har för få credits: kontrollera kontots saldo och tillgängliga credits innan du skickar in fler sökningar.
  • Tasken har status failed eller stopped: kontrollera felet, tillgängliga resultat och förbrukade credits innan du avgör vad som behöver köras igen.
  • En rad saknar resultat eller innehåller ett fel: behåll prospect-posten i källdatan för korrigering eller uppföljning via en annan kanal. Raden i sig förklarar inte vilken leverantör, geografi eller synlighetsinställning som orsakade utfallet.

Om POST-svaret går förlorat använder du det uniqueId som skrevs ut före inskickningen. Lista dina tasks innan du skickar in något igen. Ersätt your-api-key i följande request och leta sedan upp den task vars uniqueId matchar det utskrivna värdet:

shell
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"

Om tasken inte finns på första sidan följer du nextCursor i svaret med task-listan. Kopiera @id från den matchande tasken, ersätt TASK_ID nedan och kontrollera statusen eller hämta de befintliga resultaten:

shell
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"

Dokumentationen för task-API:et förklarar task-statusar, paginering av resultat och vad som händer vid avbrott.

Nästa steg

Nu har du en återanvändbar Requests-funktion för offentliga LinkedIn-profiler och en sammanslagning med beständiga ID:n som förbereder hittade telefonnummer för säljteamets granskning.

Ersätt de redigerbara exemplen med en mindre uppsättning kvalificerade prospects. Behåll deras beständiga ID:n och kontoansvariga, och granska sedan varje hittat nummer innan du skickar den färdiga listan vidare till teamets ringprocess. Börja med en liten batch så att du kan kontrollera ID-mappningen och de returnerade fälten. Om du behöver icke-blockerande parallellism kan du använda det underhållna async HTTPX-exemplet.