Переезд
This commit is contained in:
commit
fa59858590
3 changed files with 176 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
env/
|
||||||
173
news_tgbot.py
Executable file
173
news_tgbot.py
Executable file
|
|
@ -0,0 +1,173 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from telegram import Update, ReplyKeyboardMarkup, InlineKeyboardMarkup, InlineKeyboardButton
|
||||||
|
from telegram.ext import ApplicationBuilder, CommandHandler, MessageHandler, CallbackQueryHandler, filters, ContextTypes
|
||||||
|
import vk_api
|
||||||
|
import time
|
||||||
|
|
||||||
|
# Введите ваши токены
|
||||||
|
TELEGRAM_TOKEN = 'ВАШ_ТОКЕН'
|
||||||
|
VK_ACCESS_TOKEN = 'ВАШ_ОТКРЫТЫЙ_ТОКЕН'
|
||||||
|
GROUP_IDS = [
|
||||||
|
('ID 1', 'Название группы 1'),
|
||||||
|
('ID 2', 'Название группы 2')
|
||||||
|
] # Список ID групп ВКонтакте
|
||||||
|
|
||||||
|
# Логирование
|
||||||
|
logging.basicConfig(
|
||||||
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||||
|
level=logging.INFO
|
||||||
|
)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Функция для получения новостей из конкретной группы ВКонтакте
|
||||||
|
def get_vk_news(group_id, group_name):
|
||||||
|
vk_session = vk_api.VkApi(token=VK_ACCESS_TOKEN)
|
||||||
|
vk = vk_session.get_api()
|
||||||
|
news = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
if group_id.isdigit():
|
||||||
|
response = vk.wall.get(owner_id=f'-{group_id}', count=5) # Используем owner_id
|
||||||
|
else:
|
||||||
|
response = vk.wall.get(domain=group_id, count=5) # Используем domain
|
||||||
|
for item in response['items']:
|
||||||
|
post = {
|
||||||
|
'text': item['text'],
|
||||||
|
'group_name': group_name,
|
||||||
|
'owner_id': item['owner_id'],
|
||||||
|
'post_id': item['id'],
|
||||||
|
'date': item['date'], # Добавляем дату публикации
|
||||||
|
'photos': []
|
||||||
|
}
|
||||||
|
|
||||||
|
# Проверяем наличие фотографий в посте
|
||||||
|
if 'attachments' in item:
|
||||||
|
for attachment in item['attachments']:
|
||||||
|
if attachment['type'] == 'photo':
|
||||||
|
max_size_photo = max(attachment['photo']['sizes'], key=lambda size: size['width'] * size['height'])
|
||||||
|
post['photos'].append(max_size_photo['url'])
|
||||||
|
|
||||||
|
news.append(post)
|
||||||
|
except vk_api.exceptions.ApiError as e:
|
||||||
|
logger.error(f"Ошибка при получении новостей для группы {group_id}: {e}")
|
||||||
|
|
||||||
|
return news
|
||||||
|
|
||||||
|
# Функция для получения комментариев поста из ВКонтакте
|
||||||
|
def get_vk_comments(owner_id, post_id):
|
||||||
|
vk_session = vk_api.VkApi(token=VK_ACCESS_TOKEN)
|
||||||
|
vk = vk_session.get_api()
|
||||||
|
comments = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = vk.wall.getComments(owner_id=owner_id, post_id=post_id, count=10, extended=1)
|
||||||
|
for comment in response['items']:
|
||||||
|
# Получаем информацию о пользователе
|
||||||
|
user_info = vk.users.get(user_ids=comment['from_id'])[0]
|
||||||
|
comments.append({
|
||||||
|
'text': comment['text'],
|
||||||
|
'from_id': comment['from_id'],
|
||||||
|
'from_name': f"{user_info['first_name']} {user_info['last_name']}",
|
||||||
|
'date': comment['date']
|
||||||
|
})
|
||||||
|
except vk_api.exceptions.ApiError as e:
|
||||||
|
logger.error(f"Ошибка при получении комментариев для поста {owner_id}_{post_id}: {e}")
|
||||||
|
|
||||||
|
return comments
|
||||||
|
|
||||||
|
# Функция разбивки длинного сообщения на несколько частей
|
||||||
|
def split_message(message, max_length=4096):
|
||||||
|
return [message[i:i+max_length] for i in range(0, len(message), max_length)]
|
||||||
|
|
||||||
|
# Функция форматирования даты
|
||||||
|
def format_date(timestamp):
|
||||||
|
return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(timestamp))
|
||||||
|
|
||||||
|
# Функция обработки команды /start
|
||||||
|
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||||
|
if update.message:
|
||||||
|
try:
|
||||||
|
await update.message.reply_text('Привет! Я бот, который собирает новости из ВКонтакте.')
|
||||||
|
await menu(update, context) # Сразу вызываем функцию menu
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Ошибка при отправке сообщения: {e}")
|
||||||
|
|
||||||
|
# Функция обработки команды /menu
|
||||||
|
async def menu(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||||
|
keyboard = [[group[1]] for group in GROUP_IDS] # Кнопки с названиями групп
|
||||||
|
reply_markup = ReplyKeyboardMarkup(keyboard, resize_keyboard=True)
|
||||||
|
if update.message:
|
||||||
|
try:
|
||||||
|
await update.message.reply_text('Выберите группу:', reply_markup=reply_markup)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Ошибка при отправке сообщения: {e}")
|
||||||
|
|
||||||
|
# Функция для формирования инлайн-кнопок под каждым сообщением новости
|
||||||
|
def generate_inline_keyboard(post_id, owner_id):
|
||||||
|
keyboard = [[InlineKeyboardButton("Показать комментарии", callback_data=f"comments_{owner_id}_{post_id}")]]
|
||||||
|
return InlineKeyboardMarkup(keyboard)
|
||||||
|
|
||||||
|
# Функция обработки нажатий кнопок
|
||||||
|
async def button_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||||
|
text = update.message.text
|
||||||
|
for group_id, group_name in GROUP_IDS:
|
||||||
|
if text == group_name:
|
||||||
|
news_items = get_vk_news(group_id, group_name)
|
||||||
|
if news_items:
|
||||||
|
for item in news_items:
|
||||||
|
post_link = f"https://vk.com/wall{item['owner_id']}_{item['post_id']}"
|
||||||
|
post_date = format_date(item['date'])
|
||||||
|
message = f"{post_link}\nДата: {post_date}\nГруппа: {item['group_name']}\n\n{item['text']}"
|
||||||
|
|
||||||
|
# Добавляем кнопки под каждым сообщением новости
|
||||||
|
inline_keyboard = generate_inline_keyboard(item['post_id'], item['owner_id'])
|
||||||
|
|
||||||
|
if item['photos']:
|
||||||
|
for photo in item['photos']:
|
||||||
|
await update.message.reply_photo(photo, caption=message, reply_markup=inline_keyboard)
|
||||||
|
else:
|
||||||
|
await update.message.reply_text(message, reply_markup=inline_keyboard)
|
||||||
|
|
||||||
|
else:
|
||||||
|
await update.message.reply_text(f'Новостей нет для группы {group_name} или произошла ошибка при получении новостей.')
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
await update.message.reply_text('Неверная команда. Используйте меню для выбора группы.')
|
||||||
|
|
||||||
|
# Функция обработки нажатий на инлайн-кнопки
|
||||||
|
async def callback_query_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||||
|
query = update.callback_query
|
||||||
|
query_data = query.data.split('_')
|
||||||
|
if query_data[0] == 'comments':
|
||||||
|
owner_id = query_data[1]
|
||||||
|
post_id = query_data[2]
|
||||||
|
comments = get_vk_comments(owner_id, post_id)
|
||||||
|
if comments:
|
||||||
|
comment_text = '\n\n'.join([f"{comment['text']}\n\nКомментарий от: {comment['from_name']}\nВремя: {format_date(comment['date'])}" for comment in comments])
|
||||||
|
if len(comment_text) > 4096:
|
||||||
|
parts = split_message(comment_text)
|
||||||
|
for part in parts:
|
||||||
|
await query.message.reply_text(part)
|
||||||
|
else:
|
||||||
|
await query.message.reply_text(comment_text)
|
||||||
|
else:
|
||||||
|
await query.message.reply_text('Комментариев нет.')
|
||||||
|
|
||||||
|
# Удаляем кнопку "Назад в меню"
|
||||||
|
await query.message.delete_reply_markup()
|
||||||
|
|
||||||
|
# Основная функция для запуска бота
|
||||||
|
def main() -> None:
|
||||||
|
application = ApplicationBuilder().token(TELEGRAM_TOKEN).build()
|
||||||
|
|
||||||
|
application.add_handler(CommandHandler("start", start))
|
||||||
|
application.add_handler(CommandHandler("menu", menu))
|
||||||
|
application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, button_handler))
|
||||||
|
application.add_handler(CallbackQueryHandler(callback_query_handler))
|
||||||
|
|
||||||
|
application.run_polling()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
2
requirements.txt
Normal file
2
requirements.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
python-telegram-bot==20.3
|
||||||
|
vk_api==11.9.8
|
||||||
Loading…
Add table
Reference in a new issue