Skip to content
Back to skills

Scrape Leads

ASecurity

Scrape leads using Apify (`code_crafter/leads-finder`), verify their relevance (industry match > 80%), and save them to a Google Sheet. For large scrapes (1000+ leads), use parallel scraping for 3-5x faster performance.

  • 43 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added May 30, 2026
developmentpythongobashapiperformance

Works with

  • api

Security analysis

A100/100

Scanned May 30, 2026

npx -y skills add ComeOnOliver/skillshub --skill scrape-leads --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Scrape Leads?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Scrape Leads
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/comeonoliver-scrape-leads/badge)](https://www.skillsdirectory.com/skills/comeonoliver-scrape-leads)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
# Lead Scraping & Verification

## Goal
Scrape leads using Apify (`code_crafter/leads-finder`), verify their relevance (industry match > 80%), and save them to a Google Sheet. For large scrapes (1000+ leads), use parallel scraping for 3-5x faster performance.

## Inputs
- **Industry**: The target industry (e.g., "Plumbers", "Software Agencies").
- **Location**: The target location (e.g., "New York", "United States").
- **Total Count**: The total number of leads desired.

## Tools/Scripts
- Script: `execution/scrape_apify.py` (single scrape, for <1000 leads)
- Script: `execution/scrape_apify_parallel.py` (parallel scraping, for 1000+ leads)
- Script: `execution/update_sheet.py` (batch sheet updates, optimized for large datasets)
- Dependencies: Apify API Token, Google Service Account Credentials

## Process

### Small Scrapes (<1000 leads)
1. **Test Scrape**
   - Run `execution/scrape_apify.py` with `max_items=25` and `--no-email-filter`.
   - Output: `.tmp/test_leads.json` (temporary file).

2. **Verification**
   - Agent (You) reads `.tmp/test_leads.json`.
   - Check if at least 20/25 (80%) leads match the **Industry**.
   - **Decision**:
     - **Pass**: Proceed to step 3.
     - **Fail**: Stop. Ask user to refine **Industry** or **Location** keywords.

3. **Full Scrape**
   - Run `execution/scrape_apify.py` with full **Total Count** and `--no-email-filter`.
   - Output: `.tmp/leads_[timestamp].json` (temporary file).

4. **[OPTIONAL] LLM Classification for Harder Niches**
   - **When to use**: For complex distinctions (e.g., "product SaaS vs agencies")
   - **Command**:
     ```bash
     python3 execution/classify_leads_llm.py .tmp/leads_[timestamp].json \
       --classification_type product_saas \
       --output .tmp/classified_leads.json
     ```
   - **Performance**: ~2 minutes for 3,000 leads
   - See [classify_leads_llm.md](classify_leads_llm.md) for details

5. **Upload to Google Sheet** (DELIVERABLE)
   - Run `execution/update_sheet.py` with the final JSON file (classified or original).
   - **Output**: Google Sheet URL (this is the actual deliverable the user receives).

6. **Enrich Missing Emails**
   - Run `execution/enrich_emails.py` with the Google Sheet URL.
   - Script auto-detects dataset size and uses appropriate API strategy.
   - **Output**: Updated Google Sheet URL (final deliverable with enriched emails).

### Large Scrapes (1000+ leads) - FASTER with Parallel Processing
1. **Test Scrape** (same as above)
   - Run `execution/scrape_apify.py` with `max_items=25` and `--no-email-filter`.
   - Verify industry match > 80%.

2. **Parallel Full Scrape**
   - Run `execution/scrape_apify_parallel.py` with:
     - `--total_count` (e.g., 4000)
     - `--location` (e.g., "United States", "EU", "UK", "Canada", "Australia")
     - `--strategy regions` (auto-detects based on location)
     - `--no-email-filter` (scrape without email requirement, enrich after)
   - **Geographic Partitioning (Cost-Neutral)**:
     - **Auto-detects region** based on location:
       - **United States**: 4-way (Northeast, Southeast, Midwest, West)
       - **EU/Europe**: 4-way (Western, Southern, Northern, Eastern)
       - **UK**: 4-way (SE England, N England, Scotland/Wales, SW England)
       - **Canada**: 4-way (Ontario, Quebec, West, Atlantic)
       - **Australia**: 4-way (NSW, VIC/TAS, QLD, WA/SA)
     - **Alternative strategies**:
       - `--strategy metros`: 8-way US metro areas
       - `--strategy apac`: 8-way Asia-Pacific split
       - `--strategy global`: 8-way worldwide continental split
     - **Custom**: Comma-separated cities/states (e.g., `--location "London,Paris,Berlin,Madrid"`)
   - **Cost**: SAME as sequential (4 partitions × 1000 = 4000 total leads)
   - **Automatic Deduplication**: Handles leads appearing in multiple regions
   - Output: `.tmp/leads_[timestamp].json` (deduplicated, temporary file).
   - **Time Savings**: 3-4x faster than sequential, no extra cost.

3. **[OPTIONAL] LLM Classification for Harder Niches**
   - **When to use**: For complex distinctions that keywords can't capture:
     - ✅ "Product SaaS vs IT consulting agencies" (use LLM)
     - ✅ "High-ticket vs low-ticket businesses" (use LLM)
     - ✅ "Subscription vs one-time payment models" (use LLM)
     - ❌ "Dentists" or "Realtors" (simple keyword matching works)
   - **Command**:
     ```bash
     python3 execution/classify_leads_llm.py .tmp/leads_[timestamp].json \
       --classification_type product_saas \
       --output .tmp/classified_leads.json
     ```
   - **Performance**: ~2 minutes for 3,000 leads, ~$0.30 per 1,000 leads
   - **Default behavior**: Includes "unclear" classifications (medium confidence)
   - **Output**: `.tmp/classified_leads.json` (use this instead of original file for next step)
   - See [classify_leads_llm.md](classify_leads_llm.md) for full details

4. **Upload to Google Sheet** (DELIVERABLE)
   - Run `execution/update_sheet.py` with the final JSON file (classified or original).
   - Script automatically uses chunked batch updates for datasets >1000 rows.
   - **Output**: Google Sheet URL (this is the actual deliverable the user receives).

5. **Enrich Missing Emails** (ALWAYS USE BULK API)
   - **IMPORTANT**: Always run `execution/enrich_emails.py` in the foreground and wait for completion before notifying the user.
   - Run: `python3 execution/enrich_emails.py <SHEET_URL>`
   - **Bulk API Strategy** (200+ rows, PREFERRED):
     - Creates a single AnyMailFinder bulk job for all missing emails
     - Processes ~1000 rows in 5 minutes (much faster than individual calls)
     - Automatically polls until complete
     - **Agent must wait** until enrichment finishes and sheet is updated
   - **Concurrent API Fallback** (<200 rows or if bulk fails):
     - Makes up to 20 concurrent individual API calls
     - Automatically used if bulk API fails
   - **Output**: Updated Google Sheet URL (final deliverable with enriched emails).
   - **Workflow**: DO NOT notify user until enrichment completes and sheet is updated.

## Outputs (Deliverables)
**The ONLY deliverable is the Google Sheet URL.** This sheet contains all verified leads with company info, contact details, etc.

**Important**: Local JSON files (`.tmp/test_leads.json`, `.tmp/leads_*.json`, `.tmp/classified_leads.json`) are temporary intermediates used for processing. They are NOT deliverables and should never be presented to the user as final outputs.

## Edge Cases
- **No leads found**: Apify returns empty list. -> Ask user to broaden search.
- **API Error**: Apify or Google API fails. -> Check credentials in `.env`.
- **Low quality classifications**: If >80% classified as "unclear", consider improving scrape keywords or using custom classification prompt.

## Error Handling
- **Authentication Error**: Ensure `APIFY_API_TOKEN` and `GOOGLE_APPLICATION_CREDENTIALS` are set.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…