Добрый день!
Наверняка многие сталкивались с ситуацией, что важная информация (новости, объявления и т.д.) публикуется ВКонтакте. Но во-первых, не всегда есть возможность туда попасть (вообще неприлично в рабочее время сидеть вконтакте!), во-вторых информацию приходится получать polling'ом, то есть постоянно обновляя страницу группы или что-нибудь аналогичное.
Отсюда родилась замечательная мысль — было бы удобно, чтобы важные уведомления приходили на почту. И на работе посмотреть можно исудорожно жать F5постоянно обновляться не нужно. Как оказалось, с помощью python'а можно легко справиться с такой задачей.
Для начала я попробовал быть честным и использовать VK API. В сети я даже сумел отыскать парочку библиотек, которые умели логиниться и выполнять функции из API. К сожалению, ни одна из них меня не устроила, поэтому я умудрился за парочку часов соорудить свой велосипед. Ладно, дело сделано, но тут я наткнулся на неприятный момент, а именно, с помощью текущей версии API нет возможности получить сообщения со стены группы (или я не нашел как это сделать, что тоже вероятно). Остался один вариант — парсить страницы ВКонтакте самостоятельно. С одной стороны, это не очень легально, с другой стороны, такой подход дает возможность получить любую информацию, которую я могу увидеть непосредственно в браузере.
Перво-наперво я попытался с помощью httplib и urllib получить страницу логина. Все замечательно и прекрасно. Вот только обнаружилось, что придется писать много некрасивого кода, да еще и с cookies работать… И как-то очень сильно меня это опечалило. Я начал искать замену. И нашел замечательную библиотеку mechanize, которая замечательно сделала за меня всю неинтересную работу по созданию соединений, обработке сессий и cookies и т.д…
Итак, с помощью mechanize получаем главную страницу ВКонтакте:
В качестве пояснения скажу, что на vkontakte.ru первая форма как раз и есть форма логина. С помощью mechanize заполняем ее и вуа-ля, мы залогинились на сайт!
Следующий код позволит нам получить страницу группы:
Теперь непосредственно будем парсить полученный html-код, с целью отыскать в нем нужные сообщения.
Для этого нам потребуется библиотека HTMLParser. Создадим свой класс парсера, который отнаследуем от HTMLParser.
Для простоты будем искать сообщения, которые начинаются с какого-нибудь pattern'а (в своем скрипте я использовал '@year2007').
Весь текст приходит в кодировке CP1251, переводим его в unicode. Слои с классами wall_text отвечают за сообщения, wall_post_text — за сам текст сообщения.
Теперь код получения сообщений можно обернуть в бесконечный цикл. Чтобы не посылать сообщения на почту каждый проход, можно устроить очередь сообщений или пытаться распарсить время. Для простоты сделаем очередь.
Также стоит заметить, что в тексте могут быть и другие тэги, например, ссылки. Их тоже можно обработать, предварительно вырезав несчастный away.php. Но это уже детали.
Теперь раскроем тайну модуля mymail.
Простейший код отправки сообщений. Я использовал smtp-сервера Яндекса: smtp.yandex.ru:587. Список получателей можно читать из конфига или захардкодить один адрес рассылки, как было в моем случае.
На выходе мы имеем:
Стоит сказать, что данный код является основой, на него можно наворачивать очень много чего. Например, для любителей GUI можно сделать формочку для ввода логина и пароля. Также можно парсить сообщения по имени автора (например, отправлять все сообщения от имени группы), обрабатывать тэги внутри сообщений и прочее, прочее, прочее.
Опыт показывает, что не стоит завышать частоту обновления страницы, все равно все сообщения будут получены, а за излишнюю активность могут наказать временным баном.
Вот собственно и все. Спасибо за внимание!
UPD. Перенес из ВКонтакте в Python.
Наверняка многие сталкивались с ситуацией, что важная информация (новости, объявления и т.д.) публикуется ВКонтакте. Но во-первых, не всегда есть возможность туда попасть (вообще неприлично в рабочее время сидеть вконтакте!), во-вторых информацию приходится получать polling'ом, то есть постоянно обновляя страницу группы или что-нибудь аналогичное.
Отсюда родилась замечательная мысль — было бы удобно, чтобы важные уведомления приходили на почту. И на работе посмотреть можно и
Попытка №1: VK API
Для начала я попробовал быть честным и использовать VK API. В сети я даже сумел отыскать парочку библиотек, которые умели логиниться и выполнять функции из API. К сожалению, ни одна из них меня не устроила, поэтому я умудрился за парочку часов соорудить свой велосипед. Ладно, дело сделано, но тут я наткнулся на неприятный момент, а именно, с помощью текущей версии API нет возможности получить сообщения со стены группы (или я не нашел как это сделать, что тоже вероятно). Остался один вариант — парсить страницы ВКонтакте самостоятельно. С одной стороны, это не очень легально, с другой стороны, такой подход дает возможность получить любую информацию, которую я могу увидеть непосредственно в браузере.
Попытка №2: парсим страницы напрямую!
Логинимся на сайт
Перво-наперво я попытался с помощью httplib и urllib получить страницу логина. Все замечательно и прекрасно. Вот только обнаружилось, что придется писать много некрасивого кода, да еще и с cookies работать… И как-то очень сильно меня это опечалило. Я начал искать замену. И нашел замечательную библиотеку mechanize, которая замечательно сделала за меня всю неинтересную работу по созданию соединений, обработке сессий и cookies и т.д…
Итак, с помощью mechanize получаем главную страницу ВКонтакте:
def initVK(): # Browser br = mechanize.Browser() # Cookie Jar cj = cookielib.LWPCookieJar() br.set_cookiejar(cj) # Browser options br.set_handle_equiv(True) br.set_handle_gzip(True) br.set_handle_redirect(True) br.set_handle_referer(True) br.set_handle_robots(False) # Follows refresh 0 but not hangs on refresh > 0 br.set_handle_refresh(mechanize._http.HTTPRefreshProcessor(), max_time=1) # Little cheating... br.addheaders = [('User-agent', 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.1) Gecko/2008071615 Fedora/3.0.1-1.fc9 Firefox/3.0.1')] br.open('http://vkontakte.ru') br.select_form(nr=0) br.form['email'] = EMAIL br.form['pass'] = PASSWORD br.submit() return br
В качестве пояснения скажу, что на vkontakte.ru первая форма как раз и есть форма логина. С помощью mechanize заполняем ее и вуа-ля, мы залогинились на сайт!
Получаем важные сообщения со стены
Следующий код позволит нам получить страницу группы:
def getGroupHTML(br): br.open('http://vkontakte.ru/OUR_GROUP') html = br.response().read() return html
Теперь непосредственно будем парсить полученный html-код, с целью отыскать в нем нужные сообщения.
Для этого нам потребуется библиотека HTMLParser. Создадим свой класс парсера, который отнаследуем от HTMLParser.
Для простоты будем искать сообщения, которые начинаются с какого-нибудь pattern'а (в своем скрипте я использовал '@year2007').
class MyHTMLParser(HTMLParser): def __init__(self): HTMLParser.__init__(self) self.recording = False self.export_tag = False self.message = unicode('') def handle_starttag(self, tag, attrs): if tag == 'div': for name, value in attrs: if name == 'class' and value == 'wall_text': self.export_tag = True if name == 'class' and value == 'wall_post_text': self.recording = True def handle_endtag(self, tag): if tag == 'div': if self.recording: self.recording = False year = re.compile(PATTERN) if year.match(self.message): message_queue.append(year.sub('', self.message).strip()) self.message = unicode('') if self.export_tag: self.export_tag = False def handle_data(self, data): if self.recording: self.message += unicode(data, 'CP1251')
Весь текст приходит в кодировке CP1251, переводим его в unicode. Слои с классами wall_text отвечают за сообщения, wall_post_text — за сам текст сообщения.
Теперь код получения сообщений можно обернуть в бесконечный цикл. Чтобы не посылать сообщения на почту каждый проход, можно устроить очередь сообщений или пытаться распарсить время. Для простоты сделаем очередь.
Также стоит заметить, что в тексте могут быть и другие тэги, например, ссылки. Их тоже можно обработать, предварительно вырезав несчастный away.php. Но это уже детали.
import codecs message_queue = [] try: f = codecs.open('/tmp/vk-last-message', 'r', encoding='utf-8') last_message = f.read() f.close() if len(last_message.strip()) == 0 : last_message = PATTERN except: last_message = PATTERN import time browser = initVK() import mymail while True: #print "Getting vk.com pages" html = getGroupHTML(browser) p = MyHTMLParser() p.feed(html) #print message_queue msgSent = 0 for msg in message_queue: if msg == last_message : break #messageForSend = processMsg(msg) print msg mymail.sendMessage(msg) msgSent += 1 if len(message_queue) > 0 and msgSent > 0 and len(last_message.strip()) > 0: last_message = message_queue[0] f = codecs.open('/tmp/vk-last-message', 'w', encoding='utf-8') f.write(last_message) f.close() #print "last message: " + last_message message_queue = [] #print "Sleeping..." time.sleep(60)
Отправка сообщения на почту
Теперь раскроем тайну модуля mymail.
import smtplib from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText def sendMessage(text): if len(text) == 0: print "Empty message" return fromaddr = FROM_ADDR toaddrs = LIST_OF_RECEPIENTS #text = 'test message' msg = MIMEMultipart('alternative') msg['Subject'] = "year2007@vkontakte" msg['From'] = fromaddr msg['To'] = toaddrs mime_text = MIMEText(text, 'plain', 'utf-8') msg.attach(mime_text) # Credentials (if needed) username = USER password = PASSWD # The actual mail send server = smtplib.SMTP('SMTP_SERVER:SMTP_PORT') server.starttls() server.login(username,password) server.sendmail(fromaddr, toaddrs, msg.as_string()) server.quit()
Простейший код отправки сообщений. Я использовал smtp-сервера Яндекса: smtp.yandex.ru:587. Список получателей можно читать из конфига или захардкодить один адрес рассылки, как было в моем случае.
Что получилось в итоге
На выходе мы имеем:
- важные сообщения приходят нам на почту, то есть не нужно ходить на ВКонтакте и обновлять страницу самостоятельно
- опыт парсинга страниц
- чувство удовлетворения и гордости собой
Стоит сказать, что данный код является основой, на него можно наворачивать очень много чего. Например, для любителей GUI можно сделать формочку для ввода логина и пароля. Также можно парсить сообщения по имени автора (например, отправлять все сообщения от имени группы), обрабатывать тэги внутри сообщений и прочее, прочее, прочее.
Опыт показывает, что не стоит завышать частоту обновления страницы, все равно все сообщения будут получены, а за излишнюю активность могут наказать временным баном.
Вот собственно и все. Спасибо за внимание!
UPD. Перенес из ВКонтакте в Python.
