@anysiteio/agent-skills 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/.claude-plugin/marketplace.json +113 -0
  2. package/.claude-plugin/plugin.json +45 -0
  3. package/LICENSE +21 -0
  4. package/README.md +221 -0
  5. package/bin/install.js +55 -0
  6. package/package.json +45 -0
  7. package/skills/anysite-audience-analysis/SKILL.md +273 -0
  8. package/skills/anysite-audience-analysis/references/PLATFORM_COVERAGE.md +53 -0
  9. package/skills/anysite-audience-analysis/references/TOOL_MAPPING.md +27 -0
  10. package/skills/anysite-brand-reputation/SKILL.md +373 -0
  11. package/skills/anysite-brand-reputation/references/MONITORING_GUIDE.md +84 -0
  12. package/skills/anysite-competitor-analyzer/SKILL.md +847 -0
  13. package/skills/anysite-competitor-intelligence/SKILL.md +642 -0
  14. package/skills/anysite-competitor-intelligence/references/ANALYSIS_PATTERNS.md +97 -0
  15. package/skills/anysite-content-analytics/SKILL.md +298 -0
  16. package/skills/anysite-content-analytics/references/METRICS_GUIDE.md +63 -0
  17. package/skills/anysite-influencer-discovery/SKILL.md +398 -0
  18. package/skills/anysite-influencer-discovery/references/DISCOVERY_CRITERIA.md +50 -0
  19. package/skills/anysite-lead-generation/SKILL.md +1022 -0
  20. package/skills/anysite-lead-generation/references/LINKEDIN_STRATEGIES.md +739 -0
  21. package/skills/anysite-lead-generation/references/WEB_SCRAPING.md +910 -0
  22. package/skills/anysite-market-research/SKILL.md +379 -0
  23. package/skills/anysite-market-research/references/RESEARCH_METHODS.md +65 -0
  24. package/skills/anysite-person-analyzer/SKILL.md +604 -0
  25. package/skills/anysite-trend-analysis/SKILL.md +310 -0
  26. package/skills/anysite-trend-analysis/references/SOCIAL_MONITORING.md +46 -0
  27. package/skills/anysite-vc-analyst/SKILL.md +269 -0
@@ -0,0 +1,910 @@
1
+ # Web Scraping for Contact Extraction
2
+
3
+ Strategies and techniques for extracting contact information from company websites using anysite MCP.
4
+
5
+ ## Overview
6
+
7
+ Web scraping complements LinkedIn lead generation by:
8
+ - Finding contacts not active on LinkedIn
9
+ - Discovering phone numbers and addresses
10
+ - Verifying email addresses
11
+ - Accessing information from company directories
12
+ - Getting regional office contacts
13
+
14
+ ## Contact Extraction Tools
15
+
16
+ ### parse_webpage
17
+
18
+ Primary tool for extracting contacts from web pages.
19
+
20
+ **Basic Usage**:
21
+ ```
22
+ Tool: mcp__anysite__parse_webpage
23
+ Parameters:
24
+ - url: "https://company.com/contact"
25
+ - extract_contacts: true
26
+ - strip_all_tags: true
27
+ - only_main_content: true
28
+ ```
29
+
30
+ **Returns**:
31
+ - Emails: All email addresses found
32
+ - Phones: Phone numbers in various formats
33
+ - Social links: LinkedIn, Twitter, Facebook, Instagram
34
+ - Content: Page text for additional parsing
35
+
36
+ **Best Practices**:
37
+ - Set `extract_contacts: true` to enable contact extraction
38
+ - Use `only_main_content: true` to avoid footer/header noise
39
+ - Try multiple page variations (/contact, /about, /team)
40
+
41
+ ### get_sitemap
42
+
43
+ Discover all pages on a website to find contact information.
44
+
45
+ **Basic Usage**:
46
+ ```
47
+ Tool: mcp__anysite__get_sitemap
48
+ Parameters:
49
+ - url: "https://company.com"
50
+ - count: 100
51
+ ```
52
+
53
+ **Returns**:
54
+ - List of URLs from sitemap.xml
55
+ - Typically includes all public pages
56
+ - Useful for finding hidden contact/team pages
57
+
58
+ **Best Practices**:
59
+ - Start with count=100 to get comprehensive coverage
60
+ - Filter results for relevant pages (contact, team, about, leadership)
61
+ - Parse identified pages with parse_webpage
62
+
63
+ ## Common Page Patterns
64
+
65
+ ### Contact Pages
66
+
67
+ **Standard URLs**:
68
+ ```
69
+ /contact
70
+ /contact-us
71
+ /get-in-touch
72
+ /reach-us
73
+ /contact-information
74
+ /locations
75
+ ```
76
+
77
+ **Parsing Strategy**:
78
+ ```
79
+ 1. Try /contact first (most common)
80
+ 2. If 404, try /contact-us
81
+ 3. Check sitemap for contact-related URLs
82
+ 4. Look for "Contact" link in navigation
83
+ ```
84
+
85
+ **Example**:
86
+ ```
87
+ parse_webpage("https://company.com/contact", extract_contacts=true)
88
+
89
+ Expected data:
90
+ - General company email (info@, contact@, hello@)
91
+ - Department emails (sales@, support@, careers@)
92
+ - Phone numbers (often main line)
93
+ - Physical address
94
+ - Social media links
95
+ ```
96
+
97
+ ### About Pages
98
+
99
+ **Standard URLs**:
100
+ ```
101
+ /about
102
+ /about-us
103
+ /who-we-are
104
+ /company
105
+ /our-story
106
+ ```
107
+
108
+ **Parsing Strategy**:
109
+ ```
110
+ 1. Often contains leadership team contacts
111
+ 2. May have founder/CEO email
112
+ 3. Usually has company description and values
113
+ 4. Sometimes includes team photos with names
114
+ ```
115
+
116
+ **Example**:
117
+ ```
118
+ parse_webpage("https://company.com/about", extract_contacts=true)
119
+
120
+ Expected data:
121
+ - Leadership emails
122
+ - Company phone
123
+ - Headquarters address
124
+ - Founder/CEO information
125
+ ```
126
+
127
+ ### Team/People Pages
128
+
129
+ **Standard URLs**:
130
+ ```
131
+ /team
132
+ /our-team
133
+ /people
134
+ /leadership
135
+ /about/team
136
+ /company/team
137
+ /meet-the-team
138
+ ```
139
+
140
+ **Parsing Strategy**:
141
+ ```
142
+ 1. Best source for individual contacts
143
+ 2. Often lists names with titles
144
+ 3. May include email addresses
145
+ 4. Sometimes has LinkedIn profile links
146
+ ```
147
+
148
+ **Example**:
149
+ ```
150
+ parse_webpage("https://company.com/team", extract_contacts=true)
151
+
152
+ Expected data:
153
+ - Individual names and titles
154
+ - Personal email addresses (name@company.com)
155
+ - LinkedIn profile links
156
+ - Role descriptions
157
+ ```
158
+
159
+ ### Locations/Offices Pages
160
+
161
+ **Standard URLs**:
162
+ ```
163
+ /locations
164
+ /offices
165
+ /contact/locations
166
+ /our-offices
167
+ /global-offices
168
+ ```
169
+
170
+ **Parsing Strategy**:
171
+ ```
172
+ 1. Find regional office contacts
173
+ 2. Get location-specific phone numbers
174
+ 3. Extract local addresses
175
+ 4. Identify office managers
176
+ ```
177
+
178
+ **Example**:
179
+ ```
180
+ parse_webpage("https://company.com/locations", extract_contacts=true)
181
+
182
+ Expected data:
183
+ - Office-specific emails
184
+ - Local phone numbers
185
+ - Regional addresses
186
+ - Office manager contacts
187
+ ```
188
+
189
+ ## Email Pattern Recognition
190
+
191
+ ### Common Email Formats
192
+
193
+ **Individual Emails**:
194
+ ```
195
+ first.last@company.com (Most common)
196
+ first@company.com (Small companies)
197
+ flast@company.com (Medium companies)
198
+ firstl@company.com (Larger companies)
199
+ first_last@company.com (Underscore variant)
200
+ last.first@company.com (Reverse order)
201
+ ```
202
+
203
+ **Department Emails**:
204
+ ```
205
+ sales@company.com
206
+ info@company.com
207
+ contact@company.com
208
+ hello@company.com
209
+ support@company.com
210
+ careers@company.com
211
+ press@company.com
212
+ marketing@company.com
213
+ ```
214
+
215
+ **Pattern Detection**:
216
+ ```
217
+ 1. Extract all emails from page
218
+ 2. Identify individual vs. department emails
219
+ 3. Detect naming pattern from individual emails
220
+ 4. Apply pattern to LinkedIn prospects
221
+ 5. Validate before using
222
+ ```
223
+
224
+ ### Email Validation
225
+
226
+ **Format Validation**:
227
+ ```
228
+ Regex pattern: ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
229
+
230
+ Check:
231
+ - Contains @ symbol
232
+ - Has domain extension
233
+ - No invalid characters
234
+ - Proper domain format
235
+ ```
236
+
237
+ **Domain Validation**:
238
+ ```
239
+ 1. Extract domain from email
240
+ 2. Verify domain matches company website
241
+ 3. Check for common typos (.con instead of .com)
242
+ 4. Ensure professional domain (not gmail, yahoo, etc. for B2B)
243
+ ```
244
+
245
+ **Deliverability Validation** (external tool required):
246
+ ```
247
+ Use email verification services:
248
+ - ZeroBounce
249
+ - NeverBounce
250
+ - Hunter.io
251
+ - EmailListVerify
252
+
253
+ Check:
254
+ - Mailbox exists
255
+ - Domain has MX records
256
+ - Not a catch-all
257
+ - Not a disposable email
258
+ ```
259
+
260
+ ## Phone Number Extraction
261
+
262
+ ### Phone Number Patterns
263
+
264
+ **US/Canada Formats**:
265
+ ```
266
+ (415) 555-1234
267
+ 415-555-1234
268
+ 415.555.1234
269
+ +1 415 555 1234
270
+ 1-415-555-1234
271
+ ```
272
+
273
+ **International Formats**:
274
+ ```
275
+ +44 20 7123 4567 (UK)
276
+ +33 1 23 45 67 89 (France)
277
+ +49 30 123456 (Germany)
278
+ +61 2 1234 5678 (Australia)
279
+ ```
280
+
281
+ **Parsing Strategy**:
282
+ ```
283
+ 1. Look for common format patterns
284
+ 2. Extract country code (+1, +44, etc.)
285
+ 3. Identify area/city code
286
+ 4. Get main number
287
+ 5. Check for extension
288
+ ```
289
+
290
+ **Normalization**:
291
+ ```
292
+ Input: "(415) 555-1234 ext. 123"
293
+ Normalized: +14155551234
294
+ Extension: 123
295
+ Display: +1 (415) 555-1234 x123
296
+ ```
297
+
298
+ ### Phone Number Context
299
+
300
+ **Labels to Look For**:
301
+ ```
302
+ Main: General company line
303
+ Sales: Sales team direct line
304
+ Support: Customer support
305
+ Direct: Individual's direct line
306
+ Mobile: Mobile/cell phone
307
+ Toll-free: 800/888 numbers
308
+ Fax: Fax number (avoid using)
309
+ ```
310
+
311
+ **Example**:
312
+ ```
313
+ Page content:
314
+ "Sales: (415) 555-SALE
315
+ Support: (415) 555-HELP
316
+ Main Office: (415) 555-1234"
317
+
318
+ Extracted:
319
+ - sales_phone: +14155557253
320
+ - support_phone: +14155554357
321
+ - main_phone: +14155551234
322
+ ```
323
+
324
+ ## Multi-Page Scraping Workflows
325
+
326
+ ### Workflow 1: Comprehensive Company Contact Extraction
327
+
328
+ **Goal**: Extract all available contact information from a company website
329
+
330
+ **Steps**:
331
+
332
+ 1. **Get sitemap**
333
+ ```
334
+ get_sitemap("https://company.com", count=100)
335
+ ```
336
+
337
+ 2. **Filter for relevant pages**
338
+ ```
339
+ Filter sitemap results for:
340
+ - URLs containing: contact, about, team, location, office
341
+ - Exclude: blog, news, privacy, terms
342
+ ```
343
+
344
+ 3. **Parse each relevant page**
345
+ ```
346
+ For each filtered URL:
347
+ parse_webpage(url, extract_contacts=true)
348
+ ```
349
+
350
+ 4. **Consolidate and deduplicate**
351
+ ```
352
+ - Combine all emails found
353
+ - Remove duplicates
354
+ - Group by type (sales, support, etc.)
355
+ - Combine all phone numbers
356
+ - Match to departments
357
+ ```
358
+
359
+ 5. **Enrich with LinkedIn**
360
+ ```
361
+ For team member names found:
362
+ search_linkedin_users(first_name, last_name, company_keywords)
363
+ get_linkedin_profile(user)
364
+ ```
365
+
366
+ **Expected Output**:
367
+ - 5-20 email addresses
368
+ - 3-10 phone numbers
369
+ - 10-50 team member names
370
+ - Social media profiles
371
+ - All office locations
372
+
373
+ ### Workflow 2: Team Directory Scraping
374
+
375
+ **Goal**: Build contact list of entire team from website directory
376
+
377
+ **Steps**:
378
+
379
+ 1. **Find team page**
380
+ ```
381
+ Try common patterns:
382
+ - parse_webpage("https://company.com/team")
383
+ - parse_webpage("https://company.com/about/team")
384
+ - parse_webpage("https://company.com/people")
385
+
386
+ Or use sitemap:
387
+ - get_sitemap("https://company.com", count=100)
388
+ - Filter for "team" or "people"
389
+ ```
390
+
391
+ 2. **Extract team members**
392
+ ```
393
+ parse_webpage(team_url, extract_contacts=true)
394
+
395
+ Look for patterns:
396
+ - Name + Title combinations
397
+ - Email addresses
398
+ - LinkedIn profile links
399
+ - Headshot images with alt text containing names
400
+ ```
401
+
402
+ 3. **Parse individual profiles** (if available)
403
+ ```
404
+ Some team pages link to individual profiles:
405
+ - /team/john-smith
406
+ - /people/jane-doe
407
+
408
+ parse_webpage(individual_url, extract_contacts=true)
409
+ → Often has direct email, phone
410
+ ```
411
+
412
+ 4. **Match to LinkedIn**
413
+ ```
414
+ For each team member name:
415
+ search_linkedin_users(
416
+ first_name=<first>,
417
+ last_name=<last>,
418
+ company_keywords=<company>
419
+ )
420
+ ```
421
+
422
+ 5. **Construct email addresses**
423
+ ```
424
+ If email pattern detected from some team members:
425
+ - Apply pattern to all team members
426
+ - Example: john.doe@company.com → jane.smith@company.com
427
+ ```
428
+
429
+ **Expected Output**:
430
+ - Complete team roster
431
+ - 40-60% email coverage (direct or inferred)
432
+ - LinkedIn profiles for 70-80% of team
433
+ - Titles and roles for all members
434
+
435
+ ### Workflow 3: Multi-Location Contact Extraction
436
+
437
+ **Goal**: Get contacts for all office locations
438
+
439
+ **Steps**:
440
+
441
+ 1. **Find locations page**
442
+ ```
443
+ parse_webpage("https://company.com/locations", extract_contacts=true)
444
+ ```
445
+
446
+ 2. **Extract location information**
447
+ ```
448
+ For each location found:
449
+ - Office name/city
450
+ - Full address
451
+ - Phone number
452
+ - Regional email
453
+ - Office manager name
454
+ ```
455
+
456
+ 3. **Parse location-specific pages** (if available)
457
+ ```
458
+ Some companies have per-location pages:
459
+ - /locations/san-francisco
460
+ - /offices/new-york
461
+
462
+ parse_webpage(location_url, extract_contacts=true)
463
+ ```
464
+
465
+ 4. **Find office leaders**
466
+ ```
467
+ For each location:
468
+ search_linkedin_users(
469
+ title="Office Manager OR General Manager",
470
+ company_keywords=<company>,
471
+ location=<office_city>
472
+ )
473
+ ```
474
+
475
+ 5. **Build location contact sheet**
476
+ ```
477
+ Spreadsheet with:
478
+ - Location name
479
+ - Address
480
+ - Main phone
481
+ - Local email
482
+ - Office manager name + LinkedIn
483
+ - Office manager email
484
+ ```
485
+
486
+ **Expected Output**:
487
+ - Contact info for all office locations
488
+ - Regional phone numbers
489
+ - Office manager contacts
490
+ - Location-specific emails
491
+
492
+ ## Advanced Extraction Techniques
493
+
494
+ ### HTML Structure Analysis
495
+
496
+ **Common Team Page Structures**:
497
+
498
+ **Grid Layout**:
499
+ ```html
500
+ <div class="team-grid">
501
+ <div class="team-member">
502
+ <img src="john.jpg" alt="John Smith">
503
+ <h3>John Smith</h3>
504
+ <p class="title">VP Sales</p>
505
+ <a href="mailto:john@company.com">Email</a>
506
+ </div>
507
+ ...
508
+ </div>
509
+ ```
510
+
511
+ **List Layout**:
512
+ ```html
513
+ <ul class="team-list">
514
+ <li>
515
+ <strong>Jane Doe</strong> - CEO
516
+ <a href="https://linkedin.com/in/janedoe">LinkedIn</a>
517
+ <a href="mailto:jane@company.com">jane@company.com</a>
518
+ </li>
519
+ ...
520
+ </ul>
521
+ ```
522
+
523
+ **Table Layout**:
524
+ ```html
525
+ <table class="team-directory">
526
+ <tr>
527
+ <td>Bob Johnson</td>
528
+ <td>CTO</td>
529
+ <td>bob.johnson@company.com</td>
530
+ <td>(415) 555-1234</td>
531
+ </tr>
532
+ ...
533
+ </table>
534
+ ```
535
+
536
+ **Parsing Strategy**:
537
+ - Look for repeating patterns
538
+ - Identify CSS classes for team members
539
+ - Extract data from consistent positions
540
+ - Handle variations in structure
541
+
542
+ ### Contact Form Scraping
543
+
544
+ **Contact Form Analysis**:
545
+ ```
546
+ Many contact pages have forms instead of direct emails
547
+
548
+ Indicators:
549
+ - Form fields: name, email, message
550
+ - Submit button
551
+ - "Get in touch" or "Send us a message"
552
+
553
+ Information to extract:
554
+ - Department options (dropdown values)
555
+ - Office location options
556
+ - Inquiry type options (sales, support, etc.)
557
+ ```
558
+
559
+ **Alternative Approaches**:
560
+ 1. **Check page source** for hidden emails
561
+ ```
562
+ Sometimes email is in HTML comments
563
+ Or in JavaScript that loads after form submission
564
+ ```
565
+
566
+ 2. **Try related pages**
567
+ ```
568
+ If /contact has only a form:
569
+ - Try /about for team emails
570
+ - Check press/media page for PR contact
571
+ - Look for careers page (jobs@)
572
+ ```
573
+
574
+ 3. **Use department-specific pages**
575
+ ```
576
+ /sales might have sales team contacts
577
+ /support might have support emails
578
+ /media might have press contact
579
+ ```
580
+
581
+ ### Social Link Extraction
582
+
583
+ **Social Profiles to Extract**:
584
+ ```
585
+ LinkedIn: linkedin.com/company/[company]
586
+ Twitter: twitter.com/[company]
587
+ Facebook: facebook.com/[company]
588
+ Instagram: instagram.com/[company]
589
+ YouTube: youtube.com/[company]
590
+ ```
591
+
592
+ **Parsing Strategy**:
593
+ ```
594
+ parse_webpage(url, extract_contacts=true) returns social links
595
+
596
+ Use social profiles to:
597
+ 1. Verify company information
598
+ 2. Find additional team members
599
+ 3. Get posting/engagement insights
600
+ 4. Identify brand voice
601
+ ```
602
+
603
+ **Example**:
604
+ ```
605
+ Social links found:
606
+ - LinkedIn: linkedin.com/company/techcorp
607
+ - Twitter: twitter.com/techcorp
608
+
609
+ Next steps:
610
+ get_linkedin_company("techcorp") → Company details
611
+ get_twitter_user("techcorp") → Twitter profile
612
+ ```
613
+
614
+ ## Error Handling & Troubleshooting
615
+
616
+ ### Common Issues
617
+
618
+ #### 1. No Contacts Found
619
+
620
+ **Symptoms**: parse_webpage returns no emails or phones
621
+
622
+ **Causes**:
623
+ - JavaScript-rendered content (page loads dynamically)
624
+ - Contact form instead of direct contacts
625
+ - Contacts hidden in images or PDFs
626
+ - Privacy-focused website design
627
+
628
+ **Solutions**:
629
+ ```
630
+ 1. Try alternative pages:
631
+ - /about instead of /contact
632
+ - /team instead of /contact-us
633
+ - /leadership for executive contacts
634
+
635
+ 2. Check page source manually to verify data exists
636
+
637
+ 3. Look for PDF downloads:
638
+ - Company brochure might have contacts
639
+ - Annual report might list executives
640
+
641
+ 4. Use LinkedIn as primary source instead
642
+ ```
643
+
644
+ #### 2. Malformed Contact Data
645
+
646
+ **Symptoms**: Emails or phones in wrong format
647
+
648
+ **Causes**:
649
+ - Email obfuscation (user[at]company.com)
650
+ - Phone with extra text (Call us: 555-1234)
651
+ - HTML entities (&amp; instead of &)
652
+
653
+ **Solutions**:
654
+ ```
655
+ Post-processing:
656
+ - Replace [at] with @
657
+ - Replace [dot] with .
658
+ - Strip "Call", "Phone:", "Email:" prefixes
659
+ - Decode HTML entities
660
+ - Normalize phone format
661
+ ```
662
+
663
+ **Example**:
664
+ ```
665
+ Raw: "Email us at hello[at]company[dot]com"
666
+ Cleaned: "hello@company.com"
667
+
668
+ Raw: "Phone: (415) 555-1234 ext 123"
669
+ Cleaned: "+14155551234"
670
+ Extension: "123"
671
+ ```
672
+
673
+ #### 3. Too Many Irrelevant Results
674
+
675
+ **Symptoms**: Extracted emails include spam, marketing, unrelated domains
676
+
677
+ **Causes**:
678
+ - Partner/sponsor logos with emails
679
+ - Advertisement blocks
680
+ - Footer links to other sites
681
+
682
+ **Solutions**:
683
+ ```
684
+ Filtering strategy:
685
+ 1. only_main_content: true (remove footer/header)
686
+ 2. Verify email domain matches company domain
687
+ 3. Exclude common spam patterns (noreply@, donotreply@)
688
+ 4. Filter out tracking/marketing emails
689
+ ```
690
+
691
+ **Example Filter**:
692
+ ```
693
+ Keep:
694
+ - john@company.com ✓
695
+ - sales@company.com ✓
696
+
697
+ Discard:
698
+ - noreply@company.com ✗
699
+ - partner@otherdomain.com ✗
700
+ - ads@advertising-network.com ✗
701
+ ```
702
+
703
+ #### 4. Rate Limiting or Blocking
704
+
705
+ **Symptoms**: Requests fail or return errors
706
+
707
+ **Causes**:
708
+ - Website blocks scraping/bots
709
+ - Rate limiting (too many requests too fast)
710
+ - IP-based blocking
711
+
712
+ **Solutions**:
713
+ ```
714
+ 1. Increase request_timeout parameter
715
+ 2. Add delays between requests (30-60 seconds)
716
+ 3. Rotate user agents (handled by MCP server)
717
+ 4. Scrape during off-peak hours
718
+ 5. Use smaller batch sizes
719
+ ```
720
+
721
+ **Best Practices**:
722
+ ```
723
+ - Wait 30-60 seconds between parse_webpage calls
724
+ - Process 5-10 websites per batch
725
+ - Don't scrape same site multiple times rapidly
726
+ - Respect robots.txt
727
+ ```
728
+
729
+ ### Validation Workflows
730
+
731
+ **Email Validation Checklist**:
732
+ ```
733
+ ✓ Contains @ symbol
734
+ ✓ Has valid domain extension
735
+ ✓ Domain matches company website
736
+ ✓ Not a role-based email (noreply, admin, etc.)
737
+ ✓ Proper format (no spaces, special chars)
738
+ ✓ Not a personal email (gmail, yahoo, etc. for B2B)
739
+ ```
740
+
741
+ **Phone Validation Checklist**:
742
+ ```
743
+ ✓ Contains correct number of digits for region
744
+ ✓ Has valid area/city code
745
+ ✓ Not a fax number
746
+ ✓ Not a toll-free number (for direct contact)
747
+ ✓ Matches expected country code
748
+ ✓ Includes extension if available
749
+ ```
750
+
751
+ **Data Quality Scoring**:
752
+ ```
753
+ High Quality (90-100):
754
+ - Direct email (first.last@)
755
+ - Direct phone with extension
756
+ - Verified through LinkedIn match
757
+
758
+ Medium Quality (70-89):
759
+ - Department email (sales@)
760
+ - Main office phone
761
+ - Found on official website
762
+
763
+ Low Quality (50-69):
764
+ - Generic contact form
765
+ - General inquiry email (info@)
766
+ - No phone available
767
+
768
+ Poor Quality (<50):
769
+ - Inferred/guessed email
770
+ - No contact method found
771
+ ```
772
+
773
+ ## Integration with LinkedIn Data
774
+
775
+ ### Workflow: LinkedIn → Web Enrichment
776
+
777
+ **Pattern**: Use LinkedIn as source, enrich with web data
778
+
779
+ **Steps**:
780
+
781
+ 1. **Find prospects on LinkedIn**
782
+ ```
783
+ search_linkedin_users(title, location, company_keywords)
784
+ ```
785
+
786
+ 2. **Get company websites**
787
+ ```
788
+ For each prospect:
789
+ get_linkedin_company(prospect.company)
790
+ → Extract website URL
791
+ ```
792
+
793
+ 3. **Extract company contacts**
794
+ ```
795
+ For each company website:
796
+ parse_webpage(website + "/contact", extract_contacts=true)
797
+ parse_webpage(website + "/team", extract_contacts=true)
798
+ ```
799
+
800
+ 4. **Match web contacts to LinkedIn**
801
+ ```
802
+ For each email found on website:
803
+ If email pattern matches prospect name:
804
+ Assign email to LinkedIn prospect
805
+ Else:
806
+ Try find_linkedin_user_email(email)
807
+ ```
808
+
809
+ 5. **Build enriched prospect list**
810
+ ```
811
+ Combine:
812
+ - LinkedIn profile data (title, experience, etc.)
813
+ - Company website (phone, address)
814
+ - Direct email (from web or LinkedIn)
815
+ - Social profiles (from website)
816
+ ```
817
+
818
+ **Expected Result**:
819
+ - LinkedIn prospects with 80-90% email coverage
820
+ - Company phone numbers for all prospects
821
+ - Verified company websites
822
+ - Full contact profiles ready for outreach
823
+
824
+ ### Workflow: Web → LinkedIn Validation
825
+
826
+ **Pattern**: Use website as source, validate with LinkedIn
827
+
828
+ **Steps**:
829
+
830
+ 1. **Extract team from website**
831
+ ```
832
+ parse_webpage("https://company.com/team", extract_contacts=true)
833
+ → Get names, titles, emails
834
+ ```
835
+
836
+ 2. **Search LinkedIn for each person**
837
+ ```
838
+ For each team member:
839
+ search_linkedin_users(
840
+ first_name=<first>,
841
+ last_name=<last>,
842
+ company_keywords=<company>
843
+ )
844
+ ```
845
+
846
+ 3. **Validate and enrich**
847
+ ```
848
+ For each LinkedIn match:
849
+ get_linkedin_profile(user)
850
+ → Verify title matches
851
+ → Get full work history
852
+ → Find additional contact methods
853
+ ```
854
+
855
+ 4. **Cross-reference data**
856
+ ```
857
+ Compare:
858
+ - Website title vs. LinkedIn title (should match)
859
+ - Email pattern consistency
860
+ - Still at company (LinkedIn current position)
861
+ ```
862
+
863
+ 5. **Build validated contact list**
864
+ ```
865
+ Keep prospects where:
866
+ - LinkedIn profile found
867
+ - Title matches (or is recent)
868
+ - Still at company
869
+ - Email validated
870
+ ```
871
+
872
+ **Expected Result**:
873
+ - 70-80% of website contacts validated on LinkedIn
874
+ - Up-to-date employment status
875
+ - Enriched with LinkedIn work history
876
+ - Higher quality contact data
877
+
878
+ ## Best Practices Summary
879
+
880
+ ### Efficiency
881
+
882
+ 1. **Start with sitemap** to identify all relevant pages
883
+ 2. **Parse in batches** of 5-10 websites at a time
884
+ 3. **Prioritize high-value pages** (team, leadership) over generic contact pages
885
+ 4. **Use LinkedIn first** for individual contacts, web scraping for company-level contacts
886
+
887
+ ### Quality
888
+
889
+ 1. **Validate all contact data** before using
890
+ 2. **Match emails to people** when possible (vs. generic info@)
891
+ 3. **Check data freshness** (recent LinkedIn activity = current employee)
892
+ 4. **Verify company domain** matches website being scraped
893
+
894
+ ### Compliance
895
+
896
+ 1. **Respect robots.txt** and website terms of service
897
+ 2. **Rate limit requests** to avoid overloading servers
898
+ 3. **Only collect publicly available** contact information
899
+ 4. **Provide opt-out mechanism** in all communications
900
+
901
+ ### Organization
902
+
903
+ 1. **Track source of data** (which page each contact came from)
904
+ 2. **Date stamp extractions** to know data freshness
905
+ 3. **Deduplicate systematically** (same email from multiple pages)
906
+ 4. **Categorize contacts** (by department, location, role)
907
+
908
+ ---
909
+
910
+ **Next Steps**: Combine web scraping with LinkedIn strategies from [LINKEDIN_STRATEGIES.md](LINKEDIN_STRATEGIES.md) for comprehensive lead generation.