Добрый день!
Наверняка многие сталкивались с ситуацией, что важная информация (новости, объявления и т.д.) публикуется ВКонтакте. Но во-первых, не всегда есть возможность туда попасть (вообще неприлично в рабочее время сидеть вконтакте!), во-вторых информацию приходится получать 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.