Перейти к содержимому
Все статьи
· Обновлено 15 февраля 2026 г.

Как отправить Discord Webhook с помощью Python

Практическое руководство по отправке сообщений через Discord webhook на Python. Обычный текст, embed-сообщения и файлы с библиотекой requests.

pythonwebhookтуториалdiscord apipython discord 2026библиотека requestsdiscord бот python
Как отправить Discord Webhook с помощью Python

Что такое Discord Webhook?

Discord webhook — это простой способ отправлять сообщения в канал Discord из внешних приложений. В отличие от бота, webhook не требует постоянного соединения или аутентификации с токеном — вы просто отправляете HTTP POST запрос на URL, и сообщение появляется в канале.

Webhook идеально подходит для:

  • Уведомлений — CI/CD пайплайны, мониторинг серверов, алерты об ошибках
  • Интеграций — подключение сторонних сервисов к Discord
  • Автоматизации — запланированные сообщения, обновления статуса, каналы данных

Требования

Вам понадобится Python 3.7+ и библиотека requests:

pip install requests

Шаг 1: Создайте Webhook в Discord

  1. Откройте ваш Discord сервер и перейдите в Настройки сервера
  2. Перейдите в ИнтеграцииВебхуки
  3. Нажмите Новый вебхук
  4. Выберите имя и канал, куда будут отправляться сообщения
  5. Нажмите Копировать URL вебхука

URL вебхука будет выглядеть примерно так:

https://discord.com/api/webhooks/1234567890/abcdefghijklmnop

Важно: Храните URL вебхука в секрете. Любой, у кого есть URL, может отправлять сообщения в ваш канал.

Шаг 2: Отправьте простое текстовое сообщение

Самый базовый запрос webhook отправляет обычное текстовое сообщение:

import requests

WEBHOOK_URL = "https://discord.com/api/webhooks/YOUR_WEBHOOK_URL"

data = {
    "content": "Привет из Python! 🐍"
}

response = requests.post(WEBHOOK_URL, json=data)

if response.status_code == 204:
    print("Сообщение отправлено успешно!")
else:
    print(f"Ошибка отправки: {response.status_code}")

Успешный запрос webhook возвращает статус код 204 No Content.

Шаг 3: Отправьте Embed-сообщение

Embed позволяют создавать красиво отформатированные сообщения с цветами, полями, изображениями и другим:

import requests
from datetime import datetime

WEBHOOK_URL = "https://discord.com/api/webhooks/YOUR_WEBHOOK_URL"

embed = {
    "title": "Отчёт о состоянии сервера",
    "description": "Все системы работают нормально.",
    "color": 5763719,  # Зелёный цвет в десятичном формате
    "fields": [
        {
            "name": "Загрузка CPU",
            "value": "23%",
            "inline": True
        },
        {
            "name": "Память",
            "value": "4.2 ГБ / 16 ГБ",
            "inline": True
        },
        {
            "name": "Время работы",
            "value": "14 дней, 6 часов",
            "inline": False
        }
    ],
    "footer": {
        "text": "Бот мониторинга"
    },
    "timestamp": datetime.utcnow().isoformat()
}

data = {
    "embeds": [embed]
}

response = requests.post(WEBHOOK_URL, json=data)
print(f"Статус: {response.status_code}")

Справка по цветам Embed

Цвета embed в Discord указываются как десятичные числа. Вот некоторые популярные:

  • Красный: 15548997 (#ED4245)
  • Зелёный: 5763719 (#57F287)
  • Синий: 5793266 (#5865F2 — Discord blurple)
  • Жёлтый: 16776960 (#FFFF00)
  • Белый: 16777215 (#FFFFFF)

Шаг 4: Отправка с кастомным именем и аватаром

Вы можете переопределить имя и аватар webhook для каждого сообщения:

data = {
    "content": "Деплой завершён! ✅",
    "username": "Deploy Bot",
    "avatar_url": "https://example.com/deploy-avatar.png"
}

response = requests.post(WEBHOOK_URL, json=data)

Шаг 5: Отправка файлов и вложений

Для отправки файлов используйте multipart/form-data вместо JSON:

import requests
import json

WEBHOOK_URL = "https://discord.com/api/webhooks/YOUR_WEBHOOK_URL"

# Данные сообщения
payload = {
    "content": "Вот последний лог-файл:"
}

# Файл для загрузки
with open("server.log", "rb") as f:
    files = {
        "payload_json": (None, json.dumps(payload), "application/json"),
        "file": ("server.log", f, "text/plain")
    }
    response = requests.post(WEBHOOK_URL, files=files)

print(f"Статус: {response.status_code}")

Лимиты запросов

Discord устанавливает лимиты на запросы webhook. Стандартные ограничения:

  • 5 запросов за 2 секунды на один webhook
  • 30 запросов за 60 секунд на один канал

При превышении лимитов вы получите ответ 429 Too Many Requests с полем retry_after:

import requests
import time

def send_webhook(url, data, max_retries=3):
    for attempt in range(max_retries):
        response = requests.post(url, json=data)

        if response.status_code == 204:
            return True

        if response.status_code == 429:
            retry_after = response.json().get("retry_after", 1)
            print(f"Лимит превышен. Повторная попытка через {retry_after}с...")
            time.sleep(retry_after)
            continue

        print(f"Ошибка: {response.status_code}")
        return False

    return False

Полный пример: Скрипт мониторинга

Вот практический пример — скрипт, который мониторит сайт и отправляет алерты в Discord:

import requests
import time
from datetime import datetime

WEBHOOK_URL = "https://discord.com/api/webhooks/YOUR_WEBHOOK_URL"
TARGET_URL = "https://example.com"
CHECK_INTERVAL = 60  # секунды

def check_website():
    try:
        response = requests.get(TARGET_URL, timeout=10)
        return response.status_code, response.elapsed.total_seconds()
    except requests.RequestException as e:
        return None, str(e)

def send_alert(status, details):
    is_up = status and status == 200
    color = 5763719 if is_up else 15548997

    embed = {
        "title": f"{'✅' if is_up else '🔴'} {TARGET_URL}",
        "description": f"Статус: **{status or 'НЕДОСТУПЕН'}**",
        "color": color,
        "fields": [
            {"name": "Детали", "value": str(details), "inline": False}
        ],
        "timestamp": datetime.utcnow().isoformat()
    }

    requests.post(WEBHOOK_URL, json={"embeds": [embed]})

if __name__ == "__main__":
    print(f"Мониторинг {TARGET_URL}...")
    last_status = None

    while True:
        status, details = check_website()
        if status != last_status:
            send_alert(status, details)
            last_status = status
        time.sleep(CHECK_INTERVAL)

Что дальше

Теперь, когда вы знаете, как отправлять webhook-сообщения с Python, вы можете:

  • Создавать автоматизированные системы уведомлений
  • Делать кастомные интеграции для вашего Discord сервера
  • Настраивать отложенные сообщения для автоматической отправки по расписанию
  • Добавлять опросы для сбора обратной связи от команды
  • Использовать наш визуальный конструктор webhook для создания сложных embed-макетов, а затем экспортировать JSON и отправлять из ваших Python-скриптов

Discord Webhook Builder позволяет визуально проектировать сообщения перед кодированием автоматизации.

Обработка ошибок и отказоустойчивость

В продакшн-коде недостаточно просто отправить запрос и проверить статус-код. Сеть ненадежна: соединение может оборваться, сервер Discord может временно не отвечать, а DNS-резолвинг — зависнуть. Грамотная обработка ошибок — обязательная часть любой автоматизации, особенно если вы строите паттерны автоматизации для критически важных систем.

Библиотека requests предоставляет иерархию исключений, которые стоит обрабатывать по отдельности:

import requests
import time

def send_with_retry(url, data, max_retries=5):
    """Отправка webhook с экспоненциальной задержкой при ошибках."""
    for attempt in range(max_retries):
        try:
            response = requests.post(url, json=data, timeout=10)
            response.raise_for_status()

            if response.status_code == 204:
                return True

            # Обработка rate limit
            if response.status_code == 429:
                retry_after = response.json().get("retry_after", 1)
                time.sleep(retry_after)
                continue

        except requests.exceptions.ConnectionError:
            print(f"[Попытка {attempt + 1}] Нет соединения с сервером")
        except requests.exceptions.Timeout:
            print(f"[Попытка {attempt + 1}] Превышено время ожидания")
        except requests.exceptions.HTTPError as e:
            print(f"[Попытка {attempt + 1}] HTTP ошибка: {e.response.status_code}")
            # Не повторяем при клиентских ошибках 4xx (кроме 429)
            if 400 <= e.response.status_code < 500:
                return False
        except requests.exceptions.RequestException as e:
            print(f"[Попытка {attempt + 1}] Неизвестная ошибка: {e}")

        # Экспоненциальная задержка: 1с, 2с, 4с, 8с, 16с
        delay = 2 ** attempt
        print(f"Повторная попытка через {delay}с...")
        time.sleep(delay)

    print("Все попытки исчерпаны")
    return False

Ключевые принципы: всегда устанавливайте timeout в requests.post(), чтобы вызов не зависал бесконечно. Используйте экспоненциальную задержку (exponential backoff), чтобы не перегружать сервер повторными запросами. И разделяйте клиентские ошибки (4xx) от серверных (5xx) — повторная попытка при неправильном JSON не имеет смысла, а вот при временной недоступности сервера Discord — вполне оправдана.

Асинхронные вебхуки с aiohttp

Если вам нужно отправлять сообщения в несколько каналов одновременно или ваш скрипт уже использует асинхронный код, синхронная библиотека requests станет узким местом. Каждый вызов requests.post() блокирует выполнение, пока не придет ответ, и при отправке в десять каналов подряд общее время растет линейно.

Библиотека aiohttp решает эту проблему через async/await:

pip install aiohttp
import aiohttp
import asyncio

WEBHOOK_URLS = [
    "https://discord.com/api/webhooks/CHANNEL_1_URL",
    "https://discord.com/api/webhooks/CHANNEL_2_URL",
    "https://discord.com/api/webhooks/CHANNEL_3_URL",
]

async def send_webhook(session, url, data):
    """Отправка одного webhook асинхронно."""
    try:
        async with session.post(url, json=data, timeout=aiohttp.ClientTimeout(total=10)) as resp:
            if resp.status == 204:
                print(f"Отправлено в {url[-8:]}...")
                return True
            else:
                print(f"Ошибка {resp.status} для {url[-8:]}...")
                return False
    except asyncio.TimeoutError:
        print(f"Таймаут для {url[-8:]}...")
        return False

async def broadcast(message, embeds=None):
    """Отправка сообщения во все каналы одновременно."""
    data = {"content": message}
    if embeds:
        data["embeds"] = embeds

    async with aiohttp.ClientSession() as session:
        tasks = [send_webhook(session, url, data) for url in WEBHOOK_URLS]
        results = await asyncio.gather(*tasks)

    success = sum(results)
    print(f"Доставлено: {success}/{len(WEBHOOK_URLS)}")
    return results

# Запуск
asyncio.run(broadcast("Внимание: плановые работы через 30 минут"))

Функция asyncio.gather() запускает все запросы параллельно. Если синхронная отправка в три канала занимает ~3 секунды (по секунде на каждый), то асинхронная — около 1 секунды. Разница становится особенно заметной при работе с embed-сообщениями: подробнее о форматировании эмбедов и доступных цветовых кодах.

Безопасность

URL вебхука — это, по сути, ключ доступа к вашему каналу. Любой, кто его получит, может отправлять произвольные сообщения. Поэтому хранить URL в коде или коммитить его в git-репозиторий — серьезная ошибка.

Используйте переменные окружения:

import os
import requests

WEBHOOK_URL = os.environ.get("DISCORD_WEBHOOK_URL")

if not WEBHOOK_URL:
    raise ValueError("Переменная DISCORD_WEBHOOK_URL не задана")

requests.post(WEBHOOK_URL, json={"content": "Безопасная отправка"})

Для локальной разработки удобно использовать файл .env с библиотекой python-dotenv:

pip install python-dotenv
from dotenv import load_dotenv
import os

load_dotenv()  # Загружает переменные из .env файла
WEBHOOK_URL = os.getenv("DISCORD_WEBHOOK_URL")

Файл .env:

DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/1234567890/abcdefg

Обязательно добавьте .env в .gitignore, чтобы случайно не опубликовать URL в открытый репозиторий. Если URL все-таки утек, немедленно удалите вебхук в настройках Discord и создайте новый.

Тестирование и отладка

Во время разработки не стоит спамить в рабочий канал Discord при каждом запуске скрипта. Для тестирования структуры запроса можно использовать сервис httpbin.org, который просто возвращает то, что вы ему отправили:

import requests
import json

TEST_URL = "https://httpbin.org/post"

data = {
    "content": "Тестовое сообщение",
    "embeds": [{"title": "Тест", "color": 5793266}]
}

response = requests.post(TEST_URL, json=data)
print(json.dumps(response.json(), indent=2, ensure_ascii=False))

Это позволяет проверить корректность JSON-структуры перед отправкой в Discord. Для валидации embed-сообщений убедитесь, что все обязательные поля заполнены: Discord молча отбросит embed без title или description. Также создайте отдельный тестовый канал на вашем сервере — это лучший способ тестировать интеграцию без риска засорить рабочие каналы.

Помимо кода, discord-webhook.com предлагает визуальный конструктор с такими функциями как отложенные сообщения, поддержка тредов и форумов, опросы и интерактивные кнопки с действиями — всё без написания кода.

Похожие статьи

Попробуйте в нашем инструменте

Открыть конструктор Discord Webhook