- PVSM.RU - https://www.pvsm.ru -
Здравствуйте, меня зовут Евгений, и я алкоголик люблю социальные сети. В силу отсутствия каких-либо намеков на писательский талант я предпочитаю Twitter — его ограничение на 140 символов избавляет от необходимости придумывать что-то длинное. К тому же, только для твиттера есть нормальный java-клиент, которым я раньше пользовался на мобильном телефоне.
С другой стороны, бóльшая часть моя знакомых использует ВКонтакте, да и мне, честно говоря, нравится слушать там музыку и читать новости. Очевидно, что писать самому в две разных соцсети неудобно, нужно это автоматизировать — использовать кросспостинг (перенос постов).
Далее небольшое описание моего не совсем обычного способа кросспостинга.
Ранее для переноса записей я использовал [1] IFTTT. Это было не слишком удобно — посты переносились раз в 15 минут, спецсимволы энкодились (" превращалось в "), ссылки переносились сокращенными (t.co) — Вконтакте ругался при попытке перейти по этим ссылкам. Однако из-за недавних изменений в Twitter API, IFTTT был вынужден [2] отключить «рецепты», которые читают твиты. Мне пришлось искать новый путь. Внезапно™ я узнал, что у Вконтакта есть официальный способ импортировать твиты, но для этого приходится использовать хэштег #vk. После пары дней тестирования, оказалось что работает это не всегда (видимо опять срабатывали новые ограничения Twitter API на количество запросов), плюс оставалась проблема с ссылками.
Конечно, самым простым способом было бы использование скрипта, который будет переносить записи. На хабре неоднократно [3] писали [4] о разных способах кросспостинга, но все эти способы упирались в отсутствие у меня своего сервера. Покупать же платный
Но вот недавно, ползая по интернету в поисках новой версии прошивки для своего роутера, меня осенило, что на базе моего Zyxel Keenetic можно сделать небольшой веб-сервер! Еще перед покупкой я читал о таких возможностях роутера, но потом это как-то вылетело из моей головы. И вот я приступил к реализации задуманного проекта — кросспостинга из Twitter в Вконтакте с помощью роутера.
Для начала немного расскажу о возможностях Zyxel Keenetic. Вкратце, на роутер можно быстро, легко и безопасно устанавливать различные готовые модули (php, lighttpd, dlna, transmission, perl, python и др). Полее подробно можно почитать на форуме [6].
Перед началом проекта я сформировал список хотелок. Скрипт должен был уметь:
Cначала надо было выбрать язык скрипта. Для роутера есть модули Perl и Python, и с этими языками я был одинаково незнаком. С Twitter API и Вконтакте API я так же никогда не сталкивался, поэтому в первую очередь меня интересовали готовые примеры работы с ними. К счастью, таких скриптов в сети было найдено достаточно. Как-то случайно я выбрал Perl:)
Затем я приступил непосредственно к документации и примерам по Twitter API. Как вы знаете, есть два типа — Streaming и REST. В последних изменениях в API явно проглядывается желание Twitter'а перевести разработчиков на Streaming API. Поэтому было решено использовать именно Streaming, чтобы не иметь проблем в будущем.
Так как я делал скрипт только для себя, то я не стал делать получение access token, а взял его сразу со страницы настроек моего Twitter-приложения. За пару часов с помощью perl-модуля [7] было написано простенькое консольное приложение, выводившие твиты. На моем компьютере все работало отлично. Для проверки на роутере установил все нужные пакеты (как мне казалось), запустил скрипт, и… ничего. Не работает. Я установил все имеющиеся пакеты для Perl, не помогло. Путем гугления по тексту ошибки выяснил, что скорее всего, проблема из-за отсутствия какого-то perl-модуля, в результате скрипт не может правильно работать с SSL. В итоге было решено оставить Perl, и попробовать Python.
Скачал PyCharm [8], стал изучать синтаксис. Если честно, после .NET был в шоке от использования отступов в качестве обозначения блоков:) Разобрался в синтаксисе, нашел модуль tweepy [9], и довольно быстро мой скрипт вывода твитов был переписан на Python. Устанавливаю пакеты python на роутер, запускаю скрипт — о, чудо! Работает! Осталось дописать побочный функционал и запись постов в Вконтакте.
Для начала разберемся с функционалом.
Разворачивание ссылки. Если твит содержит ссылку, то Twitter возвращает нам JSON, в котором есть элемент "entities"
, содержащий "urls"
. Выглядит это примерно так:
"entities":
{
"hashtags":[],
"user_mentions":[],
"urls":[{
"indices":[0,21],
"display_url":"dev.twitter.com/terms/display-u2026",
"url":"https://t.co/Ed4omjYs",
"expanded_url":"https://dev.twitter.com/terms/display-guidelines"
}]
}
В тексте твита содержится "url"
, поэтому для разворачивания ссылки нужно просто в тексте заменить значение "url"
на значение "expanded_url"
.
Получение изображения. Если к твиту приложена картинка, то в "entities"
добавится элемент "media"
, вот так:
"entities":
{
"hashtags":[],
"user_mentions":[],
"urls":[],
"media":[{
"type":"photo",
"media_url":"http://p.twimg.com/A7kqLpACEAAUlwz.png",
"indices":[0,20],
"sizes":
{
"large":{"resize":"fit","h":454,"w":584},
"small":{"resize":"fit","h":264,"w":340},
"thumb":{"resize":"crop","h":150,"w":150},
"medium":{"resize":"fit","h":454,"w":584}
},
"display_url":"pic.twitter.com/XzDoEpH9",
"media_url_https":"https://p.twimg.com/A7kqLpACEAAUlwz.png",
"url":"http://t.co/XzDoEpH9",
"expanded_url":"http://twitter.com/TestTwVK/status/268292032273977344/photo/1",
"id":268292032278171648,
"id_str":"268292032278171648"
}]
},
Прямая ссылка на изображение содержится в элементе "media_url"
. Мне пришлось сохранять картинку во временный файл на локальном диске, не нашел способа загрузить его в ВК напрямую с сервера твиттера.
Посмотрим на получивший код для работы с Twitter.
Сначала авторизуемся и начинаем читать стрим
url = "https://userstream.twitter.com/1.1/user.json"
param = {"delimited":"length", "with":"user"}
header = {}
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_key, access_secret)
auth.apply_auth(url, "POST", header,param)
logging.info('Twitter authorization successful')
#запрос твитов
req = urllib2.Request(url)
req.add_header("Authorization", header["Authorization"])
r = urllib2.urlopen(req, urllib.urlencode(param), 90)
Читаем ответы, если это твит — обрабатываем его
while True:
#получаем длину твита
length = ""
while True:
c = r.read(1)
if c == "n": break
if c == "": raise Exception
length += c
length = length.strip()
if not length.isdigit(): continue
#читаем ответ указанной длины
tweet = json.loads(r.read(int(length)))
#если это твит - запускаем его обработку
if "user" in tweet and "text" in tweet and "created_at" in tweet and "id" in tweet:
handleTweet(tweet)
Метод обработки твита:
#получаем текст твита
text = tweet["text"]
#проверяем, что это не ответ, ретвит или упоминание
if not text.startswith('@') and not "@zzeneg" in text:
#получаем ссылки в твите
urls = tweet["entities"]["urls"]
#заменяем сокращенные ссылки
for url in urls:
text = text.replace(url["url"], url["expanded_url"])
#если ссылка ведет на EyeEm - получаем id фото
#если приложена картинка - убираем ее из текста
if "media" in tweet["entities"]:
photo = tweet["entities"]["media"][0]
text = text.replace(photo["url"], "")
У ВК немного другой механизм авторизации, и просто так получить access token не получится.
Сначала нужно создать desktop-приложение и взять его id. Затем сформировать ссылку вида https://oauth.vk.com/authorize?client_id={ID}&scope=wall,photos,offline&redirect_uri=http://oauth.vk.com/blank.html&display=page&response_type=token
, где {ID} — это ID приложения. В данной ссылке так же указаны разрешения для приложения — wall для постинга на стену, photos для заливки изображения и offline для того чтобы полученный токен был вечным. Копируем данную ссылку в браузер. ВК спросит нас о предоставлении прав данному приложению, а затем перенаправит на URL, в котором будет содержаться токен.
Для работы с методами VK API используется вот такая обертка. Код не мой, но я совершенно забыл откуда его взял — прошу прощения, что не указываю автора.
def vkMethod(method, data={}):
url = 'https://api.vk.com/method/%s.json' % (method)
data.update({'access_token': vkToken})
response = requests.post(url, data).json
if 'error' in response:
print 'VK API error: %s' % (response['error']['error_msg'])
return response
Здесь vkToken — полученный токен для ВК, method — имя метода из списка методов VK API, data — какие-то данные для метода.
Чтобы прикрепить картинку к посту на стене, нужно загрузить ее в альбом пользователя. Для фотографий на стене в ВК есть специальный альбом и специальные методы для работы с ним. Сначала получаем ссылку для загрузки фото, затем сохраняем картинку. В итоге получился такой метод:
def uploadPhoto(fileUrl):
#получаем url для загрузки фото
response = vkMethod('photos.getWallUploadServer')
uploadUrl = response['response']['upload_url']
#сохраняем фото локально
urllib.urlretrieve(fileUrl,'temp.jpg')
#загружаем фото в ВК
files = {'photo': open('temp.jpg', 'rb')}
response = requests.post(uploadUrl, files = files).json
#добавляем фото в альбом
response = vkMethod('photos.saveWallPhoto', response)
#возвращаем id фото
return response['response'][0]['id']
Данный метод возвращает ID загруженной картинки, который можно указать непосредственно при создании сообщения на стене:
attachments = uploadPhoto(photo["media_url"])
vkMethod('wall.post', {'message': text,'attachments':attachments})
При этом, если attachments
будет пустой строкой — то сообщение все равно появится на стене, без вложений.
Я использую EyeEm (это аналог Instagram, но с нормальными Privacy Terms), и недавно подумал, что фото оттуда хорошо бы загружать в ВКонтакте. К счастью, у EyeEm есть очень простой и понятный API, и буквально в две строчки в скрипт можно добавить поддержку загрузки фоток из него.
Метод получения ссылки на фото по ее ID
def getEyeEmPhotoUrlById(photoId):
url = "https://www.eyeem.com/api/v2/photos/{0}?access_token={1}".format(photoId, eyeEmToken)
response = requests.get(url).json
return response['photo']['photoUrl']
Теперь находим ссылку на фото в твите, получаем ее url и так же загружаем в ВК
if url["expanded_url"].startswith("http://www.eyeem.com/p/"):
eyeEmId = url["expanded_url"].replace("http://www.eyeem.com/p/", "")
photoUrl = getEyeEmPhotoUrlById(eyeEmId)
attachments = uploadPhoto(photoUrl)
Готовый скрипт можно скачать с github [10]. Токены в нем, естественно, изменены:) Нужно будет получить свои.
Теперь настравиваем роутер для поддержки сторонних пакетов по инструкциям на вики [11]. Приведу здесь краткую инструкция для Windows:
dropbear[4017] Running in background
"
Роутер готов к установке opkg пакетов. Их список можно посмотреть на сайте [13] либо командой opkg list
. Устанавливаем python и необходимые модули:
Затем, устанавливаем python с помощью команды:
opkg install python
и opkg install python-openssl
systemusrlibpython2.7
. Новая версия requests у меня не заработала, попробуйте либо ветку cache [15], либо из архива [16].*/15 * * * * killall -9 "python" ; /media/DISK_A1/system/usr/bin/python /media/DISK_A1/system/root/TwVk.py
Теперь cron в 0/15/30/45 минут каждого часа будет убивать скрипт и запускать его заново.Это очень криво, но стандартная для cron команда для действия после перезагрузки @reboot
не заработала. Ну и плюс скрипт тоже не совсем идеален, перезапуск ему не повредит. Если кто-то сможет предложить идею получше — милости прошу.
Данный скрипт работает у меня уже около полугода (статья писалась ооочень долго), большинство ошибок я исправил. Мою стену в ВК стало гораздо удобнее читать из-за развернутых ссылок и прикрепленных фоток. Я доволен. Планирую создать еще пару скриптов для Twitter на основе роутера, например твиттер-бота.
Надеюсь, данная статья кому-нибудь пригодится. Хотя бы чтобы начать использовать имеющийся роутер не только по его прямому предназначению:)
Я честно постарался исправить все грамматические ошибки и опечатки, но если Вы что-то заметите — пишите в личку.
Так же я еще раз напоминаю, что мои знания в Linux и Python недалеко ушли от нуля, и я с удовольствием выслушаю Ваши подсказки по улучшению скрипта.
Автор: zzeneg
Источник [19]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/vkontakte/31709
Ссылки в тексте:
[1] использовал: http://zzeneg.ru/post/eksport-zapisei-iz-twitter-v-vkontakte.aspx
[2] был вынужден: http://techcrunch.com/2012/09/20/ifttt-is-the-latest-service-to-be-affected-by-twitters-api-constraints-will-remove-triggers/
[3] неоднократно: http://habrahabr.ru/post/131107/
[4] писали: http://habrahabr.ru/post/149093/
[5] хостинг: https://www.reg.ru/?rlink=reflink-717
[6] форуме: http://forum.zyxmon.org/forum6-marshrutizatory-zyxel-keenetic.html
[7] perl-модуля: http://search.cpan.org/~mmims/Net-Twitter-Lite-0.11002/
[8] PyCharm: http://www.jetbrains.com/pycharm/
[9] tweepy: https://github.com/tweepy/tweepy
[10] github: https://github.com/zzeneg/TwVk
[11] вики: http://code.google.com/p/zyxel-keenetic-packages/wiki/Welcome
[12] ext_init.sh: http://zyxel-keenetic-packages.googlecode.com/files/ext_init.sh-r2.zip
[13] сайте: http://code.google.com/p/zyxel-keenetic-packages/source/browse/#svn%2Fbinary-packages-r2
[14] requests: https://github.com/kennethreitz/requests
[15] cache: https://github.com/kennethreitz/requests/tree/cache
[16] из архива: http://zzeneg.ru/uploads/requests.rar
[17] zyxmon: http://habrahabr.ru/users/zyxmon/
[18] kethlin_mil: http://habrahabr.ru/users/kethlin_mil/
[19] Источник: http://habrahabr.ru/post/158285/
Нажмите здесь для печати.