电报(Telegram)的广告过滤

Telegram的垃圾广告太多,需要文明环境的我们非常排斥。

整体架构流程

adblocking/

├── app/
│   ├── app.py                 # 主程序,包含广告屏蔽的逻辑
│   ├── requirements.txt       # Python 项目依赖
│   └── blocked_ads.db         # SQLite 数据库文件,用于存储广告消息和白名单

├── Dockerfile                 # Dockerfile 文件
└── docker-compose.yml         # Docker Compose 配置文件

编写 Python 脚本 app.py文件

以下是 Python 脚本 bot.py 的完整代码,包含广告检测、频率限制、白名单功能、消息统计等功能。

import os
import secrets
import logging
import sqlite3
import re
import time
from telegram import Update,ChatPermissions
from telegram.ext import Application, CommandHandler, MessageHandler, filters, CallbackContext

# 配置日志
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO)
logger = logging.getLogger(__name__)

# 设置 Bot Token(替换为你自己的 Token)
TOKEN = os.getenv("TELEGRAM_TOKEN")


# 初始化数据库
def init_db():
    conn = sqlite3.connect('blocked_ads.db')
    c = conn.cursor()
    c.execute('''CREATE TABLE IF NOT EXISTS blocked_ads
                 (chat_id INTEGER,group_title TEXT,username TEXT,first_name TEXT, message_id INTEGER, message_text TEXT, sender_id INTEGER, timestamp INTEGER)''') # 记录用户消息
    c.execute('''CREATE TABLE IF NOT EXISTS whitelist
                 (chat_id INTEGER, user_id INTEGER, group_title TEXT, chat_token TEXT)''')  # 白名单
    c.execute('''CREATE TABLE IF NOT EXISTS tokenlist
                 (token_type INTEGER,token_val TEXT, chat_id INTEGER, user_id INTEGER)''')  # 操作字典
    conn.commit()
    conn.close()

# ---------------------------以下是server方法区----------------------------------------

# 添加字典
def addtooltoken(token_type,chat_id, user_id,token_val):
    conn = sqlite3.connect('blocked_ads.db')
    c = conn.cursor()
    c.execute('INSERT INTO tokenlist (token_type,token_val,chat_id, user_id) VALUES (?,?,?,?)', (token_type,token_val,chat_id, user_id))
    conn.commit()
    conn.close()

# 将字典删除
def deltooltoken(token_val,token_type):
    # 检查是否持有令牌
    is_token = is_tool_token(token_val,token_type)
    if is_token:
        conn = sqlite3.connect('blocked_ads.db')
        c = conn.cursor()
        c.execute('DELETE FROM tokenlist WHERE token_type=? and token_val=?', (token_type,token_val))
        conn.commit()
        conn.close()
    return

# 查询字典
def seltooltoken(token_type,chat_id = None):
    conn = sqlite3.connect('blocked_ads.db')
    c = conn.cursor()
    if chat_id:
        c.execute('SELECT token_val FROM tokenlist WHERE token_type=? and chat_id=?', (token_type,chat_id))
    else:
        c.execute('SELECT token_val FROM tokenlist WHERE token_type=?', (token_type,))
    result = c.fetchall()
    c.close()
    conn.close()
    return result
    
# 是否持有字典
def is_tool_token(token_val,token_type,chat_id = None):
    conn = sqlite3.connect('blocked_ads.db')
    c = conn.cursor()
    if 2 == token_type and chat_id:
        c.execute('SELECT COUNT(*) FROM tokenlist WHERE token_val=? and (token_type=1 or (token_type=? and chat_id=?))', (token_val,token_type,chat_id))
    elif chat_id:
        c.execute('SELECT COUNT(*) FROM tokenlist WHERE token_val=? and token_type=? and chat_id=?', (token_val,token_type,chat_id))
    else:
        c.execute('SELECT COUNT(*) FROM tokenlist WHERE token_val=? and token_type=?', (token_val,token_type))
    count = c.fetchone()[0]
    conn.close()
    return count > 0
    
# 记录被屏蔽的广告消息
def log_blocked_ad(chat_id,group_title,username,first_name, message_id, message_text, sender_id, timestamp):
    conn = sqlite3.connect('blocked_ads.db')
    c = conn.cursor()
    c.execute( 'INSERT INTO blocked_ads (chat_id,group_title,username,first_name, message_id, message_text, sender_id, timestamp) VALUES (?,?,?,?,?, ?, ?, ?)',
        (chat_id,group_title,username,first_name, message_id, message_text, sender_id, timestamp))
    conn.commit()
    conn.close()


# 获取屏蔽广告的统计信息
def get_blocked_stats(chat_id):
    conn = sqlite3.connect('blocked_ads.db')
    c = conn.cursor()
    c.execute('SELECT COUNT(*) FROM blocked_ads where chat_id=?',(chat_id,))
    count = c.fetchone()[0]
    conn.close()
    return count


# 广告检测规则:检查关键词、链接等
def is_ad_message(message_text, sender_id, timestamp, chat_id):
    ad_keywords  = ["免费", "优惠", "广告", "赚钱", "投资", "促销", "折扣","TG群", "Telegram群", "机器人", "云手机", "群控", "自动拉人", "自动私信", "自动转发","扫码", "长按识别", "点链接", "点击进入", "加我", "私我", "加好友", "微信", "VX", "QQ", "电报", "电报群"
]
    ad_patterns = [
        r'https?://\S+',
        r't\.me/\S+',
        r'加[QqQq]|加微|加微信|加V',
        r'(邀请码|推广码|推广奖励)',
        r'(数字货币|区块链|比特币|USDT|NFT)',
        r'(投资|暴利|高收益|稳赚不赔)'
    ]
    blocked_images = ['image/jpeg', 'image/png']
   
    # 检查关键词
    if any(word.lower() in message_text.lower() for word in ad_keywords):
        return True
        
    # 检查链接
    for pattern in ad_patterns:
        if re.search(pattern, message_text, re.IGNORECASE):
            return True

    # 检查图片
    if 'photo' in message_text:
        return True

    #自定义黑名单关键字
    tokens = []
    tokens0 = seltooltoken(0)
    if tokens0:
        tokens = tokens0
    tokens2 = seltooltoken(2,chat_id)
    if tokens2:
        tokens= tokens+tokens2
    # 检查黑名单关键词
    if tokens:
        if any(word[0].lower() in message_text.lower() for word in tokens):
            return True    
        
    return False

# 检查广告发送频率:
def check_user_frequency(sender_id, chat_id, timestamp, limittime, limit):
    conn = sqlite3.connect('blocked_ads.db')
    c = conn.cursor()
    time_limit = timestamp - (limittime * 60)
    c.execute('SELECT COUNT(*) FROM blocked_ads WHERE sender_id=? AND chat_id=? AND timestamp > ?',
              (sender_id, chat_id, time_limit))
    count = c.fetchone()[0]
    conn.close()

    return count >= limit

# 检查群是否在白名单
def is_user_whitelisted(chat_id, user_id):
    conn = sqlite3.connect('blocked_ads.db')
    c = conn.cursor()
    if user_id:
        c.execute('SELECT COUNT(*) FROM whitelist WHERE chat_id=? AND user_id=?', (chat_id, user_id))
    else:
        c.execute('SELECT COUNT(*) FROM whitelist WHERE chat_id=?', (chat_id,))
    count = c.fetchone()[0]
    conn.close()
    return count > 0

#判断权限
async def handle_tool_permissions(update: Update, context: CallbackContext,permissionsType = 0):
    chat_id = update.message.chat_id
    sender_id = update.message.from_user.id
    is_bot = update.message.from_user.is_bot
    if permissionsType != 3:
        group_type = update.message.chat.type  # "group" or "supergroup"
        if "group" not in group_type:
            return True if permissionsType == 1 else False
    if permissionsType == 0 or permissionsType == 2:
        # 检查是否在白名单,如果不在白名单内,则跳过广告屏蔽
        if not is_user_whitelisted(chat_id,None):
            return  False
    # 判断目标用户是否是管理员
    member = await context.bot.get_chat_member(chat_id, sender_id)
    if member.status in ['administrator', 'creator']:
        return True if permissionsType == 2 else False
    elif permissionsType == 2:
        return False
    #如果是机器人,则直接踢出
    if is_bot and permissionsType == 2:
        await kick(update, context)
        return False
    return True

# 禁言命令(5天)
async def mute(update: Update, context: CallbackContext):
    target_user = update.message.from_user
    chat_id = update.message.chat_id
    
    try:
        # 设置禁止发言权限(1小时=3600秒)
        await context.bot.restrict_chat_member(
            chat_id=chat_id,
            user_id=target_user.id,
            permissions=ChatPermissions(can_send_messages=False),
            until_date=int(update.message.date.timestamp()) + (3600 * 24 * 5)
        )
        await send_auto_reply(update, context,f"🚫 已禁言用户 @{target_user.username or target_user.first_name} 5天,再有下次踢人了!")
    except Exception as e:
        print(f" 禁言失败: {e}")
#        await update.message.reply_text(f"⚠️ 禁言失败: {e}")

# 踢人命令
async def kick(update: Update, context: CallbackContext):
    target_user = update.message.from_user
    chat_id = update.message.chat_id

    try:
        await context.bot.ban_chat_member(chat_id=chat_id, user_id=target_user.id)
        await send_auto_reply(update, context,f"👢 已将用户 @{target_user.username or target_user.first_name} 移除群组。")
    except Exception as e:
        print(f" 踢人失败: {e}")
#        await update.message.reply_text(f"⚠️ 踢人失败: {e}")

# 将群添加到白名单
async def whitelist(update: Update, context: CallbackContext, token_val):
    chat_id = update.message.chat_id
    user_id = update.effective_user.id
    group_title = update.message.chat.title
    #检测权限
    if (await handle_tool_permissions(update, context,1)):
        return False
    is_token = is_tool_token(token_val,1)
    if not is_token:
        return False
    else:
        await delete_message(update, context)
    # 检查是否在白名单
    is_white = is_user_whitelisted(chat_id, None)
    if is_white:
        await send_auto_reply(update, context,f"群{group_title}已经购买了 @adtoolseniorBot 广告拦截的功能,无需再次购买。")
    if not is_white:
        deltooltoken(token_val,1)
        conn = sqlite3.connect('blocked_ads.db')
        c = conn.cursor()
        c.execute('INSERT INTO whitelist (chat_id, user_id,group_title, chat_token) VALUES (?, ?, ?, ?)', (chat_id, user_id, group_title,token_val))
        conn.commit()
        conn.close()
        await send_auto_reply(update, context,f"群{group_title}成功购买 @adtoolseniorBot 广告拦截的功能。")
        
    return True
    
# 自动删除广告消息
async def delete_message(update: Update, context: CallbackContext):
    try:
        await context.bot.delete_message(chat_id=update.effective_chat.id, message_id=update.message.message_id)
    except Exception as e:
        logger.error(f"处理消息时出错:{e}")


# 自动回复
async def send_auto_reply(update: Update, context: CallbackContext, reply_text):
    first_name = update.message.from_user.first_name
    username = update.message.from_user.username
    sender_id = update.message.from_user.id
    chat_id = update.message.chat_id
    
    if not reply_text:
        reply_text = f"抱歉用户 @{username or first_name} ,您的消息包含广告内容,已被屏蔽。请遵守群规,谢谢!"
    await context.bot.send_message(chat_id=chat_id, text=reply_text)
    
# ---------------------------------以下是api----------------------------------------

# 处理群消息
async def handle_message(update: Update, context: CallbackContext):
    username = update.message.from_user.username
    first_name = update.message.from_user.first_name
    message_text = update.message.text
    sender_id = update.message.from_user.id
    message_id = update.message.message_id
    chat_id = update.message.chat_id
    timestamp = update.message.date.timestamp()
    # 群组信息
    group_title = update.message.chat.title
    
    #检测权限
    if not (await handle_tool_permissions(update, context)):
        return
        
    if is_ad_message(message_text, sender_id, timestamp, chat_id):
        await delete_message(update, context)  # 删除广告消息
        log_blocked_ad(chat_id,group_title,username,first_name, message_id, message_text, sender_id, int(timestamp))  # 记录广告消息
        # 踢人命令,6个月内发送超过5次广告
        if check_user_frequency(sender_id, chat_id, timestamp,(60 * 24 * 30 * 6),5):
           await kick(update, context)
        elif check_user_frequency(sender_id, chat_id, timestamp,(60 * 24 * 30),4):
           # 禁言命令(5天),30天内发送超过4次广告
           await mute(update, context)
        elif check_user_frequency(sender_id, chat_id, timestamp,(60 * 24),3):
           # 检查频率限制,1天内发送超过3次广告
           await send_auto_reply(update, context,f"对用户 @{username or first_name} 严重警告!")
        else:
           await send_auto_reply(update, context,None)  # 发送
        
# 查询屏蔽广告统计
async def stats(update: Update, context: CallbackContext):
    #检测权限
    if not (await handle_tool_permissions(update, context,2)):
        return
    chat_id = update.message.chat_id
    blocked_count = get_blocked_stats(chat_id)
    await send_auto_reply(update, context,f"已屏蔽 {blocked_count} 条广告消息。")

# 将用户删除白名单
async def delwhitelist(update: Update, context: CallbackContext):
    chat_id = update.message.chat_id
    user_id = update.message.from_user.id
    #检测权限
    if not (await handle_tool_permissions(update, context,2)):
        return
    await delete_message(update, context)
    # 检查是否在白名单
    is_white = is_user_whitelisted(chat_id, user_id)
    if is_white:
        conn = sqlite3.connect('blocked_ads.db')
        c = conn.cursor()
        c.execute('DELETE FROM whitelist WHERE chat_id=?', (chat_id,))
        c.execute('DELETE FROM tokenlist WHERE chat_id=?', (chat_id,))
        c.execute('DELETE FROM blocked_ads WHERE chat_id=?', (chat_id,))
        conn.commit()
        conn.close()
        await send_auto_reply(update, context,f"已将群广告拦截取消,如需再次使用请重新购买。")
    else:
        await send_auto_reply(update, context,f"您非购买人,只有购买人才能取消。")

# 添加全局的关键字黑名单
async def setadminwhite(update: Update, context: CallbackContext):
    chat_id = update.message.chat_id
    user_id = update.message.from_user.id
    group_type = update.message.chat.type
    if "group" in group_type:
        return
    # 判断有没有参数
    if not context.args:
        await update.message.reply_text("❗请提供过滤黑名单值")
        return
    # 获取第一个参数作为 过滤值
    val = context.args[0]
    is_token = is_tool_token(val,0)
    if is_token:
        print(f" 为群黑名单无需再次添加: {val}")
        return
    addtooltoken(0,chat_id, user_id,val)
    print(f" 添加全局的关键字黑名单: {val}")

# 为群添加关键字黑名单
async def setwhite(update: Update, context: CallbackContext):
    chat_id = update.message.chat_id
    user_id = update.message.from_user.id
    group_type = update.message.chat.type
    if "group" not in group_type:
        return
    # 检查是否在白名单,如果不在白名单内,则跳过广告屏蔽
    if not is_user_whitelisted(chat_id,None):
        return
    # 判断目标用户是否是管理员
    member = await context.bot.get_chat_member(chat_id, user_id)
    if member.status not in ['administrator', 'creator']:
        return
    # 判断有没有参数
    if not context.args:
        await update.message.reply_text("❗请提供过滤黑名单值")
        return
    # 获取第一个参数作为 过滤值
    val = context.args[0]
    is_token = is_tool_token(val,2,chat_id)
    if is_token:
        print(f" 为群黑名单无需再次添加: {val}")
        return
    addtooltoken(2,chat_id, user_id,val)
    print(f" 为群添加关键字黑名单: {val}")
 
#生成群白名单token
async def whitekey(update: Update, context: CallbackContext):
    # 判断有没有参数
    if not context.args:
        await update.message.reply_text("❗请提供购买的令牌,例如:/whitekey YOUR_TOKEN")
        return
    # 获取第一个参数作为 token
    user_token = context.args[0]
    #生成群白名单token
    if (await whitelist(update, context,user_token)):
        return
    
# 添加群权限令牌
async def settooltoken(update: Update, context: CallbackContext):
    chat_id = update.message.chat_id
    user_id = update.message.from_user.id
    group_type = update.message.chat.type
    if "group" in group_type:
        return
    token = secrets.token_hex(16)
    addtooltoken(1,chat_id, user_id,token)
    await update.message.reply_text(f"✅ 权限令牌:/whitekey {token},让群管理员将权限令牌发送到需要加权限的群中,即可获取对应权限。", parse_mode="Markdown")

# 处理 /start 命令
async def start(update: Update, context: CallbackContext):
    await send_auto_reply(update, context,"Hi.I'm LookOn bot. I can filter ads or do somethings else.")


# 主函数:启动机器人并设置消息处理
def main():
    init_db()  # 初始化数据库
    application = Application.builder().token(TOKEN).build()

    # 消息处理:处理文本消息
    application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))

    # 添加 /start 命令的处理器
    application.add_handler(CommandHandler("start", start))
    # 处理 /stats 命令
    application.add_handler(CommandHandler("stats", stats))
    
    # 处理 /settooltoken 命令 获取token群消息广告拦截功能
    application.add_handler(CommandHandler("settooltoken", settooltoken))

    # 处理 /delwhitelist 命令
    application.add_handler(CommandHandler("delwhitelist", delwhitelist))
    # 处理 /whitekey 命令
    application.add_handler(CommandHandler("whitekey", whitekey))
    # 处理 /setadminwhite 命令
    application.add_handler(CommandHandler("setadminwhite", setadminwhite))
    # 处理 /setwhite 命令
    application.add_handler(CommandHandler("setwhite", setwhite))

    # 启动机器人
    application.run_polling()  # Don't use asyncio.run(main()) here


if __name__ == '__main__':
    main()

    编辑requirements.txt文件

    将项目所需的库列在 requirements.txt 中。

    python-telegram-bot

      编辑Dockerfile文件

      Dockerfile 用于构建应用容器并设置环境。

      # 使用官方 Python 镜像作为基础镜像
      FROM python:3.9-slim
      
      # 设置工作目录
      WORKDIR /app
      
      # 复制代码到容器内
      COPY /app /app
      
      # 安装依赖
      RUN pip install --upgrade pip
      RUN pip install --no-cache-dir -r requirements.txt
      RUN pip install --upgrade python-telegram-bot
      
      # 设置环境变量
      ENV PYTHONUNBUFFERED 1
      
      # 设置默认命令
      CMD ["python", "app.py"]
      

      编辑docker-compose.yml文件

      接下来,我们用 docker-compose 来简化 Docker 容器的管理。创建一个 docker-compose.yml 文件,用于定义和运行多个容器。

      version: '3'
      
      services:
        telegram-bot:
          build: /opt/adblocking
          container_name: telegram-bot
          restart: always
          environment:
            - TELEGRAM_TOKEN=234234:FTRARAWERWERW# 替换为你的 Telegram Bot Token
          volumes:
            - /opt/adblocking/app:/app
          ports:
            - "8088:8080"
      

      构建和启动 Docker 容器

      • 构建 Docker 镜像
        在项目根目录下运行以下命令来构建 Docker 镜像:

        docker-compose build
      • 启动 Docker 容器
        使用以下命令来启动应用:

        docker-compose up -d
        

      Telegram端使用的命令

      广告拦截的命令
      生成群广告拦截权限令牌(与机器人(@adtoolseniorBot)私聊):/settooltoken
      取消群广告拦截(在对应的群里使用):/delwhitelist
      添加全局黑名单关键字(与机器人(@adtoolseniorBot)私聊)  的例子:whitecmdadminblack=比特币
      单独为群添加黑名单关键字(在对应的群里使用)  的例子:whitecmdblack=比特币

      小结

      这个系统包含了以下功能:

      1. 广告检测规则:检测消息是否包含广告(关键词、链接、图片等)。

      2. 自动屏蔽广告:删除广告消息,并自动回复用户。

      3. 白名单功能:允许管理员将某些用户加入白名单,避免误屏蔽。

      4. 广告频率限制:避免频繁发送广告的用户被误屏蔽。

      5. 广告统计功能:可以查询被屏蔽广告的统计数据。

      你可以将这些功能容器化并通过 Docker Compose 方便地管理 Telegram 群广告屏蔽工具。

      评论
      添加红包

      请填写红包祝福语或标题

      红包个数最小为10个

      红包金额最低5元

      当前余额3.43前往充值 >
      需支付:10.00
      成就一亿技术人!
      领取后你会自动成为博主和红包主的粉丝 规则
      hope_wisdom
      发出的红包

      打赏作者

      快乐的小贞

      世纪的浪漫,最不过——雨落星辰

      ¥1 ¥2 ¥4 ¥6 ¥10 ¥20
      扫码支付:¥1
      获取中
      扫码支付

      您的余额不足,请更换扫码支付或充值

      打赏作者

      实付
      使用余额支付
      点击重新获取
      扫码支付
      钱包余额 0

      抵扣说明:

      1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
      2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

      余额充值