This commit is contained in:
2025-04-10 06:42:46 +00:00
parent e93d2615a8
commit fddc7539fd

View File

@@ -1537,41 +1537,52 @@ def process_contacts():
# Weitere Verarbeitung der Kontakte folgt hier ...
# ==================== LINKEDIN HELPER ====================
def search_linkedin_contact(company_name, website, position_query, crm_kurzform):
def search_linkedin_contacts(company_name, website, position_query, crm_kurzform, num_results=100):
"""
Sucht über SERPAPI einen einzelnen LinkedIn-Kontakt basierend auf der Positionsbezeichnung und der CRM-Kurzform des Unternehmens.
Es wird nur ein Treffer zurückgegeben, wenn der Titel auch die CRM-Kurzform (als Teilstring) enthält.
Sucht über SERPAPI mehrere LinkedIn-Kontakte basierend auf der Positionsbezeichnung
und der CRM-Kurzform des Unternehmens. Es werden alle Treffer zurückgegeben, bei denen
die CRM-Kurzform (als Teilstring) im Titel auftaucht.
Args:
company_name (str): Der Firmenname.
website (str): Die Website des Unternehmens.
position_query (str): Die zu suchende Positionsbezeichnung (z. B. "Serviceleiter").
crm_kurzform (str): Die manuell gepflegte Kurzform des Firmennamens.
num_results (int): Anzahl der abzurufenden Suchergebnisse (hier standardmäßig 100).
Returns:
dict oder None: Ein Dictionary mit den Kontaktdaten (Vorname, Nachname, Position, LinkedInURL) oder None, falls kein passender Kontakt gefunden wurde.
list: Eine Liste von Dictionaries mit den Kontaktdaten (Vorname, Nachname, Position, LinkedInURL)
oder eine leere Liste, wenn keine Treffer gefunden wurden.
"""
try:
with open("serpApiKey.txt", "r") as f:
serp_key = f.read().strip()
except Exception as e:
debug_print("Fehler beim Lesen des SerpAPI-Schlüssels: " + str(e))
return None
return []
query = f'site:linkedin.com/in "{position_query}" "{company_name}"'
params = {
"engine": "google",
"q": query,
"api_key": serp_key,
"hl": "de"
"hl": "de",
"num": num_results
}
# Logge die vollständige Such-URL
request_url = "https://serpapi.com/search?" + urlencode(params)
debug_print(f"Such-URL: {request_url}")
try:
response = requests.get("https://serpapi.com/search", params=params, timeout=10)
data = response.json()
contacts = []
if "organic_results" in data and len(data["organic_results"]) > 0:
for result in data["organic_results"]:
title = result.get("title", "")
if crm_kurzform.lower() in title.lower():
# Aufteilen des Titels in Namens- und Positionsbestandteile
if "" in title:
parts = title.split("")
elif "-" in title:
@@ -1589,22 +1600,22 @@ def search_linkedin_contact(company_name, website, position_query, crm_kurzform)
lastname = ""
linkedin_url = result.get("link", "")
debug_print(f"Gefundener Kontakt: {firstname} {lastname}, Position: {pos_part}")
return {
contacts.append({
"Firmenname": company_name,
"Website": website,
"Vorname": firstname,
"Nachname": lastname,
"Position": pos_part,
"LinkedInURL": linkedin_url
}
debug_print("Kein Treffer mit CRM-Kurzform in Titel gefunden.")
return None
})
if not contacts:
debug_print("Kein Treffer mit CRM-Kurzform in Titel gefunden.")
else:
debug_print("Keine organic_results für Query gefunden.")
return None
return contacts
except Exception as e:
debug_print(f"Fehler bei der SerpAPI-Suche: {e}")
return None
debug_print(f"Fehler bei der SERPAPI-Suche: {e}")
return []
def count_linkedin_contacts(company_name, website, position_query, crm_kurzform):
"""
@@ -1772,12 +1783,9 @@ def count_linkedin_contacts(company_name, website, position_query, crm_kurzform)
def process_contact_research():
"""
Sucht mithilfe der SerpAPI Kontakte für bestimmte Positionen für jedes Unternehmen.
Es werden zunächst die CRM-Daten (insbesondere CRM Kurzform in Spalte C) sowie Firma und Website aus dem Hauptblatt gelesen.
Die gefundenen Kontakte, welche den Filter (CRM Kurzform muss im Titel enthalten sein) erfüllen, werden im Kontakte-Blatt eingetragen.
Zusätzlich werden die Trefferzahlen (als Summen pro Position) in das Hauptblatt in den Spalten AI, AJ, AK, AL geschrieben
und ein Timestamp in Spalte AM gesetzt.
Sucht mithilfe der SERPAPI Kontakte für bestimmte Positionen für jedes Unternehmen.
Die gefundenen Kontakte werden im Kontakte-Blatt eingetragen pro Kategorie werden alle
Treffer (die den Filter (CRM-Kurzform muss im Titel enthalten sein) erfüllen) verarbeitet.
Im Kontakte-Blatt wird folgende Spaltenstruktur verwendet:
A: Firmenname
@@ -1791,8 +1799,6 @@ def process_contact_research():
I: E-Mail-Adresse
J: LinkedIn-Link
K: Timestamp
Detaillierte Debug-Ausgaben sorgen für Transparenz bei der Ausführung.
"""
debug_print("Starte Contact Research (Modus 6)...")
# Verbinde zum Hauptblatt
@@ -1802,20 +1808,20 @@ def process_contact_research():
main_sheet = sh.sheet1
data = main_sheet.get_all_values()
# Ermittle die letzte Zeile in Spalte AM (Spalte 39), in der ein Timestamp eingetragen wurde
col_am = main_sheet.col_values(39) # Spalte AM hat den Index 39 (A=1, ..., AM=39)
last_filled_row = 1 # Header-Zeile
# Ermittle die letzte Zeile in Spalte AM (Spalte 39) mit einem Timestamp
col_am = main_sheet.col_values(39)
last_filled_row = 1
for idx, cell in enumerate(col_am):
if cell.strip() != "":
last_filled_row = idx + 1
start_row = last_filled_row + 1
debug_print(f"Letzter Timestamp in Spalte AM wurde in Zeile {last_filled_row} gefunden. Starte Verarbeitung ab Zeile {start_row}.")
debug_print(f"Letzter Timestamp in Spalte AM in Zeile {last_filled_row}. Starte Verarbeitung ab Zeile {start_row}.")
if start_row > len(data):
debug_print("Keine neuen Zeilen zu verarbeiten, da Timestamp in Spalte AM bereits bis zum Ende vorhanden ist.")
debug_print("Keine neuen Zeilen zu verarbeiten, da Timestamp in Spalte AM bis zum Ende vorhanden ist.")
return
# Kontakte-Blatt öffnen oder erstellen
# Kontakte-Blatt öffnen oder erstellen (Header: A-K)
try:
contacts_sheet = sh.worksheet("Contacts")
except gspread.exceptions.WorksheetNotFound:
@@ -1825,7 +1831,7 @@ def process_contact_research():
contacts_sheet.update(values=[header], range_name="A1:K1")
debug_print("Neues Blatt 'Contacts' erstellt und Header eingetragen.")
# Verarbeite jede Zeile ab der ermittelten Startzeile
# Gehe alle Zeilen im Hauptblatt ab der Startzeile durch
for i in range(start_row, len(data) + 1):
row = data[i - 1]
company_name = row[1] if len(row) > 1 else ""
@@ -1840,16 +1846,16 @@ def process_contact_research():
for pos in positions:
count = count_linkedin_contacts(crm_kurzform, website, pos, crm_kurzform)
contact_counts[pos] = count
contact = search_linkedin_contact(crm_kurzform, website, pos, crm_kurzform)
if contact:
# Abfrage: Es sollen nun alle Treffer (bis zu 100) verarbeitet werden
contacts = search_linkedin_contacts(crm_kurzform, website, pos, crm_kurzform, num_results=100)
for contact in contacts:
firstname = contact.get("Vorname", "")
lastname = contact.get("Nachname", "")
gender_value = get_gender(firstname) if firstname else "unknown"
email = get_email_address(firstname, lastname, website)
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# Neue Reihenfolge:
# A: Firmenname, B: CRM Kurzform, C: Website, D: Geschlecht, E: Vorname, F: Nachname,
# G: Position, H: Suchbegriffskategorie, I: E-Mail-Adresse, J: LinkedIn-Link, K: Timestamp
# Spaltenanordnung: A: Firmenname, B: CRM Kurzform, C: Website, D: Geschlecht, E: Vorname,
# F: Nachname, G: Position, H: Suchbegriffskategorie, I: E-Mail-Adresse, J: LinkedIn-Link, K: Timestamp
contact_row = [
company_name,
crm_kurzform,
@@ -1865,13 +1871,10 @@ def process_contact_research():
]
try:
contacts_sheet.append_row(contact_row)
debug_print(f"Zeile {i}: Kontakt für Position '{pos}' in Contacts gespeichert: {contact_row}")
debug_print(f"Zeile {i}: Kontakt für '{pos}' gespeichert: {contact_row}")
except Exception as e:
debug_print(f"Zeile {i}: Fehler beim Speichern des Kontakts in Contacts: {e}")
else:
debug_print(f"Zeile {i}: Kein passender Kontakt für Position '{pos}' gefunden.")
# Aktualisiere Hauptblatt-Zeile mit Trefferzahlen und Timestamp
debug_print(f"Zeile {i}: Fehler beim Speichern des Kontakts für '{pos}': {e}")
# Aktualisiere Trefferzahlen und Timestamp im Hauptblatt
try:
main_sheet.update(values=[[str(contact_counts.get("Serviceleiter", 0))]], range_name=f"AI{i}")
main_sheet.update(values=[[str(contact_counts.get("IT-Leiter", 0))]], range_name=f"AJ{i}")