Объединяем twitter.com и vkontakte.ru

    Пользуетесь ли вы twitter’ом? Если ответом является «Да», то милости просим под кат, где будет рассказано про способ автоматического репостинга сообщений из twitter’а в статус сообщения на сайте vkontakte.ru используя python.

    Что такое twitter? Вот так отвечают на этот вопрос сами разработчики:
    Twitter — это сервис для друзей, родственников и коллег по работе для общения и поддержания связи при помощи обмена быстрыми, частыми ответами на один простой вопрос: Что ты делаешь?

    Но в русскоязычном twitter’е в данный момент всего лишь 17 тыс. пользователей (по данным Бобука). И, к сожалению, не все мои друзья, родственники и коллеги зарегистрированы на twitter.com и не спешат там регистрироваться, даже после красочных рассказов как тут всё радужно и прекрасно. Но все мои друзья подсели на сайт вконтакт.ру. Тут они проводят много своего свободного и не очень времени онлайн (причём некоторые сидят тут и с портативных устройств, что лично для меня как-то странновато).

    Поэтому логичным явилась идея объединить эти два сервиса каким либо способом. Хочу сказать, что данная мысль совсем не нова и есть даже специализированный сервис, пропиарим его немного: ВТвиттер. Но лично я, не люблю отдавать свои пароли непонятно кому (я же не квип пользователь, без обид;).

    Собственно вот так мы и подобрались к цели этой статьи. Мы будем связывать статус сообщения вконтакт'а и twitter’а по средствам скрипта на питоне, который будет считывать последние сообщение из твиттера, проверять статус вконтакта и, в случае расхождения, обновлять статус сообщение в контакте. Скрипт отдаём на съедение планировщику вашей ОС и радуемся. Я расскажу как это сделать на линуксовой машине при помощи cron. На винде изменится только работа с планировщиком.

    И так для начала подготовим окружение для работы. Нам потребуются две библиотеки для питона:
    • библиотека для работы c API Twitter'a;
    • библиотека для работы с json-ом.
    Скачиваем и распаковываем. В принципе, нам нужны будут только папки twyt и simplejson, которые необходимо разместить в одной папке с нашим будущим скриптом. Либо можете просто установить эти библиотеки для python в системе — читаем соответствующие readme.

    Теперь переходим к подготовке конфиденциальной информацию, которая нам потребуется. Для начала нам необходим логин и пароль twitter’а. Это просто.
    Теперь сайт вконтакта. Т.к. мы пишем скриптик под себя, а не сервис, мы не станем производить sing-in каждый раз на контаке для того чтобы получить куки. Вместо этого мы будем использовать готовые куки, которые раздобудем в браузере. Из кук нам будут нужны:
    • remixpass — хэш пароля;
    • remixmid — id юзера контакта (можно достать не из кук);
    • remixemail — ваша электронная почта для логина (тоже просто известна).
    А теперь интересный момент. Нам понадобится специальный код подтверждения операции смены статуса. У каждого пользователя контакта он свой и как генерируется мне не известно. Но он содержится в коде вашей главной странички (профайла пользователя). Поэтому открываем исходный код странички и ищем там activityhash. Это должен быть md5 хэш примерно такого вида: 876daef42dfe20351bbf31c2a9847c6d.

    Теперь у нас всё готово для написания кода. Дальше я покажу весь код сразу. Он очень хорошо прокомментирован и проблем с его пониманием, в принципе, не должно возникнуть, а если возникнут — комментарии внизу странички.

    1. #!/usr/bin/env python
    2. # -*- coding: utf8 -*-
    3.  
    4. import urllib2, urllib
    5. import re
    6. from twyt import twitter
    7. import simplejson as json
    8.  
    9.  
    10. #Прописываем информацию для авторизации
    11. #Для вконтака:
    12. email = 'lalala@mail.ru'
    13. id = '23'
    14. hash = '191aeb36d7876f9337ca61707b56d5882'
    15. activityhash = '982daef72dfd20321bbf31cia01347c6d'
    16. #Для твиттера:
    17. tw_login = 'Twitter_login'
    18. tw_passwrd = 'Twitter_pass'
    19.  
    20.  
    21. #формируем строку кук для вконтакта
    22. cookies_string = 'remixemail='+email+';remixmid='+id+';remixpass='+hash
    23.  
    24.  
    25. def get_vkontakt_status(text):
    26.         """Функция выдерает статус сообщение со страницы вконтакта"""
    27.          
    28.         #Маска по которой происходит поиск регулярного выражения. Первый элемент начало, второй конец для поиска  
    29.         mask_link = ( r';return false;">', r'</a><br />')
    30.         #Формируем маску регулярного выражения
    31.         mask = r"(?:"+mask_link[ 0 ]+r")(.*)(?:"+mask_link[1]+r")"
    32.         #Компилируем регулярное выражение, re.I — игнорируем регистр
    33.         parsed= re.compile(mask, re.I)
    34.         #и производим поиск
    35.         finish = parsed.findall(text)
    36.          
    37.         #Возвращаем первый найденный элемент (а он будет один),
    38.         #при этом режем последний символ (в статусе вконтака там всегда точка, а она нам не нужна)
    39.         #и декодируем из cp1251
    40.         return finish[0][0:-1].decode('cp1251')
    41.  
    42.  
    43. def get_twit_status(login, passwrd):
    44.         """Получаем последнее сообщение твиттера"""
    45.          
    46.         #Создаём объект класса
    47.         t = twitter.Twitter()
    48.         #авторизуемся
    49.         t.set_auth(login, passwrd)
    50.         #Получаем последнее сообщение (count=1)
    51.         response = t.status_user_timeline(count=1)
    52.         #Ответ возвращает в виде json-строки
    53.         #Обрабатываем полученное сообщение
    54.         #Переводим json объект в объект питона
    55.         json_objs = json.loads(response)         
    56.         #Перебираем все пришедшие сообщения (хоть и прийти должно одно)
    57.         for json_obj in json_objs:
    58.                 #забираем только текст сообщения
    59.                 twit = json_obj['text']
    60.                  
    61.         return twit
    62.  
    63. def get_page(url, post=None, cookies=None, timeout=None, referer=None):
    64.         """Получаем странички, отсылаем запросы"""    
    65.    
    66.     #Устанавливаем тайм аут
    67.     if timeout:
    68.         urllib2.socket.setdefaulttimeout(timeout)
    69.    
    70.     #POST данные посылаются в виде: post = {'key1' : 'value1', 'key2' : 'value2'}
    71.     if post != None:
    72.         #кодируем русские и спец символы  пос запроса  
    73.         post = urllib.urlencode(post)
    74.          
    75.         #Создаём опенер для загрузки страницы
    76.     opener = urllib2.build_opener()
    77.  
    78.     #Формируем запрос
    79.    
    80.     #задаём адрес и строку для поста
    81.     request = urllib2.Request(url, post)
    82.     # задаёмся рефером
    83.     if referer != None:
    84.         request.add_header('Referer', referer)
    85.     # устанавливаем клиент
    86.     request.add_header('User-Agent', 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.10) Gecko/2009042523 Ubuntu/9.04 (jaunty) Firefox/3.0.10')
    87.     # устанавливаем куки
    88.     if cookies != None:
    89.         request.add_header('Cookie', cookies) # куки
    90.    
    91.    
    92.     #Запрос пошёл
    93.     handle = opener.open(request)
    94.    
    95.     # Читаем данные
    96.     data = handle.read()
    97.    
    98.     #Закрываем хэндл
    99.     handle.close()
    100.    
    101.     return data
    102.  
    103. #Собственно понеслась программа
    104. if __name__ == "__main__":
    105.  
    106.         #Получаем твиттер статус
    107.         status_twitter = get_twit_status(tw_login, tw_passwrd)
    108.  
    109.         #Получаем вконтакте статус
    110.         content = get_page('http://vkontakte.ru/', cookies=cookies_string)
    111.         status_vkontakt = get_vkontakt_status(content)
    112.  
    113.         #Обновляем статус в случае расхождения
    114.         if status_twitter != status_vkontakt:
    115.                 #формируем пост запросс для обновления
    116.                 #посылаем текст нового статуса в поле setactivity, указав принудительно кодировку utf8,
    117.                 #и activityhash для подтвержднения действия с одновление
    118.                 post_array = {'setactivity': status_twitter.encode("utf8"), 'activityhash':activityhash}
    119.                 # И посылаем запрос для обновления статуса
    120.                 # ВНИМАНЕ в данном случае отсылка реффрера является обязательно. В противном случае ничего не обновится.
    121.                 content = get_page(url='http://vkontakte.ru/profile.php', post=post_array,
    122.                                    cookies=cookies_string, referer='http://vkontakte.ru/id'+id
    123.                 )



    Сохраняем это всё в файл, к примеру, twitter_in_vkon.py. Убеждаемся, что папки с библиотеками присутствуют в той же папке, даём права для запуска chmod +x ./twitter_in_vkon.py и запускаем скрипт ./twitter_in_vkon.py. Всё должно работать: последнее сообщение из твиттера перекочует в контакт;).

    Теперь я расскажу как прикрутить всё это к локальному/удалённому планировщику типа cron. Прикручивал на непонятно почему всех в последнее время раздражающей Ubuntu. У других может быть по другому.
    Выполняем:
    1. crontab -e

    Нам открывается файл cron’а с задачами и периодичностью их выполнения (по умолчанию он пуст). Добавим сюда запуск нашего скрипта каждые пять минут. Для этого вставим в файл строчку:
    1. */5 * * * * /etc/путь_к_нашему_скрипту/twitter_in_vkon.py

    И перезапускаем cron:
    1. sudo /etc/init.d/cron restart

    либо 
    1. sudo service cron restart

    Тем кому хочется почитать больше про настройку cron’а выполняют команду man cron =).
    Вот и всё. В итоге, у нас получился автоматический репостинг наших твиттов в статус сообщения контакта. Даёшь микроблогинг в массы! =)

    UPD
    arti_kz предложил логичный патч, исключающий постинг реплаев.
    Меняем 114 строку на:
    if (status_twitter != status_vkontakt) and (status_twitter[0] != '@'):
    Поделиться публикацией
    Похожие публикации
    Ой, у вас баннер убежал!

    Ну. И что?
    Реклама
    Комментарии 90
      0
      Классная статья! Благодарю за питона =).
        +5
        Поддерживаю. Лично мне Python очень нравится. Популярность языка растет и это радует.
        +1
        Статус в твиттере — это иное и не похоже на статус вконтакте, где почитают и забудут, я статусы вконтакте не читаю совершенно, еще не видел ниразу здравого смысла в них.
          0
          Писать в твиттер для двух друзей и кучи непонятнокого — это не то для чего придумывался твиттер. И как я писал выше все мои друзья в контакте и они пишут и читают статус сообщения.
            0
            На всякий случай оговорюсь, я за такие эксперименты, вы молодец, что не поленились написать.
            В твиттере у меня нет ни одного друга с реальной жизни. В отличии от контакта я нашел определенный круг умных людей, с которыми можно общаться. И найти в твиттере одно думцев плевое дело =)
            Контакт я воспринимаю, как сеть общения с друзьями в неформальной форме, для всего остального я не вижу зачем он.
          +15
          Пользуетесь ли вы twitter’ом? Если ответом является «Да», то милости просим под кат


          Согласно настроениям аудитории, логично было бы спрашивать «пользуетесь ли вы vkontakte.ru» :)
            0
            Шанс, что вы пользуетесь контактом, больше, чем твиттером ,.)
              –12
              стадо.
            0
            Эх, скармливать свои пароли неизвестному сервису не хочется, а своего сервера нет. Обидно.
              0
              Так а что мешает запускать python на своей машине?
              python есть даже под мобильные винды и симбиан.
                –1
                Компьютер не работает круглые сутки, а крона на симбе, боюсь, нет :)
                0
                В принципе на Google App Engine должно работать, сам не копал в эту сторону.
                  0
                  У GAE нет cron'а
                    +3
                    последние две недели у GAE cron есть :)
                +1
                есть же app engine.
                кстати могу сделать java/groovy версию, если кому надо.
                  –2
                  Порт под Django логичнее смотрится.
                  Но все интересно — особенно если один пример на нескольких языках рядом написан.
                  Если дойдут руки, опубликуйте здесь же, пожалуйста.
                    +2
                    Язык Django? Ух ты, круто!
                –16
                > Пользуетесь ли вы twitter’ом? Если ответом является «Да», то милости просим под кат, где будет рассказано про способ автоматического репостинга сообщений из twitter’а в статус сообщения на сайте vkontakte.ru

                Т.е. вариант, что кто-то не пользуется говновконтактом даже не рассматривается?
                  +3
                  В рунете так говорить опасно :) Даже если вы правы)
                    –1
                    я осознавал, на что шел.
                  0
                  Я к сожалению пока что не знаю этого языка, подскажите, что может быть? При запуске выдаётся
                  twivk # ./vktwi.py
                  File "./vktwi.py", line 31
                  mask = r"(?:"+mask_link[]+r")(.*)(?:"+mask_link[1]+r")"
                  ^
                  SyntaxError: invalid syntax
                    0
                    Да, меня тоже это — mask_link[] настораживает:)
                      +1
                      я избавился от этого заменой [] на [0]
                        0
                        Исправил.
                        –1
                        Нефиг под рутом сидеть.
                          0
                          v2nek@host ~/twivk $ ./vktwi.py
                          File "./vktwi.py", line 31
                          mask = r"(?:"+mask_link[]+r")(.*)(?:"+mask_link[1]+r")"
                          ^
                          SyntaxError: invalid syntax
                            0
                            Ежу понятно, что синтаксическая ошибка от этого не улетучится :) Я просто.
                              –1
                              Это очередной холивар, не относящийся к теме :)
                        –1
                        ох, спасибо. освободили немного времени, избавив от необходимости писать самому :)
                          0
                          А нельзя как-нибудь описать более подробно, для не особо сведущих в этом?
                            0
                            А что вам иненно не понятно? Задавайте вопросы и я попытаюсь ответить
                            +1
                            Небольшой патчик:

                            114c114
                            < if status_twitter != status_vkontakt:
                            — > if (status_twitter != status_vkontakt) and (status_twitter[0] != '@'):

                            Все-таки реплаи не очень красиво там будут смотреться…
                              0
                              Вы правы, так красивее.
                              0
                              да, и еще, некоторые символы, например "!", во вконтакте заменяются на html-entity, соответственно надо исправить сравнение. ну и точка в конце ставится не всегда.
                                0
                                Вы правы, сейчас посмотрю, что можно с этим сделать.
                                +1
                                у кого есть твиттер, тому не нужен вконтакт имхо
                                  +2
                                  > Пользуетесь ли вы twitter’ом? Если ответом является «Да», то милости просим под кат

                                  т.е. Вы утверждаете, что во вконтакте есть все пользователи хабра?
                                    +4
                                    а вы не знали что когда вы регились на хабре, вас тайно регили на Вконтакте.ру, Одноклассниках, и друхи подобных сервисах?))
                                    • НЛО прилетело и опубликовало эту надпись здесь
                                    0
                                    Как всегда не хватает ссылки, где посмотреть живой пример
                                      +1
                                      Что-то у вас странное с отступами в коде. То четыре, то восемь.
                                        0
                                        Это скорее всего хабрапарсер намутил.
                                          0
                                          Может быть возможно выложить сам файлик?
                                        0
                                        Может добавите ссылку на какой-нибудь сервис, заточенный для передачи кода другим?
                                          0
                                          Добавил
                                          0
                                          Пытаюсь запустить на Маке:

                                          File «twitter_in_vkon.py», line 67
                                          if timeout:
                                          ^
                                          IndentationError: unindent does not match any outer indentation level
                                            0
                                            Скорее всего съехали отступы. Такое очень часто с питоном
                                            0
                                            А нельзя ли выложить исходник? А то хз как удалять номера строк.
                                              0
                                              Alt+click+drag
                                              Позволяет выделять столбцы текста.

                                              А исхожник все-же надо.
                                                0
                                                К вечеру выложу исходник
                                                  0
                                                  Выложил
                                                  0
                                                  Под маком скрипт не работает. Я, к сожалению, питон не знаю и не могу сам исправить ошибку.

                                                  Traceback (most recent call last):
                                                  File «TwiVkon.py», line 107, in status_twitter = get_twit_status(tw_login, tw_passwrd)
                                                  File «TwiVkon.py», line 51, in get_twit_status
                                                  response = t.status_user_timeline(count=1)
                                                  File "/Users/icekeeper/Documents/TwiVkon/twyt/twitter.py", line 223, in status_user_timeline
                                                  return self.get(data, handler, doauth=True)
                                                  File "/Users/icekeeper/Documents/TwiVkon/twyt/twitter.py", line 134, in get
                                                  return self.__request(data, handler, doauth=doauth, method='GET')
                                                  File "/Users/icekeeper/Documents/TwiVkon/twyt/twitter.py", line 115, in __request
                                                  raise TwitterException(«Connect failed: » + str(e.reason))
                                                  twyt.twitter.TwitterException: Connect failed: unknown url type: https
                                                    0
                                                    Выложил исходный текст попробуйте запустить оттуда.
                                                      0
                                                      у меня все заработало. вы что-то сделали не так.
                                                      0
                                                      нууу обработки ошибок вообще нет

                                                      P.S. Где нормальный API от ВКонтакте? Парсинг — это зло.
                                                        0
                                                        Я же это не продаю, а показываю пример реализации. Допишите обработчик, если заинтересовались, всё опен сорс.
                                                      • НЛО прилетело и опубликовало эту надпись здесь
                                                          0
                                                          Как я ждал такой коммент ;)
                                                          • НЛО прилетело и опубликовало эту надпись здесь
                                                            • НЛО прилетело и опубликовало эту надпись здесь
                                                                0
                                                                Вы правы, так и впрямь красивее.
                                                          +1
                                                          Все хорошо, но зачем перезапускать cron? Вроди как, все задачи подхватываются спустя 2 минуты? Так было и есть на всех линуксах на которых работал подолгу (Red Hat, Fedora, Gentoo, Kubuntu), на всех BSD (FreeBSD, Mac OS X).
                                                            0
                                                            Не знал. Спасибо за подсказку.
                                                              0
                                                              Сообщество для того и нужно, чтобы делиться опытом ;)
                                                            0
                                                            >Вместо этого мы будем использовать готовые куки, которые раздобудем в браузере.
                                                              0
                                                              В голове появились гадкие мысли о вконтакто трояне на питоне
                                                                0
                                                                Пишите ;)
                                                              0
                                                              запускаю скрипт, ошибок никаких не выдает, пыхтит вроде, но статус не меняет. =( последнее сообщение — не реплай, проверил. без дебаггера сложно.
                                                                0
                                                                спасибо. все заработало без пиления напильником.
                                                                  0
                                                                  не подскажете как можно из вконтакта выдрать список друзей(id, фамиля, имя)?
                                                                  изучением языка занялся недавно) пока только удалось, с помощью этой статьи, получить страницу содержащую список…
                                                                    0
                                                                    Посмотри документацию контактовского API, на сколько я помню там есть доступ к друзьям.
                                                                    0
                                                                    Скрипт отказывается работать, при обращении к vkontakte.ru/ выдает:

                                                                    urllib2.URLError: прокси нету и можно простым пингом достучаться до vkontakte.ru
                                                                      0
                                                                      Я знаю, уже поздно писать, но код корявый. Во-первых, столько комментариев никому не нужно — новички все равно не поймут, опытным хватит и гораздо более меньшего количества. Во-вторых, форматирование кода ужасно. Минимум пробелов, зачем-то лишние символы и действия (типа конструировния регекспа в две стадии, да еще и с ненужными (?:) группами).

                                                                      Кстати, перезапускать crond после редактирования пользовательского crontab не нужно.

                                                                      А если бы его понадобилось перезапустить (например, после редактирования /etc/crontab, и то я не уверен), то лучше испольовать reload.
                                                                        0
                                                                        А если нет сервера и домашний комп не включён всегда — есть vtwittere.ru — готовый сервис.
                                                                        P.S. Пароль доверить можно, я проверял.
                                                                          0
                                                                          Э… сразу скажу что я Python изучаю неделю:) так что… ну все поняли… код я прочитал, и прочитал коментарии… Под Ubuntu запустил так python tinv.py сначала выжавал кучу синтаксических ошибок — исправил выравниванием отступов… теперь ошибок не выдает… но… статус в контакте не меняется :( в чем проблема?
                                                                            0
                                                                            Косо криво как-то работает. Многие символы заменяются вконтакте на html и соответственно сообщение публикуется множество раз, так как статусы считаются разными. Аналогичные вещи творятся если в статусе присутствует ссылка! К ней добавляется тег.
                                                                              0
                                                                              А вы по мере обновления кода ни в какой репозиторий его не сливаете?
                                                                              И еще, как решается проблема с устареванием кук?
                                                                                0
                                                                                Сорри за поздний (и немного тупой) пост, но:

                                                                                Крон вываливается с ошибкой:
                                                                                Fatal error: Call to undefined function curl_init() in /virt/homes/ozonar/htdocs/twit/twitter.class.php on line 253

                                                                                Функция curl_init() нигде не обьявлена. Что не так?
                                                                                  0
                                                                                  vtwittere.ru/:

                                                                                  К великому сожалению, сервис прекратил свое земное существование.
                                                                                  Все авторизационные данные были удалены вместе с базой данных.
                                                                                  Просим прощения за такой вот косяк. Если что, пишите письма: evgenij@beloded.net
                                                                                    0
                                                                                    А на PHP нет такого решения?
                                                                                      0
                                                                                      cookie_string изменился. Теперь он выглядит так.

                                                                                      cookies_string = ""«remixchk=5; remixlang=3; remixclosed_tabs=8; remixsid=31fcc376cf74c284332552ec6c3e3d42d5ac223d9ed12b64579b2x2»""
                                                                                        0
                                                                                        из них вполне хватает remixsid=
                                                                                        0
                                                                                        ура допилил подмену куков, теперь и у меня работает
                                                                                          0
                                                                                          А в виде готового решения нет? Не хочется тратить пару часов на изучение языка программирования, с которым никогда не сталкивался.
                                                                                            0
                                                                                            Кажется, вконтакте поменяли формат кук.
                                                                                              0
                                                                                              не в этом дело. Старое API твиттера закрыто жеж, теперь только OAuth.
                                                                                                0
                                                                                                Есть РСС у твиттера еще
                                                                                              0
                                                                                              > Но в русскоязычном twitter’е в данный момент всего лишь 17 тыс. пользователей (по данным Бобука).

                                                                                              Это по данным Бобука за какой год?
                                                                                              По данным на март этого года, «к настоящему моменту русскоязычный сегмент в „Твиттере“ насчитывает 183 тысячи пользователей.»
                                                                                              Хотя да, это всё равно безусловно меньше десятков миллионов Вконтакте.
                                                                                                0
                                                                                                Похоже, activityhash почил с миром или как-то генериться теперь — на странице его натйи не получается.

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

                                                                                                Самое читаемое