Python के साथ ईमेल स्क्रैपिंग: उदाहरणों सहित पूर्ण गाइड

टिप्पणियाँ: 0

प्रत्यक्ष आउटरीच के काम करने के लिए, आपको एक ठोस आधार की आवश्यकता होती है – वास्तविक और अद्यतन ईमेल पतों का डेटाबेस। यहीं पर Python के साथ ईमेल स्क्रैपिंग उपयोगी होती है: वेबसाइटों से प्रोग्रामेटिक रूप से पते एकत्र करने का एक तरीका।

इस गाइड में, हम यह देखेंगे कि शुरुआत से ईमेल स्क्रैपिंग को Python के साथ कैसे बनाया जाए, डायनेमिक पेजों को कैसे संभाला जाए, एकत्र किए गए पतों को कैसे फ़िल्टर और सत्यापित किया जाए, और परिणामस्वरूप डेटा को वास्तविक मार्केटिंग या व्यावसायिक वर्कफ़्लो में कैसे उपयोग किया जाए।

यह सामग्री उपयोगी है यदि आपको आवश्यकता है:

  • यह समझने की कि बिना तैयार सेवाओं के, आप स्वयं Python का उपयोग करके वेबसाइट से ईमेल पते कैसे स्क्रैप कर सकते हैं;
  • न्यूज़लेटर, CRM या शोध के लिए मेलिंग सूचियों के निर्माण को स्वचालित करने की;
  • कोड को वास्तविक उपयोग मामलों से जोड़ने की – निष्कर्षण से लेकर एकीकरण तक।

आगे हम देखेंगे कि कैसे सार्वजनिक रूप से उपलब्ध पृष्ठों को सीधे संचार चैनल में बदला जा सकता है उन लोगों के साथ जो आपके ग्राहक बन सकते हैं – Python का उपयोग करके।

ईमेल स्क्रैपिंग क्या है और यह कैसे मदद करती है

मूल रूप से, इस प्रकार की स्क्रैपिंग का मतलब है HTML या डायनेमिक पृष्ठों को स्वचालित रूप से स्कैन करना और सामग्री या विशेषताओं में उन पैटर्न की खोज करना जो पते के प्रारूप (उदाहरण के लिए, username@domain.tld) से मेल खाते हैं। फिर आप परिणामों को फ़िल्टर, सत्यापित और सहेजते हैं।

वे कार्य जहाँ Python ईमेल स्क्रैपर का उपयोग होता है

इसका व्यापक रूप से उपयोग व्यवसाय, मार्केटिंग, शोध और नियमित प्रक्रियाओं के स्वचालन में किया जाता है। यह विशेष रूप से उपयोगी है जब आपको कई स्रोतों से बड़ी मात्रा में सार्वजनिक जानकारी एकत्र और संरचित करनी हो।

विशिष्ट कार्यों के उदाहरण जहाँ Python के साथ ईमेल स्क्रैपिंग लागू होती है:

  • ईमेल अभियानों के लिए संपर्क डेटाबेस बनाना;
  • मार्केटिंग और लीड जनरेशन;
  • सार्वजनिक रूप से उपलब्ध संपर्कों का शोध और विश्लेषण;
  • CRM सिस्टम को भरना और अपडेट करना;
  • प्रतिस्पर्धियों की गतिविधियों की निगरानी;
  • अपने स्वयं के संपर्क डेटा का ऑडिट और सत्यापन।

यदि आप ई-कॉमर्स परियोजनाओं के लिए संपर्क डेटा एकत्र करने में रुचि रखते हैं, तो हमारे ईकॉमर्स डेटा स्क्रैपिंग गाइड को देखें।

बुनियादी बातें: उपकरण और तैयारी

स्क्रैपिंग को प्रभावी बनाने के लिए, आपको पर्यावरण तैयार करना होगा और सही उपकरण चुनने होंगे। ये आपको डेटा को तेजी से प्राप्त करने, जटिल या डायनेमिक पेजों को संभालने और बड़े प्रोजेक्ट्स को संगठित करने में मदद करते हैं।

ईमेल पतों को स्क्रैप करने के लिए लाइब्रेरी चुनें

स्क्रैपिंग के लिए सामान्य Python उपकरण:

टूल उपयोग
requests / httpx स्थिर पृष्ठ प्राप्त करना
BeautifulSoup HTML पार्सिंग / तत्व खोज
re (regular expressions) पैटर्न निकालना
lxml तेज़ पार्सिंग
Selenium / Playwright JavaScript-चालित पृष्ठों को संभालना
Scrapy बड़े क्रॉल के लिए एक पूर्ण-स्तरीय फ़्रेमवर्क

कार्य वातावरण तैयार करना

  1. एक वर्चुअल वातावरण बनाएं (venv या virtualenv)।
  2. निर्भरता स्थापित करें:
    pip install requests beautifulsoup4 lxml
    pip install selenium  # यदि आपको डायनेमिक रेंडरिंग की आवश्यकता है
  3. (यदि आवश्यक हो) एक ब्राउज़र ड्राइवर सेट करें (ChromeDriver, GeckoDriver)।
  4. प्रारंभिक URL या डोमेन की सूची तैयार करें।
  5. ट्रैवर्सल रणनीति तय करें — रिकर्सिव या सीमित।

यह देखने के लिए कि समान विधियाँ अन्य प्लेटफार्मों के लिए कैसे लागू होती हैं, हमारे Python का उपयोग करके Reddit को स्क्रैप करें पर विस्तृत गाइड देखें।

उदाहरण: Python के साथ ईमेल स्क्रैपिंग — मुख्य लॉजिक (Pseudocode)

# 1. Create an HTTP session with timeouts and retries
session = make_session()
# 2. Load the page
html = session.get(url)
# 3. Look for email addresses:
#    - via regex across the entire text
#    - via mailto: links in HTML
emails = extract_emails_from_text(html)
emails.update(find_mailto_links(html))
# 4. Return a unique list of addresses
return emails

यह तरीका क्यों?

  • Session + retries — रैंडम फेलियर्स से बचने और त्रुटियों पर अनुरोधों को दोहराने के लिए।
  • Regex + mailto: — तुरंत दो सरल और प्रभावी रास्ते।
  • lxml in BeautifulSoup — एक तेज़ और अधिक सटीक HTML पार्सर।
  • Normalizing mailto: — अतिरिक्त चीजें हटाएँ (?subject=...), केवल पता रखें।

विस्तारित संस्करण: मल्टी-लेवल क्रॉलर

"""
Iterate over internal links within one domain and collect email addresses.
Highlights:
- Page limit (max_pages) to stop safely
- Verifying that a link belongs to the base domain
- Avoiding re-visits
- Optional respect for robots.txt
"""

from __future__ import annotations
from collections import deque
from typing import Set
from urllib.parse import urljoin, urlparse, urlsplit, urlunsplit
import time
import requests
from bs4 import BeautifulSoup
import lxml # Import lxml to ensure it's available for BeautifulSoup
from urllib import robotparser  # standard robots.txt parser
# We use functions from the previous block:
# - make_session()
# - scrape_emails_from_url()
import re

# General regular expression for email addresses
EMAIL_RE = re.compile(r"[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9.-]+")

def scrape_emails_from_url(url: str, session: requests.Session) -> Set[str]:
   """Collect email addresses from the given URL page."""
   emails: Set[str] = set()
   try:
       resp = session.get(url, timeout=getattr(session, "_default_timeout", 10.0))
       resp.raise_for_status()
       # Regular expression for email addresses
       # Note: this regex isn't perfect, but it's sufficient for typical cases
       email_pattern = re.compile(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}")
       emails.update(email_pattern.findall(resp.text))
   except requests.RequestException:
       pass
   return emails

def make_session() -> requests.Session:
   """Create and return a requests session with basic settings."""
   session = requests.Session()
   session.headers.update({
       "User-Agent": "EmailScraper/1.0",
       "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
       "Accept-Language": "en-US,en;q=0.9",
       # Don't force Accept-Encoding to avoid br issues without brotli
       "Connection": "keep-alive",
   })
   return session
def same_host(url: str, base_netloc: str) -> bool:
   """True if the link belongs to the same host (domain/subdomain)."""
   return urlparse(url).netloc == base_netloc
def load_robots(start_url: str, user_agent: str = "EmailScraper") -> robotparser.RobotFileParser:
   """Read robots.txt and return a parser for permission checks."""
   base = urlparse(start_url)
   robots_url = f"{base.scheme}://{base.netloc}/robots.txt"
   rp = robotparser.RobotFileParser()
   rp.set_url(robots_url)
   try:
       rp.read()
   except Exception:
       pass
   rp.useragent = user_agent
   return rp

def normalize_url(url: str, base: str | None = None) -> str | None:
   try:
       abs_url = urljoin(base, url) if base else url
       parts = urlsplit(abs_url)
       if parts.scheme not in ("http", "https"):
           return None
       host = parts.hostname
       if not host:
           return None
       host = host.lower()
       netloc = host
       if parts.port:
           netloc = f"{host}:{parts.port}"
       parts = parts._replace(fragment="")
       return urlunsplit((parts.scheme.lower(), netloc, parts.path or "/", parts.query, ""))
   except Exception:
       return None

def in_scope(url: str, base_host: str, include_subdomains: bool) -> bool:
   try:
       host = urlsplit(url).hostname
       if not host:
           return False
       host = host.lower()
       base_host = (base_host or "").lower()
       if include_subdomains:
           return host == base_host or host.endswith("." + base_host)
       else:
           return host == base_host
   except Exception:
       return False
def collect_emails_from_site(
   start_url: str,
   max_pages: int = 100,
   delay_sec: float = 0.5,
   respect_robots: bool = True,
   include_subdomains: bool = True,
) -> Set[str]:
   """
   Traverse pages within a domain and return unique email addresses.
   - max_pages: hard limit on visited pages.
   - delay_sec: polite pause between requests.
   - respect_robots: if True — checks access rules.
   - include_subdomains: if True — allows subdomains (www, etc.).
   """
   session = make_session()
   base_host = (urlparse(start_url).netloc or "").lower()
   visited: Set[str] = set()
   queue: deque[str] = deque()
   enqueued: Set[str] = set()
   all_emails: Set[str] = set()

   start_norm = normalize_url(start_url)
   if start_norm:
       queue.append(start_norm)
       enqueued.add(start_norm)

   rp = load_robots(start_url, user_agent="EmailScraper/1.0") if respect_robots else None

   while queue and len(visited) < max_pages:
       url = queue.popleft()
       if url in visited:
           continue

       # robots.txt check
       if respect_robots and rp is not None:
           try:
               if not rp.can_fetch("EmailScraper/1.0", url):
                   continue
           except Exception:
               pass

       # One request: used both for emails and links
       try:
           resp = session.get(url, timeout=10)
           resp.raise_for_status()
           html_text = resp.text or ""
       except requests.RequestException:
           continue

       visited.add(url)

       # Skip non-HTML pages
       ctype = resp.headers.get("Content-Type", "")
       if ctype and "text/html" not in ctype:
           continue

       # Collect emails
       for m in EMAIL_RE.findall(html_text):
           all_emails.add(m.lower())

       # Parse links
       soup = BeautifulSoup(html_text, "lxml")

       # Emails from mailto:
       for a in soup.find_all("a", href=True):
           href = a["href"].strip()
           if href.lower().startswith("mailto:"):
               addr_part = href[7:].split("?", 1)[0]
               for piece in addr_part.split(","):
                   email = piece.strip()
                   if EMAIL_RE.fullmatch(email):
                       all_emails.add(email.lower())

       for a in soup.find_all("a", href=True):
           href = a["href"].strip()
           if not href or href.startswith(("javascript:", "mailto:", "tel:", "data:")):
               continue
           next_url = normalize_url(href, base=url)
           if not next_url:
               continue
           if not in_scope(next_url, base_host, include_subdomains):
               continue
           if next_url not in visited and next_url not in enqueued:
               queue.append(next_url)
               enqueued.add(next_url)

       if delay_sec > 0:
           time.sleep(delay_sec)

   try:
       session.close()
   except Exception:
       pass
   return all_emails
if __name__ == "__main__":
   import argparse

parser = argparse.ArgumentParser(
   description="An email scraper that traverses pages within a site and prints discovered addresses."
)

parser.add_argument(
   "start_url",
   help="Starting URL, for example: https://example.com"
)

parser.add_argument(
   "--max-pages",
   type=int,
   default=100,
   dest="max_pages",
   help="Maximum number of pages to traverse (default: 100)"
)

parser.add_argument(
   "--delay",
   type=float,
   default=0.5,
   help="Delay between requests in seconds (default: 0.5)"
)

parser.add_argument(
   "--no-robots",
   action="store_true",
   help="Ignore robots.txt (use carefully)"
)

scope = parser.add_mutually_exclusive_group()

scope.add_argument(
   "--include-subdomains",
   dest="include_subdomains",
   action="store_true",
   default=True,
   help="Include subdomains (default)"
)

scope.add_argument(
   "--exact-host",
   dest="include_subdomains",
   action="store_false",
   help="Restrict traversal to the exact host (no subdomains)"
)

parser.add_argument(
   "--output",
   type=str,
   default=None,
   help="Optional: path to a file to save found email addresses (one per line)"

   args = parser.parse_args()

   emails = collect_emails_from_site(
       args.start_url,
       max_pages=args.max_pages,
       delay_sec=args.delay,
       respect_robots=not args.no_robots,
       include_subdomains=args.include_subdomains,
   )

   for e in sorted(emails):
       print(e)

   print(f"Found {len(emails)} unique emails.")

   if args.output:
       try:
           with open(args.output, "w", encoding="utf-8") as f:
               for e in sorted(emails):
                   f.write(e + "\n")
       except Exception as ex:
           print(f"Could not write the output file: {ex}")

विस्तारित स्क्रिप्ट को चलाने और कॉन्फ़िगर करने का तरीका

main.py https://example.com
स्क्रिप्ट पैरामीटर्स
  • start_url – प्रारंभिक URL जहाँ से ट्रैवर्सल शुरू होता है (उदाहरण: https://example.com)।
  • --max-pages – ट्रैवर्स करने के लिए अधिकतम पृष्ठों की संख्या। डिफ़ॉल्ट: 100।
  • --delay – सर्वर लोड कम करने के लिए अनुरोधों के बीच विलंब (सेकंड में)। डिफ़ॉल्ट: 0.5।
  • --no-robots – robots.txt के नियमों को अनदेखा करें। सावधानी से उपयोग करें, क्योंकि साइट स्वचालित ट्रैवर्सल को अस्वीकार कर सकती है।
  • --include-subdomains – ट्रैवर्सल के दौरान सबडोमेन्स को शामिल करें। डिफ़ॉल्ट रूप से सक्षम।
  • --exact-host – ट्रैवर्सल को केवल सटीक होस्ट तक सीमित करें (कोई सबडोमेन नहीं)।
  • --output – पाए गए पतों को सहेजने के लिए फ़ाइल का पथ (प्रत्येक पंक्ति में एक)। यदि प्रदान नहीं किया गया है, तो पते कंसोल पर प्रदर्शित किए जाते हैं।

ऑबफ्युस्केशन और डायनेमिक सामग्री को संभालना

जब आप कोई स्क्रिप्ट चलाते हैं, तो चीजें हमेशा सीधी नहीं होतीं: कई साइटें जानबूझकर ईमेल पतों को छिपाती हैं या केवल तब दिखाती हैं जब JavaScript रेंडर हो चुका हो। यहाँ बताया गया है कि कौन सी चीजें बाधा डाल सकती हैं — और उन्हें कैसे संभाला जाए।

संभावित समस्याएँ

1. ऑबफ्युस्केशन

साइटें अक्सर बॉट्स से पते छिपाने के लिए तकनीकें अपनाती हैं:

  • JavaScript जो पते को भागों से जोड़ता है (जैसे user + “@” + domain.com);
  • एन्क्रिप्टेड या एन्कोडेड स्ट्रिंग्स (जैसे Base64, HTML entities);
  • HTML टिप्पणियाँ या इनसर्शन, जहाँ पते का कुछ भाग छिपा रहता है;
  • ईमेल को एक इमेज के रूप में दिखाना (टेक्स्ट की तस्वीर), जिसमें स्क्रिप्ट कुछ नहीं देखती;
  • कैरेक्टर रिप्लेसमेंट: user [at] example [dot] com और अन्य “मनुष्य-पठनीय” रूप (address munging)।

2. डायनेमिक पेजेज

आधुनिक साइटें अक्सर JavaScript (जैसे fetch, AJAX) के माध्यम से सामग्री लोड करती हैं। एक साधारण requests.get() एक “खाली” HTML शेल लौटा सकता है जिसमें ईमेल सामग्री नहीं होती।

इन बाधाओं को दूर करने के तरीके

जब आप ऐसी पृष्ठों का सामना करते हैं, तो व्यावहारिक दृष्टिकोण:

  1. Selenium या Playwright:

    ब्राउज़र लॉन्च करें, पृष्ठ को “लोड” होने दें, आवश्यक तत्वों के प्रकट होने की प्रतीक्षा करें, फिर पूरा HTML कैप्चर करें। यह तब काम करता है जब ईमेल JS द्वारा रेंडर के बाद जोड़ा जाता है।

  2. API कॉल्स:

    अक्सर पृष्ठ वास्तव में किसी API से डेटा खींचता है। नेटवर्क अनुरोधों (DevTools → Network) की जाँच करें ताकि यह देखें कि कोई ऐसा अनुरोध है जो JSON में ईमेल या संपर्क जानकारी लौटाता है या नहीं। यदि हाँ, तो सीधे API का उपयोग करना बेहतर है।

  3. नलाइन JS / स्क्रिप्ट्स को पार्स करना:

    कभी-कभी पता JavaScript में “एम्बेडेड” होता है (जैसे Base64 स्ट्रिंग या भागों में विभाजित)। आप उस JS की व्याख्या कर सकते हैं, स्ट्रिंग निकाल सकते हैं और पते को डिकोड कर सकते हैं।

  4. यदि ईमेल किसी इमेज में है:

    इमेज डाउनलोड करें और OCR (Optical Character Recognition) लागू करें, उदाहरण के लिए Tesseract के साथ। यह अधिक संसाधन-गहन है लेकिन कभी-कभी आवश्यक होता है।

  5. विलंब और समय-निर्धारण:

    कुछ तत्व कुछ सेकंड बाद या विशिष्ट घटनाओं (स्क्रॉल, क्लिक) के बाद दिखाई देते हैं। इसलिए समझदारी यह है कि:

    • sleep() का उपयोग करें या किसी चयनकर्ता की प्रतीक्षा करें;
    • कई प्रयास करें;
    • “यदि नहीं मिला तो पुनः प्रयास करें” जैसी रणनीतियाँ लागू करें।

निष्कर्ष

Python के साथ ईमेल स्क्रैपिंग के लिए इस लेख में बताई गई तकनीकों को लागू करके, आप अपनी स्क्रिप्ट्स को वास्तविक परिस्थितियों में विश्वसनीय रूप से काम करने योग्य बना सकते हैं। ध्यान रखें कि डेटा की गुणवत्ता सीधे बाद के अभियानों की प्रभावशीलता को प्रभावित करती है, इसलिए शुरुआत से ही फ़िल्टरिंग, सत्यापन और सुविधाजनक प्रारूप में सहेजना लागू करना उचित है।

टिप्पणियाँ:

0 टिप्पणियाँ