← back to Rentv Sheet Enrich

build_li_targets.py

56 lines

#!/usr/bin/env python3
"""Build next batch of LinkedIn(Contact) targets: REAL-named people missing LinkedIn,
with a plausible company, not already searched. ADD-only. Prints JSON [{name, company}]."""
import sys, os, re, json
sys.path.insert(0, os.path.dirname(__file__))
import lib, guards

GID = 3823360
TITLE = "Unique Contacts (all tabs)"
N = int(sys.argv[1]) if len(sys.argv) > 1 else 12

# company-suffix tokens that mean the "Contact Name" is really a firm name, not a person
_FIRM = {"holdings","holding","enterprise","enterprises","associates","partners","capital",
 "realty","properties","property","group","commercial","point","creek","bank","ventures",
 "development","developments","management","mgmt","advisors","advisor","investments","investment",
 "residential","communities","community","trust","fund","funds","equities","equity","corp",
 "corporation","company","companies","inc","llc","lp","co","of","the","real","estate","american",
 "national","first","global","financial","insurance","mortgage","lending","builders","construction"}
_BADCO = {"", "email", "(need email)", "need email", "n/a", "na", "none", "-"}

def norm(s): return re.sub(r'[^a-z0-9]', '', (s or '').lower())

searched = set()
p = os.path.join(os.path.dirname(__file__), "data/searched_names.txt")
if os.path.exists(p):
    for ln in open(p):
        if ln.strip(): searched.add(norm(ln))

def firm_like_name(name):
    toks = [re.sub(r'[^a-z]', '', t.lower()) for t in re.split(r"[\s,]+", name) if t]
    return any(t in _FIRM for t in toks)

def has_digit(s): return bool(re.search(r'\d', s))

tok = lib.access_token()
rows = lib.read_tab(tok, TITLE)
hdr = [h.strip() for h in rows[0]]
c = {v: i for i, v in enumerate(hdr) if v}
NAME, CO, LIC = c["Contact Name"], c["Company/Venue"], c["LinkedIn (Contact)"]
def g(r, i): return (r[i].strip() if i < len(r) else "")

targets = []; scanned = 0
for r in rows[1:]:
    name = g(r, NAME); co = g(r, CO); li = g(r, LIC)
    if not name or li: continue
    if guards.bad_name(name): continue
    if has_digit(name): continue
    if firm_like_name(name): continue
    if co.strip().lower() in _BADCO: continue
    if norm(name) in searched: continue
    scanned += 1
    targets.append({"name": name, "company": co})
    if len(targets) >= N: break

print(json.dumps(targets, indent=1))