bot script
This commit is contained in:
153
bot.py
Normal file
153
bot.py
Normal file
@@ -0,0 +1,153 @@
|
||||
# discord_export_bot.py
|
||||
# This bot connects to a Discord server and exports the entire message
|
||||
# history from every accessible text channel into separate CSV files.
|
||||
|
||||
# Make sure to install the discord.py library first:
|
||||
# pip install discord.py
|
||||
|
||||
import discord
|
||||
import csv
|
||||
import os
|
||||
import asyncio
|
||||
|
||||
# --- Configuration ---
|
||||
# Place your Bot Token here. Treat this like a password!
|
||||
# It's recommended to use environment variables for security.
|
||||
BOT_TOKEN = "YOUR_BOT_TOKEN_HERE"
|
||||
|
||||
# The directory where the CSV files will be saved.
|
||||
# The script will create this directory if it doesn't exist.
|
||||
OUTPUT_DIRECTORY = "discord_chat_logs"
|
||||
# -------------------
|
||||
|
||||
|
||||
# --- Bot Setup ---
|
||||
# Define the necessary "Intents" for the bot. Intents tell Discord what
|
||||
# events your bot needs to receive. To read messages, we need the
|
||||
# `messages` and `message_content` intents. You MUST enable these
|
||||
# in the Discord Developer Portal for your bot.
|
||||
intents = discord.Intents.default()
|
||||
intents.guilds = True
|
||||
intents.messages = True
|
||||
intents.message_content = True # This is a privileged intent!
|
||||
|
||||
# Create the bot client instance with the specified intents.
|
||||
client = discord.Client(intents=intents)
|
||||
|
||||
# --- Main Export Logic ---
|
||||
async def export_channel_history(channel):
|
||||
"""
|
||||
Asynchronously fetches all messages from a given text channel
|
||||
and saves them to a CSV file.
|
||||
"""
|
||||
print(f"Starting export for channel: #{channel.name} (ID: {channel.id})")
|
||||
|
||||
# Sanitize channel name to create a valid filename
|
||||
# Replaces invalid file name characters with an underscore
|
||||
sanitized_channel_name = "".join(c if c.isalnum() else '_' for c in channel.name)
|
||||
file_path = os.path.join(OUTPUT_DIRECTORY, f"{sanitized_channel_name}.csv")
|
||||
|
||||
try:
|
||||
message_count = 0
|
||||
with open(file_path, 'w', newline='', encoding='utf-8') as csvfile:
|
||||
# Define the headers for the CSV file. This includes all the
|
||||
# useful information we can easily get from a message object.
|
||||
header = [
|
||||
'message_id', 'timestamp_utc', 'author_id', 'author_name',
|
||||
'author_nickname', 'content', 'attachment_urls', 'embeds'
|
||||
]
|
||||
writer = csv.DictWriter(csvfile, fieldnames=header)
|
||||
writer.writeheader()
|
||||
|
||||
# Fetch the channel's history. `limit=None` tells the library to
|
||||
# fetch all messages. This can take a very long time and consume
|
||||
# significant memory for channels with a large history.
|
||||
async for message in channel.history(limit=None):
|
||||
message_count += 1
|
||||
if message_count % 100 == 0:
|
||||
print(f" ... processed {message_count} messages in #{channel.name}")
|
||||
|
||||
# Extract attachment URLs
|
||||
attachment_urls = ", ".join([att.url for att in message.attachments])
|
||||
|
||||
# Serialize embed objects to a string representation (e.g., JSON)
|
||||
# This gives a detailed look into rich embeds.
|
||||
embeds_str = ", ".join([str(embed.to_dict()) for embed in message.embeds])
|
||||
|
||||
# Write the message data as a row in the CSV
|
||||
writer.writerow({
|
||||
'message_id': message.id,
|
||||
'timestamp_utc': message.created_at,
|
||||
'author_id': message.author.id,
|
||||
'author_name': message.author.name,
|
||||
'author_nickname': message.author.nick,
|
||||
'content': message.content,
|
||||
'attachment_urls': attachment_urls,
|
||||
'embeds': embeds_str
|
||||
})
|
||||
|
||||
print(f"✅ Finished exporting {message_count} messages from #{channel.name}.")
|
||||
return True
|
||||
|
||||
except discord.errors.Forbidden:
|
||||
print(f"❌ ERROR: Permission denied for channel #{channel.name}. Skipping.")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"❌ An unexpected error occurred for channel #{channel.name}: {e}")
|
||||
return False
|
||||
|
||||
# --- Bot Events ---
|
||||
@client.event
|
||||
async def on_ready():
|
||||
"""
|
||||
This event is triggered once the bot has successfully connected to Discord.
|
||||
"""
|
||||
print(f'Logged in as: {client.user.name} (ID: {client.user.id})')
|
||||
print('------')
|
||||
|
||||
# Create the output directory if it doesn't exist
|
||||
if not os.path.exists(OUTPUT_DIRECTORY):
|
||||
os.makedirs(OUTPUT_DIRECTORY)
|
||||
print(f"Created output directory: {OUTPUT_DIRECTORY}")
|
||||
|
||||
# Get the server (guild) the bot is in. This script assumes the bot
|
||||
# is only in ONE server. If it's in multiple, you may need to specify
|
||||
# which one to target.
|
||||
guild = client.guilds[0]
|
||||
if not guild:
|
||||
print("Error: Bot does not appear to be in any server.")
|
||||
await client.close()
|
||||
return
|
||||
|
||||
print(f"Targeting server: {guild.name} (ID: {guild.id})")
|
||||
|
||||
# Get a list of all text channels the bot can see
|
||||
text_channels = [channel for channel in guild.text_channels]
|
||||
print(f"Found {len(text_channels)} text channels to export.")
|
||||
|
||||
# Loop through each channel and run the export function
|
||||
for channel in text_channels:
|
||||
await export_channel_history(channel)
|
||||
# A small delay to be respectful to Discord's API, although
|
||||
# the library handles rate limiting automatically.
|
||||
await asyncio.sleep(1)
|
||||
|
||||
print('------')
|
||||
print("All channels have been processed. The bot will now shut down.")
|
||||
|
||||
# Shuts down the bot once the export is complete.
|
||||
await client.close()
|
||||
|
||||
# --- Run the Bot ---
|
||||
if __name__ == "__main__":
|
||||
if BOT_TOKEN == "YOUR_BOT_TOKEN_HERE":
|
||||
print("!!! ERROR: Please replace 'YOUR_BOT_TOKEN_HERE' with your actual bot token in the script.")
|
||||
else:
|
||||
try:
|
||||
# This starts the bot. The `on_ready` event will be called once it's connected.
|
||||
client.run(BOT_TOKEN)
|
||||
except discord.errors.LoginFailure:
|
||||
print("!!! ERROR: Login failed. The token is likely invalid or incorrect.")
|
||||
except Exception as e:
|
||||
print(f"!!! An error occurred while running the bot: {e}")
|
||||
|
||||
Reference in New Issue
Block a user