Telegramscrapinglead-extractiontechnicalautomation

Telegram Lead Scraping: The Complete Technical Guide to Extracting Qualified Leads

6 min read

Complete technical guide to Telegram lead scraping: group discovery, member extraction, comment mining, profile enrichment, intent detection, and data pipeline architecture. Includes working code examples for every component.

Telegram Lead Scraping: The Complete Technical Guide

Introduction

Telegram lead scraping is fundamentally different from scraping LinkedIn or email. The platform''s open API, structured group membership, and accessible message history make it the most scrapable major platform for B2B lead generation.

This guide covers every technical aspect: group discovery, member extraction, comment mining, profile enrichment, intent detection, and building a complete data pipeline.

Part 1: Infrastructure Setup

API Access Configuration

Telegram provides two API layers:

Bot API - Limited but stable. Bots can only access groups they are added to. User API (MTProto) - Full access through personal accounts. This is the primary tool for lead scraping.

Setting Up Telethon

pip install telethon
from telethon import TelegramClient

api_id = 12345678
api_hash = ''your_api_hash_here''
phone = ''+1234567890''

client = TelegramClient(f''sessions/{phone}'', api_id, api_hash)

async def initialize():
await client.start(phone)
me = await client.get_me()
print(f''Logged in as: {me.first_name}'')

with client:
client.loop.run_until_complete(initialize())

Multi-Account Setup

class AccountPool:
    def __init__(self, config_path=''accounts.json''):
        with open(config_path) as f:
            self.accounts = json.load(f)
        self.clients = {}
        self.usage = {}
    
    def get_best_account(self):
        min_usage = float(''inf'')
        best_index = 0
        for i, account in enumerate(self.accounts):
            usage = self.usage.get(i, 0)
            if usage < min_usage and usage < account.get(''daily_limit'', 200):
                min_usage = usage
                best_index = i
        return best_index

Part 2: Group Discovery

Automated Group Discovery

class GroupDiscovery:
    def __init__(self, client):
        self.client = client
    
    async def evaluate_group(self, group_username):
        entity = await self.client.get_entity(group_username)
        full_chat = await self.client(GetFullChatRequest(entity))
        participants_count = full_chat.full_chat.participants_count or 0
        
        messages = []
        async for msg in self.client.iter_messages(entity, limit=100):
            messages.append(msg)
        
        if not messages:
            return None
        
        oldest_msg = messages[-1].date
        newest_msg = messages[0].date
        time_span_days = max((newest_msg - oldest_msg).days, 1)
        messages_per_day = len(messages) / time_span_days
        
        score = 0
        if 5000 <= participants_count <= 50000:
            score += 30
        elif 1000 <= participants_count <= 5000:
            score += 20
        
        score += min(messages_per_day / 10, 30)
        
        return {
            ''username'': group_username,
            ''participants_count'': participants_count,
            ''messages_per_day'': messages_per_day,
            ''overall_score'': score
        }

Part 3: Member Extraction

Basic Member Scraping

async def scrape_group_members(group_username, limit=1000):
    client = TelegramClient(''session'', api_id, api_hash)
    await client.start()
    
    members = []
    entity = await client.get_entity(group_username)
    
    offset = 0
    batch_size = 100
    
    while offset < limit:
        result = await client(GetParticipantsRequest(
            channel=entity,
            filter=ChannelParticipantsSearch(''''),
            offset=offset,
            limit=batch_size,
            hash=0
        ))
        
        if not result.users:
            break
        
        for user in result.users:
            if not user.bot and not user.deleted:
                members.append({
                    ''user_id'': user.id,
                    ''username'': user.username,
                    ''first_name'': user.first_name,
                    ''last_name'': user.last_name,
                    ''phone'': user.phone,
                    ''is_premium'': getattr(user, ''premium'', False),
                    ''group'': group_username
                })
        
        offset += len(result.users)
        await asyncio.sleep(2)
    
    await client.disconnect()
    return members

Part 4: Comment-Based Lead Extraction

Intent Detection

class CommentExtractor:
    def __init__(self, client):
        self.client = client
        self.intent_keywords = {
            ''high'': [''recommend'', ''suggest'', ''looking for'', ''need help'',
                     ''рекомендуете'', ''посоветуйте'', ''ищу'', ''нужна помощь''],
            ''medium'': [''how to'', ''what is'', ''best way'',
                       ''как сделать'', ''что такое'', ''лучший способ''],
            ''low'': [''interesting'', ''tell me more'',
                    ''интересно'', ''расскажи больше'']
        }
    
    async def extract_comments_with_intent(self, group_username, hours_back=24):
        entity = await self.client.get_entity(group_username)
        cutoff_time = datetime.now() - timedelta(hours=hours_back)
        
        leads = []
        async for message in self.client.iter_messages(entity, offset_date=cutoff_time):
            if not message.text or message.reply_to is None:
                continue
            
            text = message.text.lower()
            intent_level = self.detect_intent(text)
            if not intent_level:
                continue
            
            sender = await message.get_sender()
            if sender.bot or sender.deleted:
                continue
            
            leads.append({
                ''user_id'': sender.id,
                ''username'': sender.username,
                ''first_name'': sender.first_name,
                ''bio'': sender.about or '''',
                ''comment'': message.text[:500],
                ''intent_level'': intent_level,
                ''timestamp'': message.date.isoformat(),
                ''group'': group_username
            })
        
        return leads
    
    def detect_intent(self, text):
        for level, keywords in self.intent_keywords.items():
            for keyword in keywords:
                if keyword in text:
                    return level
        return None

Part 5: Profile Enrichment

async def enrich_profile(user, client):
    profile = {
        ''telegram_id'': user.id,
        ''username'': user.username,
        ''first_name'': user.first_name,
        ''last_name'': user.last_name,
        ''phone'': user.phone,
        ''bio'': user.about or '''',
        ''is_premium'': getattr(user, ''premium'', False),
        ''has_photo'': bool(user.photo),
    }
    
    bio_text = profile[''bio''].lower()
    
    company_patterns = [r''at (\w+)'', r''@ (\w+)'', r''working at (\w+)'']
    for pattern in company_patterns:
        match = re.search(pattern, bio_text)
        if match:
            profile[''company''] = match.group(1)
            break
    
    role_keywords = {
        ''cto'': [''cto'', ''technical director'', ''технический директор''],
        ''ceo'': [''ceo'', ''founder'', ''основатель''],
        ''cmo'': [''cmo'', ''marketing director'', ''директор по маркетингу''],
        ''developer'': [''developer'', ''engineer'', ''разработчик'']
    }
    for role, keywords in role_keywords.items():
        if any(kw in bio_text for kw in keywords):
            profile[''role''] = role
            break
    
    return profile

Part 6: Intent Scoring

class IntentScorer:
    def __init__(self):
        self.weights = {
            ''comment_intent'': 0.25,
            ''profile_match'': 0.20,
            ''activity_level'': 0.15,
            ''recency'': 0.15,
            ''question_asked'': 0.15,
            ''company_match'': 0.10
        }
    
    def calculate_intent_score(self, lead_data):
        scores = {}
        
        if lead_data.get(''intent_level'') == ''high'':
            scores[''comment_intent''] = 90
        elif lead_data.get(''intent_level'') == ''medium'':
            scores[''comment_intent''] = 60
        else:
            scores[''comment_intent''] = 10
        
        scores[''profile_match''] = self.calculate_profile_match(lead_data)
        scores[''activity_level''] = min(lead_data.get(''message_count'', 0) * 10, 100)
        scores[''question_asked''] = 80 if lead_data.get(''question'') else 20
        scores[''company_match''] = 70 if lead_data.get(''company_match'') else 30
        
        return sum(scores[k] * self.weights[k] for k in self.weights)

Part 7: Data Pipeline Architecture

[Group Discovery] -> [Group Scoring] -> [Member Extraction] -> [Profile Enrichment]
        |                    |                   |                    |
   TGStat API          NLP Analysis       Telethon API        External APIs
        |                    |                   |                    |
  [Comment Mining] -> [Intent Detection] -> [Behavioral Analysis] -> [Intent Scoring]
        |                    |                   |                    |
   Message API       Keyword Match       Pattern Detection     Weighted Score
        |                    |                   |                    |
  [Data Storage] -> [Lead Qualification] -> [CRM Integration] -> [Outreach Ready]
        |                    |                   |                    |
   PostgreSQL       Score Threshold     Webhook/API         Campaign Ready

Database Schema

CREATE TABLE leads (
    id SERIAL PRIMARY KEY,
    telegram_id BIGINT UNIQUE,
    username VARCHAR(255),
    first_name VARCHAR(255),
    last_name VARCHAR(255),
    phone VARCHAR(50),
    bio TEXT,
    is_premium BOOLEAN DEFAULT FALSE,
    has_photo BOOLEAN DEFAULT FALSE,
    scraped_at TIMESTAMP DEFAULT NOW(),
    intent_score FLOAT DEFAULT 0,
    status VARCHAR(50) DEFAULT ''new'',
    metadata JSONB DEFAULT ''{}''
);

CREATE TABLE lead_sources (
id SERIAL PRIMARY KEY,
lead_id INTEGER REFERENCES leads(id),
source_type VARCHAR(50),
source_group VARCHAR(255),
source_context TEXT,
discovered_at TIMESTAMP DEFAULT NOW()
);

CREATE INDEX idx_leads_score ON leads(intent_score DESC);
CREATE INDEX idx_leads_status ON leads(status);

Part 8: Scaling and Optimization

Parallel Processing

async def parallel_scrape(groups, max_concurrent=5):
    semaphore = asyncio.Semaphore(max_concurrent)
    
    async def scrape_with_semaphore(group):
        async with semaphore:
            return await scrape_group(group)
    
    tasks = [scrape_with_semaphore(g) for g in groups]
    results = await asyncio.gather(*tasks, return_exceptions=True)
    
    successful = [r for r in results if not isinstance(r, Exception)]
    return successful

Caching

class CacheManager:
    def __init__(self, redis_url=''redis://localhost:6379''):
        self.redis = redis.from_url(redis_url)
        self.default_ttl = 3600 * 24
    
    def cached(self, ttl=None):
        def decorator(func):
            @wraps(func)
            async def wrapper(args, *kwargs):
                cache_key = f''{func.__name__}:{hash(str(args) + str(kwargs))}''
                cached = self.redis.get(cache_key)
                if cached:
                    return json.loads(cached)
                result = await func(args, *kwargs)
                self.redis.setex(cache_key, ttl or self.default_ttl, json.dumps(result, default=str))
                return result
            return wrapper
        return decorator

Part 9: Compliance and Best Practices

  • Only scrape public groups
  • Do not store phone numbers without explicit consent
  • Provide opt-out mechanisms in all outreach
  • Respect rate limits
  • Document data processing activities

Conclusion

Telegram lead scraping provides the foundation for automated lead generation. The technical infrastructure described here enables continuous discovery, extraction, enrichment, and qualification of prospects. Start with basics, then progressively add sophistication: comment mining, intent detection, external enrichment, and predictive scoring.