Кросспостинг

10-09-2021

Кросспостинг в Интернете - автоматическое, полуавтоматическое или ручное размещение или отправка одного и того же сообщения, статьи, ссылки или темы, на адреса электронной почты, форумах, блогах, либо на иной формы сайтах или в публичных переписках.

Будем публиковать анонсы на материалы сайта в социальных сетях и мессенджерах с указанием ссылки. Самыми популярными являются Twitter, Вконтакте и Facebook, а также мессенджеры Телеграм и Rocket.Chat. Возможно позже добавим одноклассников.

Все работы будем проводить на сервере под управлением OS linux debian 10.

Подобных скриптов в интернете много и всегда можно найти нужный и настроить для себя. Я напишу свой велосипед, для себя.

Почти свой.

Начало

Для публикации анонсов нужно их от куда-то брать? Почти на каждом сайте есть лента RSS с последними новостями. Обычно это файл rss.xml или index.xml.

В самом простейшем варианте наша новость в нем выглядит так:

<item>
    <title>Кросспостинг на python</title>
    <link>http://drhellp.loc.ru/krossposting-na-python/</link>
    <pubDate>Fri, 10 Sep 2021 11:41:04 +0300</pubDate>
    <description><h3 id="кросспостинг">Кросспостинг</h3> <p>Кросспостинг - что, как и зачем это нужно.</p></description>
</item>

Это обычный файл формата xml.

Также необходимо будет хранить пароли и токены доступа к социальным сетям, а также другие настройки в отдельном файле settings.ini.

Теперь определим, что будет делать наш скрипт и в каком порядке:

  1. Проверяем доступ в интернет
  2. Считываем настройки из settings.ini
  3. Читаем rss.xml файл блога с последними новостями
  4. Парсим rss.xml
  5. Находим последнюю новость и публикуем в социальные сети
  6. Записываем в settings.ini время публикации

Создадим директорию для нашего скрипта и перейдем в нее:

mkdir cross-bot
cd cross-bot

Создаем главный файл скрипта:

nano main.py

Проверка доступа в интернет

Проверять будем обычной командой ping до публичных серверов Google. Существует много способов проверить наличие интернет соединение мне этого достаточно. Скрипт завершит работу если ping не пройдет.

Прописываем следующие строки в скрипт:

#!/usr/bin/python3
# -*- coding: utf-8 -*

import sys
import subprocess

# Проверяем, есть ли доступ в интернет
print ("Проверка соединения...")
response = subprocess.call(["/usr/bin/ping", "-c", "3", "8.8.8.8"], stdout=subprocess.DEVNULL)
if response != 0:
    print ("Нет доступа в интернет. Бот завершает работу.")
    sys.exit(1)
print ("OK Google!")

Чтение параметров

Для хранения настроек скрипта используем файл settings.ini. Для работы с ini файлами нужно подключить библиотеку configparser.

import configparser

Создадим файл настроек settings.ini.

nano settings.ini

Добавим в него параметры:

[RSS]
feed = http://drhellp.loc.ru/rss.xml
datetime = 2021-09-10 10:12:23+00:00

Читаем:

# Имя ini файла
ini = '/home/drhellp/cross-bot/settings.ini'
config = configparser.ConfigParser()
config.read(ini)
FEED = config.get('RSS', 'feed')
DATETIME = config.get('RSS', 'DATETIME')

Чтение RSS

Для работы с rss установим библиотеку feedparser.

sudo apt-get install python3-pip
sudo pip3 install feedparser

Проверяем чтение rss. В цикле проходим все элементы.

import feedparser

# Получаем RSS ленту
rss = feedparser.parse(FEED)

for post in reversed(rss.entries):
    print('---------------------------------')
    # Получаем заголовок поста
    title = post.title
    print(title)

    # Получаем ссылку на пост
    link = post.links[0].href
    print(link)

    # Скачиваем текст
    text = post.description
    text = remove_html_tags(text)
    print(text)

Для вывода новостей без html тегов добавим в начало скрипта функцию remove_html_tags. Также импортируем библиотеку для работы с регулярными выражениями.

import re

def remove_html_tags(text):
    clean = re.compile('<.*?>')
    return re.sub(clean, '', text)

Получаем вывод новостей.

---------------------------------
Кросспостинг на python
http://drhellp.loc.ru/krossposting-na-python/
Кросспостинг
Кросспостинг - что, как и зачем это нужно.

Публикация в Twitter

Для публикации анонсов в Twitter нужно получить ключи и токены.

  • consumer_key
  • consumer_secret
  • access_token
  • access_token_secret

Как их получить хорошо описано здесь https://mihalica.ru/twitter-api-key-token/ Если эта статья не поможет перейдите на страницу https://apps.twitter.com/app/new и при необходимости войдите в систему. Создайте приложение и оформите заявку для работы с API.

После получения ключей и токенов доступа продолжим. Добавим в систему библиотеку для работы с Twitter.

sudo apt-get install python3-tweepy

В settings.ini добавим секцию с ключами и токенами.

[Twitter]
consumer_key = XXXXXXXXXX
consumer_secret = XXXXXXXXXX
access_token = XXXXXXXXXX
access_token_secret = XXXXXXXXXX

Считываем параметры

import tweepy

# Параметры twitter
CONSUMER_KEY = config.get('Twitter', 'consumer_key')
CONSUMER_SECRET = config.get('Twitter', 'consumer_secret')
ACCESS_TOKEN = config.get('Twitter', 'access_token')
ACCESS_TOKEN_SECRET = config.get('Twitter', 'access_token_secret')

Прежде чем пытаться отправить сообщения в Twitter немного доработаем скрипт. Чтобы не публиковать все сообщения при каждом запуске скрипта, будем проверять время публикации в rss и время в файле settings.ini. Если в rss время больше чем в файле, тогда новость публикуем и обновляем время в файле, иначе ничего не делаем.

import datetime

for post in reversed(rss.entries):
    # Время публикации
    data = post.published
    time = datetime.datetime.strptime(data, '%a, %d %b %Y %H:%M:%S %z')
    time_old = config.get('RSS', 'DATETIME')
    time_old = datetime.datetime.strptime(time_old, '%Y-%m-%d  %H:%M:%S%z')

    # Пропускаем уже опубликованные посты
    if time <= time_old:
        continue
    else:
        # Записываем время и дату нового поста в файл
        config.set('RSS', 'DATETIME', str(time))
        with open(ini, "w") as config_file:
            config.write(config_file)

        print('---------------------------------')
        # Получаем заголовок поста
        title = post.title
        print(title)

        # Получаем ссылку на пост
        link = post.links[0].href
        print(link)

        # Скачиваем текст
        text = post.description
        text = remove_html_tags(text)
        print(text)

Теперь при запуске напечатаются только те новости у которых время создания больше даты в файле settings.ini. При повторном запуске новости выводиться не будут. Для эксперимента можно исправить значение datetime в файле settings.ini.

# Авторизуемся в твитере и отправляем сообщение
    auth = tweepy.OAuthHandler(
        CONSUMER_KEY,
        CONSUMER_SECRET
    )
    auth.set_access_token(
        ACCESS_TOKEN,
        ACCESS_TOKEN_SECRET
    )
    api = tweepy.API(auth)
    # Формируем сообщение twitter
    tweet = title + '\n' + link
    status = api.update_status(status=tweet)

Публикация в Вконтакте

Для публикации анонсов Вконтакте тоже необходимо получить токен доступа.

Создадим Standalone приложение cross-bot на странице https://vk.com/apps?act=manage

Вконтакте

Для подтверждения на номер подключенного к аккаунту телефона придет код.

Код

Добавим описание и сохраняем изменения. Переходим в настройки.

Настройки

Здесь нам нужен ID приложения.

ID приложения

Сформируем ссылку такого вида:

https://oauth.vk.com/authorize?client_id={ID-CLIENT}&display=page&redirect_uri=https://oauth.vk.com/blank.html&scope=wall,offline&response_type=token&…

{ID-CLIENT} - ID нашего приложения. Открываем ссылку в браузере.

Доступ к аккаунту

Разрешаем доступ нашему приложению.

Получаем следующее предупреждение:

Пожалуйста, не копируйте данные из адресной строки для сторонних сайтов. Таким образом Вы можете потерять доступ к Вашему аккаунту.

Из адресной строки копируем часть после access_token= и до &expires_in, это и есть нужный нам токен доступа.

Для проверки напишем маленький скрипт.

#!/usr/bin/python3
# -*- coding: utf-8 -*

import requests

token = 'access_token'
version = 5.81

data = {
    'access_token': token,
    'from_group': 1,
    'message': 'Тест',
    'attachments': 'Ссылка на любую страничку',
    'signed': 0,
    'close_comments': 1,
    'v':version
    }

r = requests.post('https://api.vk.com/method/wall.post', data).json()

print(r)

Добавляю в settings.ini данные.

[VK]
access_token = XXXXXXXXXXXXXXXXXXXX
version = 5.81

В скрипте считываю данные и добавляю функцию.

import requests

# Параметры Вконтакт
VK_TOKEN = config.get('VK', 'access_token')
VK_VERSION = config.get('VK', 'version')

# Публикуем анонс во Вконтакт
def public_vk(title, link):
    # Формируем массив данных
    data = {
        'access_token': VK_TOKEN,
        'from_group': 1,
        'message': title,
        'attachments': link,
        'signed': 0,
        'close_comments': 1,
        'v': VK_VERSION
    }
    # Отправляем запрос
    requests.post('https://api.vk.com/method/wall.post', data).json()
    return

public_vk(title, link)

Публикация в Телеграм

Для публикаций в Телеграм создадим бота. Хорошее руководство находится на этой странице http://nikovit.ru/blog/telegram-bot-peresylki-soobshcheniy-rss/

Лучше для наших целей воспользоваться клиентом на компьютере. Добавляем в контакты @BotFather. Отправляем ему команду:

/newbot

Придумываем имя, логин должно заканчиваться обязательно на bot.

После регистрации бота получаем следующее:

Done! Congratulations on your new bot. You will find it at t.me/ИМЯ_ВАШЕГО_БОТА. You can now add a description, about section and profile picture for your bot, see /help for a list of commands. By the way, when you've finished creating your cool bot, ping our Bot Support if you want a better username for it. Just make sure the bot is fully operational before you do this.

Use this token to access the HTTP API:
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Keep your token secure and store it safely, it can be used by anyone to control your bot.

For a description of the Bot API, see this page: https://core.telegram.org/bots/api

Бот зарегистрирован, токен бота получен, никому не сообщайте его, зная токен можно полностью управлять ботом. Добавляем бота поиском по имени которое указывали ранее в наш канал, выдаем ему право публиковать сообщения.

Установим недостающие библиотеки.

sudo pip3 install pyTelegramBotAPI

Добавляем в файл настроек новую секцию.

[Telegram]
bot_token = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
channel = @ВАШ_КАНАЛ

Если канал частный то нужен его ID.

  • Вы должны преобразовать канал в публичный и назначить @channelName
  • Отправить сообщение на этот канал через Bot API
    https://api.telegram.org/bot[ТОКЕН_ВАШЕГО_БОТА]/sendMessage?chat_id=@channelName&text=test
  • В ответ вы получите информацию с chat_id вашего канала.
    {"ok": true, "result": {"chat": { "id": -1001005582487, "title": "Test Private Channel", "type": "channel"}, "date": 1448245538, "message_id": 7,"text":"test"}}
  • Теперь вы можете преобразовать канал обратно в частный (удалив ссылку на канал) и отправить сообщение прямо на этот chat_id “-1001005582487”
    https://api.telegram.org/bot[ТОКЕН_ВАШЕГО_БОТА]/sendMessage?chat_id=-1001005582487&text=test

Дописываем в скрипт:

import telebot

# Публикуем анонс в Telegram
def public_telegram(title, text, link):
    # Инициализируем телеграм бота
    bot = telebot.TeleBot(BOT_TOKEN)
    # Формируем сообщение в канал
    message = '<a href="' + link + '">' + title + '</a>' + "\n" + text
    # Отправляем сообщение в Telegram
    bot.send_message(CHANNEL, message, parse_mode='HTML', disable_web_page_preview=False)
    return

# Параметры бота Telegram
BOT_TOKEN = config.get('Telegram', 'bot_token')
CHANNEL = config.get('Telegram', 'channel')

public_telegram(title, text, link)False)

Публикация в Facebook

Устанавливаю библиотеку для работы с API Facebook.

sudo pip3 install facebook-sdk

В Facebook публиковать сообщения можно или в группу или на специально созданную страницу. В чем отличия группы и страницы, тема для другой статьи. Буду публиковать анонсы на страницу, создаю её.

Создание страницы

Придумываю название, описание и категорию для страницы. Добавить обложку и изображение, это по желанию. Также по желанию можно подключить Страницу Facebook к WhatsApp.

Подключить WhatsApp

Выбираю меню Ещё, пункт Информация

Информация

В самом низу - ID страницы.

ID страницы

Теперь создаем приложение Facebook, которое будет использоваться для доступа к Graph API Facebook. Перехожу на страницу https://developers.facebook.com/apps/ и создаю приложение cross-bot.

Создаем приложение

Выбираем тип Другое.

Тип приложения

Придумаем название приложения.

Название приложения

Потребуется дополнительно ввести наш пароль от аккаунта. В верхнем меню выбираем Инструменты и Graph API Explorer. Выбираем наше приложение.

Выбираем наше приложение

Выбираем Получить маркер доступа пользователя

Маркер доступа пользователя

cross-bot запрашивает доступ к следующим данным: имя и фото профиля.

Продолжаем со своим аккаунтом. Получим Разрешения public_profile. Добавим разрешение pages_manage_posts и сгенерируем токен.

Продолжаем со своим аккаунтом.

Какие Страницы вы хотите использовать с приложением cross-bot?

На следующем этапе вы определите, что приложение cross-bot может делать с выбранными Страницами.

Bыбираем недавно созданную страницу.

Что разрешено делать приложению cross-bot?

Показать список Страниц, которыми вы управляете

ДА

Читать контент, опубликованный на этой Странице

ДА

Создание контента на вашей Странице и управление им

ДА

Разрешения

В результате получим дополнительно следующие разрешения:

  • pages_show_list
  • pages_read_engagement
  • pages_manage_posts
  • public_profile

Возле маркера доступа нажимаем на значек i

Создаем приложение

Полученный токен действителен несколько часов. Увеличим время его действия. Жмем кнопку Открыть в Инструменте маркеров доступа и на открывшейся странице, в самом низу нажимаем Продлить маркер доступа

Создаем приложение

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

Создаем приложение

Добавляем в settings.ini новую секцию.

[Facebook]
access_token = XXXXXXXXXXXXXXXXXXXXXXX
page_id = 109592441534081

Считываем параметры

import facebook

# Параметры Facebook
FB_TOKEN = config.get('Facebook', 'access_token')
FB_PAGE_ID = config.get('Facebook', 'page_id')

В скрипт добавляем новую функцию

# Публикуем анонс в Facebook
def public_fb(link):
    # ID страницы для которой нужно получить токен
    page_id = FB_PAGE_ID
    # Используем для запроса токен пользователя
    graph = facebook.GraphAPI(FB_TOKEN)
    # Отправляем запрос
    resp = graph.get_object('me/accounts')
    page_access_token = None
    # Поиск токена для страницы
    for page in resp['data']:
        if page['id'] == page_id:
            page_access_token = page['access_token']
    # Запрос с токеном страницы
    graph = facebook.GraphAPI(page_access_token)
    # Публикуем анонс
    graph.put_object('me', 'feed', link=link)
    return

public_fb(link)

Публикация в Rocket.Chat

Создайте пользователя или воспользуйтесь существующим. Убедитесь, что пользователь может отправлять сообщения в нужном канале. Предоставьте пользователю роль с разрешением на создание личных токенов доступа. Получите токен доступа.

Добавим параметры в файл настроек.

[RocketChat]
url = https://chat.loc.ru/hooks/XXXXXXXXX
username = USER
icon_emoji = :information_source:
color = #00008b

Считываем параметры и вызываем функцию.

# Параметры RocketChat
URL = config.get('RocketChat', 'url')
USERNAME = config.get('RocketChat', 'username')
ICON_EMOJI = config.get('RocketChat', 'icon_emoji')
COLOR = config.get('RocketChat', 'color')

# Публикуем анонс в RocketChat
def public_rc(title, text, link):
    # Отправляем пост в корпоративный чат
    payload = {"username":USERNAME,"emoji":ICON_EMOJI,"attachments":[{"color":COLOR,"title":title,"title_link":link,"text":text}]}
    r = requests.post(URL, json=payload)
    return

public_rc(title, text, link)

Публикация в Одноклассниках

Для публикаций в Одноклассниках потребуется создать тематическую группу и приложение. Во первых нужно получить права разработчика, переходим на страницу. Подробная инструкция, как создать приложение. Создаем приложение со следующими правами.

Права

Приложение добавлено. На вашу эл. почту gmail@gmail.com был выслан код, который будет необходимо указывать при изменении настроек приложения.

В почтовом ящике обнаружите письмо.

Ваше приложение cross_bot успешно зарегистрировано на Одноклассниках.

Application ID: XXXXXXXXXXX
Публичный ключ приложения: XXXXXXXXXXX
Секретный ключ приложения:  XXXXXXXXXXX
Ссылка на приложение: https://ok.ru/game/XXXXXXXXXXX
--
С уважением,
Служба поддержки OK.ru

Переходим по ссылке и выбираем Изменить настройки приложения. Внизу страницы нажимаем кнопку Добавить платформу.

Добавить платформу

Выбираем OAuth авторизацию. В Список разрешённых redirect_uri добавим пару строк и сохраним.

okauth://okApplication ID
okApplication ID://authorize

Внизу страницы, в разделе Access token нажимаем кнопку Получить новый.

Права

Получаем необходимые токены доступа.

Вечный session_key: XXXXXXXXXXX
Session_secret_key: XXXXXXXXXXX

Сохраняем параметры приложения.

Внимание, после добавления дополнительных прав доступа в приложении, access_token работать перестанет, его необходимо будет получить заново.

Добавляем в файл настроек новую секцию.

[OK]
; Вечный access_token
ok_access_token = XXXXXXXXXXX
; Секретный ключ приложения
ok_private_key = XXXXXXXXXXX
; Публичный ключ приложения
ok_public_key = XXXXXXXXXXX
; Session_secret_key
ok_session_key = XXXXXXXXXXX
; ID группы
ok_gid = XXXXXXXXXXX

ID группы можно посмотреть в настройках группы или в строке браузера.

https://ok.ru/group/XXXXXXXXXXX

Для создания хэша нам понадобится библиотека шифрования. В скрипте считываем параметры и вызываем функцию.

import requests
import hashlib

# Параметры в Одноклассниках
OK_ACCESS_TOKEN = config.get('OK', 'ok_access_token')
OK_PRIVATE_KEY = config.get('OK', 'ok_private_key')
OK_PUBLIC_KEY = config.get('OK', 'ok_public_key')
OK_SESSION_KEY = config.get('OK', 'ok_session_key')
OK_GID = config.get('OK', 'ok_gid')

# Публикуем анонс в Одноклассники
def public_ok(link):
    # Формируем массив параметров
    params = {
        "application_key": OK_PUBLIC_KEY,
        "attachment": '{"media": [{"type": "link", "url": "' + link + '"}]}',
        "format": "json",
        "gid": OK_GID,
        "method": "mediatopic.post",
        "type": "GROUP_THEME"
    }

    # Формируем строку параметров из массива
    string_params = ''
    for key in params:
        string_params = string_params + key + '=' + params[key]

    # Высчитываем хеш для строки параметров
    string_params = string_params + OK_SESSION_KEY
    hash_string = hashlib.md5(string_params.encode())
    # Добавляем наш токен
    params["access_token"] = OK_ACCESS_TOKEN
    # Добавляем полученный хеш
    params["sig"] = hash_string.hexdigest()

    # Отправляем пост
    r =  requests.post('https://api.ok.ru/fb.do', data=params)
    return

Заключение

Полностью скрипт можно скачать в репозитории. Не забудьте добавить скрипт в задания CRON.