ВКонтакте
vk.com/hahasorryidie →
Коротко обо мне и все порталы, где меня можно найти
Разработчик на Python. Пишу код для автоматизации, создаю приложения и решаю сложные задачи. Интересуюсь веб-разработкой, скрейпингом и программированием в целом.
Проекты на Python, которыми я горжусь
Современный портфолио-сайт на чистом HTML/CSS/JavaScript с темной темой, адаптивным дизайном и интеграцией API ВКонтакте для отображения текущей музыки. Развернут на собственном VDS с HTTPS и кастомным доменом.
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Портфолио | onxml.fun</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;500;600;700&display=swap" rel="stylesheet" />
<style>
:root {
color-scheme: dark;
--bg-1: #05030f;
--bg-2: #0f1a45;
--accent: #6a7bff;
--accent-2: #42e8e0;
--text-main: #f5f8ff;
--text-muted: rgba(245, 248, 255, 0.7);
--card-bg: rgba(255, 255, 255, 0.05);
--border: rgba(255, 255, 255, 0.12);
--glow: 0 10px 40px rgba(80, 131, 255, 0.15);
}
* { box-sizing: border-box; }
body {
margin: 0;
font-family: "Inter", system-ui, sans-serif;
min-height: 100vh;
background: radial-gradient(circle at top, var(--bg-2), var(--bg-1) 40%);
color: var(--text-main);
overflow-x: hidden;
}
main {
position: relative;
padding: 80px 24px;
max-width: 960px;
margin: 0 auto;
}
header {
text-align: center;
margin-bottom: 60px;
}
h1 {
font-size: clamp(2.5rem, 6vw, 4.2rem);
margin: 0 0 16px;
letter-spacing: -0.03em;
}
.card {
position: relative;
padding: 24px;
background: var(--card-bg);
border: 1px solid var(--border);
border-radius: 24px;
backdrop-filter: blur(12px);
box-shadow: var(--glow);
overflow: hidden;
transition: transform 0.5s ease, border-color 0.5s ease;
}
.card:hover {
transform: translateY(-8px);
border-color: rgba(88, 119, 255, 0.9);
}
.card-icon {
width: 48px;
height: 48px;
border-radius: 16px;
background: rgba(255, 255, 255, 0.06);
display: inline-flex;
align-items: center;
justify-content: center;
margin-bottom: 18px;
font-size: 24px;
}
.card-title {
font-size: 1.2rem;
margin: 0 0 6px;
font-weight: 600;
}
.contact-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 24px;
margin-top: 48px;
}
nav {
display: flex;
gap: 24px;
justify-content: space-between;
margin-bottom: 60px;
align-items: center;
flex-wrap: wrap;
}
nav > div:first-child {
display: flex;
gap: 24px;
}
nav a {
text-decoration: none;
color: var(--text-main);
font-weight: 600;
padding: 8px 16px;
border-radius: 8px;
transition: background 0.3s ease;
}
nav a.active {
color: var(--accent-2);
background: rgba(66, 232, 224, 0.12);
}
.language-switcher {
display: flex;
gap: 8px;
align-items: center;
background: transparent;
border: 1px solid rgba(106, 123, 255, 0.4);
border-radius: 999px;
padding: 6px 12px;
}
.lang-btn {
padding: 8px 14px;
border: none;
background: transparent;
color: var(--text-muted);
border-radius: 999px;
cursor: pointer;
font-weight: 600;
font-size: 0.85rem;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.lang-btn:hover {
color: var(--accent-2);
}
.lang-btn.active {
background: rgba(106, 123, 255, 0.25);
color: var(--accent-2);
box-shadow: inset 0 0 12px rgba(106, 123, 255, 0.2);
border: 1px solid rgba(106, 123, 255, 0.5);
}
.lang-toggle {
display: flex;
gap: 8px;
align-items: center;
background: transparent;
border: 1px solid rgba(106, 123, 255, 0.4);
border-radius: 999px;
padding: 6px 12px;
}
.page { display: none; }
.page.active { display: block; }
@media (max-width: 600px) {
main { padding-top: 60px; }
.card { padding: 20px; }
}
</style>
</head>
<body>
<main>
<nav>
<div>
<a href="#" class="nav-link active" data-page="contacts" data-i18n="nav-contacts">Контакты</a>
<a href="#" class="nav-link" data-page="works" data-i18n="nav-works">Работы</a>
</div>
<div class="language-switcher">
<button class="lang-btn active" onclick="changeLanguage('ru')" data-lang="ru">РУ</button>
<button class="lang-btn" onclick="changeLanguage('en')" data-lang="en">EN</button>
</div>
</nav>
<div id="contacts" class="page active">
<header>
<h1 data-i18n="title">Всегда на связи</h1>
<p data-i18n="subtitle">Коротко обо мне и все порталы, где меня можно найти</p>
</header>
<div class="contact-grid">
<a href="https://vk.com/hahasorryidie" target="_blank" class="card-wrapper">
<article class="card">
<div class="card-icon">VK</div>
<h2 class="card-title" data-i18n="vk-title">ВКонтакте</h2>
<p data-i18n="vk-desc">vk.com/hahasorryidie →</p>
</article>
</a>
<a href="https://t.me/jzdox" target="_blank" class="card-wrapper">
<article class="card">
<div class="card-icon">TG</div>
<h2 class="card-title" data-i18n="tg-title">Telegram</h2>
<p data-i18n="tg-desc">t.me/jzdox →</p>
</article>
</a>
<a href="mailto:doxmepls@mail.ru" class="card-wrapper">
<article class="card">
<div class="card-icon">@</div>
<h2 class="card-title" data-i18n="mail-title">Почта</h2>
<p data-i18n="mail-desc">doxmepls@mail.ru →</p>
</article>
</a>
</div>
</div>
<div id="works" class="page">
<header>
<h1 data-i18n="works-title">Мои работы</h1>
</header>
</div>
</main>
<script>
document.querySelectorAll('.nav-link').forEach(link => {
link.addEventListener('click', (e) => {
e.preventDefault();
const page = link.dataset.page;
document.querySelectorAll('.nav-link').forEach(l => l.classList.remove('active'));
document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));
link.classList.add('active');
document.getElementById(page).classList.add('active');
});
});
</script>
</body>
</html>
Полнофункциональный Telegram бот на Python с системой управления пользователями, ролями, мини-игры, магазин товаров, администраторская панель и база данных SQLite.
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import Application, CommandHandler, CallbackQueryHandler
import sqlite3
import logging
from datetime import datetime, timedelta
# Конфигурация
BOT_TOKEN = "YOUR_BOT_TOKEN_HERE"
ADMIN_IDS = [YOUR_ADMIN_ID]
DATABASE_NAME = "bot_database.db"
# Система ролей
ROLES = {
"member": {"name": "👤 Участник", "level": 1},
"vip": {"name": "⭐ VIP", "level": 2, "permissions": ["fast_chat"]},
"premium": {"name": "💎 Премиум", "level": 3, "permissions": ["fast_chat", "extra_coins"]},
"moderator": {"name": "🛡️ Модератор", "level": 4, "permissions": ["warn_users"]},
"admin": {"name": "👑 Админ", "level": 5, "permissions": ["all"]}
}
def init_database():
"""Инициализация базы данных"""
conn = sqlite3.connect(DATABASE_NAME)
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
user_id INTEGER PRIMARY KEY,
username TEXT,
first_name TEXT,
coins INTEGER DEFAULT 0,
role TEXT DEFAULT 'member',
warnings INTEGER DEFAULT 0,
message_count INTEGER DEFAULT 0,
join_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''')
conn.commit()
conn.close()
def add_user(user_id, username, first_name):
"""Добавляет пользователя в БД"""
conn = sqlite3.connect(DATABASE_NAME)
cursor = conn.cursor()
role = "admin" if user_id in ADMIN_IDS else "member"
cursor.execute('''
INSERT OR IGNORE INTO users (user_id, username, first_name, role)
VALUES (?, ?, ?, ?)
''', (user_id, username, first_name, role))
conn.commit()
conn.close()
def get_user_role(user_id):
"""Получает роль пользователя"""
conn = sqlite3.connect(DATABASE_NAME)
cursor = conn.cursor()
cursor.execute('SELECT role FROM users WHERE user_id = ?', (user_id,))
result = cursor.fetchone()
conn.close()
return result[0] if result else "member"
def add_coins(user_id, amount):
"""Добавляет монеты"""
conn = sqlite3.connect(DATABASE_NAME)
cursor = conn.cursor()
cursor.execute('UPDATE users SET coins = coins + ? WHERE user_id = ?', (amount, user_id))
conn.commit()
conn.close()
async def start(update: Update, context):
user = update.effective_user
add_user(user.id, user.username, user.first_name)
keyboard = [
[InlineKeyboardButton("📋 Информация", callback_data="info")],
[InlineKeyboardButton("🎮 Мини-игры", callback_data="games")],
[InlineKeyboardButton("🛍️ Магазин", callback_data="shop")],
[InlineKeyboardButton("👥 Профиль", callback_data="profile")]
]
reply_markup = InlineKeyboardMarkup(keyboard)
await update.message.reply_text(
f"Привет, {user.first_name}! 👋\nДобро пожаловать в улучшенного бота!",
reply_markup=reply_markup
)
async def button_handler(update: Update, context):
query = update.callback_query
await query.answer()
if query.data == "info":
await query.edit_message_text("ℹ️ Информация о боте...")
def main():
init_database()
application = Application.builder().token(BOT_TOKEN).build()
application.add_handler(CommandHandler("start", start))
application.add_handler(CallbackQueryHandler(button_handler))
application.run_polling()
if __name__ == "__main__":
main()
Сложный парсер на Python с авторизацией на сайте, обработкой OAuth, парсингом HTML, системой управления пользователями, уведомлениями в Telegram и автоматическими обновлениями.
from bs4 import BeautifulSoup
import requests
import json
import logging
from datetime import datetime, timedelta
from urllib.parse import urljoin
import telebot
import schedule
import threading
import os
# Конфигурация
BOT_TOKEN = "YOUR_BOT_TOKEN_HERE"
ADMIN_CHAT_ID = "YOUR_ADMIN_ID"
WEBSITE_URL = "https://cabinet.vvsu.ru/time-table/"
LOGIN_URL = "https://cabinet.vvsu.ru/sign-in"
class VVGUScheduleParser:
def __init__(self):
self.session = requests.Session()
self.is_authenticated = False
self.cookie_file = "vvgu_cookies.json"
self.session.headers.update({
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'
})
def login(self):
"""Авторизация на сайте с обработкой OAuth"""
try:
logger.info("🔐 Начало авторизации...")
login_page = self.session.get(LOGIN_URL)
soup = BeautifulSoup(login_page.content, 'html.parser')
# Ищем форму входа
form = soup.find('form')
if not form:
logger.error("❌ Форма входа не найдена")
return False
# Собираем данные формы
login_data = {}
hidden_inputs = form.find_all('input', type='hidden')
for hidden in hidden_inputs:
name = hidden.get('name')
value = hidden.get('value', '')
if name:
login_data[name] = value
# Ищем поля логина и пароля
username_field = form.find('input', {
'name': lambda x: x and any(word in x.lower()
for word in ['username', 'login', 'email'])
})
password_field = form.find('input', {'type': 'password'})
if username_field and password_field:
login_data[username_field.get('name')] = "YOUR_USERNAME"
login_data[password_field.get('name')] = "YOUR_PASSWORD"
action_url = form.get('action', '')
if action_url:
action_url = urljoin(LOGIN_URL, action_url)
else:
action_url = LOGIN_URL
# Отправляем запрос на авторизацию
headers = {'Referer': LOGIN_URL}
response = self.session.post(action_url, data=login_data,
headers=headers, allow_redirects=True)
# Обработка OAuth редиректа
if 'fort.vvsu.ru' in response.url:
return self._handle_oauth_redirect(response)
return self._check_auth_success(response)
except Exception as e:
logger.error(f"❌ Ошибка при авторизации: {e}")
return False
def _handle_oauth_redirect(self, response):
"""Обрабатывает OAuth редирект"""
try:
soup = BeautifulSoup(response.content, 'html.parser')
form = soup.find('form')
if not form:
return False
oauth_data = {}
for hidden in form.find_all('input', type='hidden'):
name = hidden.get('name')
if name:
oauth_data[name] = hidden.get('value', '')
oauth_url = form.get('action', '')
if not oauth_url.startswith('http'):
oauth_url = urljoin(response.url, oauth_url)
oauth_response = self.session.post(oauth_url, data=oauth_data,
allow_redirects=True)
return self._check_auth_success(oauth_response)
except Exception as e:
logger.error(f"❌ Ошибка OAuth: {e}")
return False
def parse_schedule(self):
"""Парсит расписание"""
try:
logger.info("📖 Получение расписания...")
response = self.session.get(WEBSITE_URL)
soup = BeautifulSoup(response.content, 'html.parser')
schedule_data = self._extract_schedule_data(soup)
return schedule_data
except Exception as e:
logger.error(f"❌ Ошибка парсинга: {e}")
return None
def _extract_schedule_data(self, soup):
"""Извлекает данные расписания"""
schedule_data = []
tables = soup.find_all('table')
for table in tables:
rows = table.find_all('tr')
for row in rows:
cells = row.find_all(['td', 'th'])
if cells:
schedule_data.append([cell.get_text(strip=True) for cell in cells])
return schedule_data
def format_message(self, schedule_data):
"""Форматирует сообщение"""
if not schedule_data:
return "📭 Расписание не найдено"
message = "🎓 Расписание ВВГУ\n\n"
for row in schedule_data[:10]:
message += " | ".join(row[:3]) + "\n"
return message
# Инициализация
parser = VVGUScheduleParser()
bot = telebot.TeleBot(BOT_TOKEN)
def send_schedule():
"""Отправляет расписание"""
schedule_data = parser.parse_schedule()
message = parser.format_message(schedule_data)
bot.send_message(ADMIN_CHAT_ID, message, parse_mode='HTML')
# Расписание обновлений
schedule.every().day.at("07:00").do(send_schedule)
schedule.every().day.at("12:00").do(send_schedule)
schedule.every().day.at("17:00").do(send_schedule)
def run_scheduler():
"""Запускает планировщик"""
while True:
schedule.run_pending()
if __name__ == "__main__":
scheduler_thread = threading.Thread(target=run_scheduler, daemon=True)
scheduler_thread.start()
bot.infinity_polling()