Today I was again asked to remind a person of an important thing at a certain time. But what to do if I forget about my business all the time, and even more so about someone else's business? And here my favorite python helped me again.

Honestly, the usual reminder programs that in the phone, in the computer, did not suit me because of their limited scope of the device + they didn’t solve the problem at all, when you need to remind about something, but not me. The decision came somehow by itself. And what if reminders will come as messages on VKontakte? If I'm not at work, the phone vibrates with its push-up notification, and at the computer it is still more obvious. The goal is to write a script that reads my reminder messages and at a given time reminds someone who needs what is actually required. Well, once the idea came, I proceed to implement it.
We start
Attention! In this article I will show how to do this without using the Vkontakte API. But for those who want to see (or use) how this is done using, in fact, the API, I attach a version of the script that works through the API. Link to it at the end of the article.
')
To begin with we will teach our script to login to this social network. It's simple, use the standard mechanize.Browser ()
br = mechanize.Browser() br.set_handle_equiv(True) br.set_handle_redirect(True) br.set_handle_robots(False) br.open('https://vk.com/') br.select_form(nr=0) br.form['email'] = name br.form['pass'] = password br.submit()
Voila! We went to your VKontakte page. Now we use the cool feature of VKontakte - the ability to write to yourself (who does not know how to do it - go to
vk.com/im?sel=id , where id is your id in the social network. In my case it was 38591009).
First read these messages. To do this, I need to know my id (it is in the code of the main page, and repeated many times).
self_username = 'username' def get_self_page_id(br): br.open('https://vk.com/'+self_username) return br.response().read().split('<form action="/wall')[1].split('?')[0] def check_messages(br): br.open('https://vk.com/im?sel='+get_self_page_id(br)) response = br.response().read()
We see the last 20 messages from those that they themselves and sent. This is enough for us. Each message has its own unique (for the user) number, it is very useful to us. Then you need to play with them a bit to separate all the messages, separate the text from the sequence number and teach the script to understand which messages are new and which are no longer relevant.
first_start = True msg_numbers = [] # . , , . def play_with_messages(br, response): global first_start all_messages = response.split('class="messages bl_cont">')[1].split('<div id="mfoot"')[0].split('<a name="msg') all_numbers = [] global msg_numbers for msg in all_messages: if msg != all_messages[0]: msg_num = msg.split('">')[0] all_numbers.append(msg_num) if first_start: msg_numbers = all_numbers first_start = False new_numbers = set(all_numbers) - set(all_numbers).intersection(set(msg_numbers)) for num in new_numbers: reply_to_message(br, get_message_text(response, num)) # . . msg_numbers = all_numbers
We start the internal dialogue
Fine. Now we know what messages I received from me recently. It remains to understand them and do something in response. Let's do the first task first:
def reply_to_message(br, message): if message.find('') == -1: print 'nothing' else: print 'I obey, my lord' ms_words = message.split(' ') user = 'self' time_s = datetime.datetime.now().strftime('%H:%M') day_s = str(datetime.date.today()) msg = 'something went wrong' times = message.split('|') if len(times) == 1: times = '1' else: times = int(times[1]) if ms_words[1] == '': user = 'self' time_s = ms_words[2] msg = message.split(' ')[1].split('|')[0] elif ms_words[1] == '': user = 'self' time_s = ms_words[4] day_s = ms_words[2] msg = message.split(' ')[1].split('|')[0] elif ms_words[2] == '': user = get_page_id(br, ms_words[1]) time_s = ms_words[3] msg = message.split(' ')[1].split('|')[0] elif ms_words[2] == '': user = get_page_id(br, ms_words[1]) time_s = ms_words[5] day_s = ms_words[3] msg = message.split(' ')[1].split('|')[0] let_it_do(user, time_s, day_s, msg, times)
Here I splichu received messages and bring in variables the corresponding values. In general, I answer the questions “to remind whom?”, “What to remind?”, “When and how many times to do it?”. The syntax of the message / command is not complicated: recall [to whom] [date] at [time] text [message text] | [how many times]. Here is an example: “remind tenoclock at 2:10 pm text Another test | four"
So our robot sees the internal dialogueTo store tasks, I chose the sqlite3 database. Our load is minimal, it unfolds completely effortlessly. Now let's start writing jobs to the database, checking the validity of the date and time along the way. It looks like this:
def valid_time(time_text): try: datetime.datetime.strptime(time_text, '%H:%M') return True except ValueError: send_message(br_fake, get_self_page_id(br), ' ') return False def valid_date(date_text): try: datetime.datetime.strptime(date_text, '%Y-%m-%d') return True except ValueError: send_message(br_fake, get_self_page_id(br), ' ') return False def let_it_do(user, time_s, day_s, message, times): if valid_time(time_s) and valid_date(day_s): c = conn.cursor() c.execute("INSERT INTO reminder (time, date, user, message, times) VALUES (?,?,?,?,?)",(time_s, day_s, user, message, str(times))) conn.commit()
Finish line
We are already close to the final! Tasks our robot received, recorded them myself. In fact, it remains only to complete them. Then I ran into a little difficulty. The script constantly reads my messages to me, therefore, if it will send them to the same dialogue, then in the unread I will not hang anything. Is that bad. The problem was solved by the establishment of a fake account for this case. Now, if the script reminds me of something, it writes from the second account, if you need to remind someone else, then he writes on my behalf, so as not to frighten people.
Actually, here are a couple of functions that are responsible for reading from the database and sending messages:
def check_answers(): conn = sqlite3.connect('reminder.db') rows = get_rows(conn) for row in rows: print row[5] c = conn.cursor() if row[3] == 'self': pass send_message(br_fake, get_self_page_id(br), row[4].encode('utf-8')) else: send_message(br, row[3], row[4].encode('utf-8')) if row[5] == '1' or row[5] == 1: c.execute("DELETE FROM reminder WHERE id = ?;", str(row[0])) else: time_s = (datetime.datetime.now()+datetime.timedelta(seconds=60)).strftime('%H:%M') num = int(row[5]) - 1 c.execute("UPDATE reminder SET time = ?, times = ? WHERE id = ?",(time_s, str(num), row[0])) conn.commit() def send_message(br, id, message): br.open('https://vk.com/im?sel='+id) br.select_form(nr=0) br.form['message'] = message br.submit()
Well, after sending messages, the script deletes the record from the database if it is not relevant (if you need to repeat a few more times, then it takes the reminder time one minute ahead and reduces the number of remaining shipments)
Summing up
So the script, which fits into 200 lines of code, solves the problem of reminding yourself and others, using the social network vkontakte. Entirely it can be downloaded
from here . If he is suddenly needed by someone, then I advise you not to collect from the pieces of the article, here only functional things. Some auxiliary things stayed behind the scenes. I ran it on one of my vps. So far, sort of, convenient.
The robot tells me what to do. On Sunday! SurvivedAfter simple modifications, you can also enable any other system management functions here if the script is running on a remote computer. Put the same torrent to download, for example. And so, in general, you can implement a web service that will deal with reminders for everyone who asks (in fact, the bot, as in, already forgotten now, irc and icq) But these things no longer apply to this article. I would be very happy if this was useful to someone.
Thank you all for your attention.
UPD: Do not rush to kindle torches and sharpen forks about the API. I deliberately do not use it in this script because of some uncomfortable places. Namely authorization and work with dialogues. However, in the first comments I opened this topic. The purpose of this article is to show how quickly and, practically, without using third-party information, apart from knowing the native language for a developer, to make life somewhat easier.
UPD # 2: The same script, but using the powerful API Vkontakte can be taken
here . Now it works without using a fake account. This is a definite plus.