You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Flask的Telegram Bot对接VirusTotal轮询逻辑失效求助

问题描述

我开发了一个基于Flask的Telegram Bot宠物项目,功能是接收用户发送的文件或哈希值,提交到VirusTotal进行检测,并返回详细的检测报告。但发送VirusTotal从未检测过的文件时,Bot会返回An error occurred while checking the file on VirusTotal错误。我推测是VirusTotal还没完成检测就收到了GET请求,于是添加了response_code=0时等待10秒并重发请求的循环逻辑,但问题仍未解决。作为Python新手,恳请帮忙排查问题。

现有代码
# Import required modules
import requests
import hashlib
import time
from flask import Flask, request

# Set bot token and VirusTotal API key
BOT_TOKEN = ''

# define the VirusTotal API key
VT_API_KEY = ''

# Create Flask app
app = Flask(__name__)

# Function to handle incoming messages
def handle_message(message):
    chat_id = message['chat']['id']
    # Check if message contains a document
    if 'document' in message:
        file_id = message['document']['file_id']
        file_url = f'https://api.telegram.org/bot{BOT_TOKEN}/getFile?file_id={file_id}'
        response = requests.get(file_url)
        if not response.ok:
            send_message(chat_id, 'An error occurred while downloading the file')
            return
        file_path = response.json().get('result', {}).get('file_path')
        if not file_path:
            send_message(chat_id, 'An error occurred while retrieving the file path')
            return
        file_url = f'https://api.telegram.org/file/bot{BOT_TOKEN}/{file_path}'
        # Download file content
        response = requests.get(file_url)
        if not response.ok:
            send_message(chat_id, 'An error occurred while downloading the file content')
            return
        content = response.content
        # Compute file hash
        file_hash = hashlib.sha256(content).hexdigest()
        # 保存文件内容,用于后续上传(如果需要)
        downloaded_file = content
    # If message doesn't contain a document, assume it contains a hash
    else:
        file_hash = message['text']
        downloaded_file = None
        # If hash is not of length 32 or 64, compute hash of hash value
        if len(file_hash) not in (32, 64):
            file_hash = hashlib.sha256(file_hash.encode()).hexdigest()
    # Build VirusTotal URL for file report
    vt_report_url = f'https://www.virustotal.com/vtapi/v2/file/report?apikey={VT_API_KEY}&resource={file_hash}'
    # Query VirusTotal for file report
    vt_response = requests.get(vt_report_url).json()
    
    # 处理资源不存在的情况(response_code=0)
    if vt_response.get('response_code') == 0:
        # 如果是用户上传的文件,尝试上传到VirusTotal
        if downloaded_file is not None:
            vt_upload_url = 'https://www.virustotal.com/vtapi/v2/file/scan'
            upload_data = {'apikey': VT_API_KEY}
            upload_files = {'file': ('uploaded_file', downloaded_file)}
            upload_response = requests.post(vt_upload_url, data=upload_data, files=upload_files).json()
            
            # 检查上传是否成功
            if upload_response.get('response_code') == 1:
                scan_id = upload_response.get('scan_id')
                # 循环等待检测完成
                while True:
                    vt_response = requests.get(f'https://www.virustotal.com/vtapi/v2/file/report?apikey={VT_API_KEY}&resource={scan_id}').json()
                    if vt_response.get('response_code') == 1:
                        break
                    # 免费版API有请求频率限制,不要太频繁
                    time.sleep(15)
            else:
                send_message(chat_id, 'Failed to upload file to VirusTotal')
                return
        else:
            # 如果是哈希且不存在,提示用户
            send_message(chat_id, 'This hash is not found in VirusTotal database')
            return
    
    # Check if file report was retrieved successfully
    if vt_response.get('response_code') == 1:
        positives = vt_response.get('positives')
        total = vt_response.get('total')
        permalink = vt_response.get('permalink')
        # If file is clean, send response indicating clean status and include detailed report URL
        if positives == 0:
            response_text = f'The file has been checked on VirusTotal and is clean ({total} scans). Here is the detailed report: {permalink}'
        # If file is malicious, send response indicating malicious status and include detailed report URL
        else:
            response_text = f'The file has been checked on VirusTotal and is malicious ({positives}/{total} detections). Here is the detailed report: {permalink}'
    # If file report couldn't be retrieved, send error response
    else:
        response_text = 'An error occurred while checking the file on VirusTotal'
    # Send response message to user
    send_message(chat_id, response_text)

# Function to send message to Telegram
def send_message(chat_id, text):
    url = f'https://api.telegram.org/bot{BOT_TOKEN}/sendMessage?chat_id={chat_id}&text={text}'
    requests.post(url)

# define a route to receive incoming Telegram messages
@app.route('/', methods=['POST'])
def receive_message():
    message = request.json['message']
    if 'document' in message or ('text' in message and len(message['text']) in (32, 64)):
        handle_message(message)
    return 'OK'

# run the Flask app
if __name__ == '__main__':
    app.run(host="0.0.0.0", port=5000)
关键修改点说明
  1. 核心逻辑修正:VirusTotal返回response_code=0不是检测未完成,而是该资源在数据库中不存在。此时如果是用户上传的文件,需要先调用文件上传API(/file/scan)将文件提交到VT,再用返回的scan_id轮询报告。
  2. 保存文件内容:在下载文件后保存downloaded_file变量,用于后续上传操作。
  3. 上传处理:添加文件上传逻辑,上传成功后用scan_id循环查询报告,直到response_code=1(报告就绪)。
  4. 哈希不存在的提示:如果用户输入的哈希在VT数据库中不存在,直接提示用户,避免无效循环。
  5. 请求频率控制:将等待时间调整为15秒,适配VirusTotal免费版API的请求限制(每分钟最多4次请求)。
额外注意事项
  • 确保BOT_TOKEN和VT_API_KEY已正确填写,VirusTotal免费版API有请求次数限制,超过会返回429错误,可添加错误处理逻辑重试。
  • 大文件上传可能需要更长时间,可根据实际情况调整等待间隔。

内容的提问来源于stack exchange,提问作者shamil guseynov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 12:29:55