Простой бот для приложений Вконтакте на Python

25 марта 2011 г.

Думаю все знают про приложения-игралки, со всяким рейтингом среди друзей, популярные среди обитателей вконтакта. В этом топике я расскажу, как можно быть в них на первом месте, при этом не задрачиваясь, и не отупляя свой мозг.

Бот для Вконтакте
В большинстве случаев, приложения обмениваются с сервером информацией по HTTP, посылая информацию POST-запросом, в ответ получая XML. Наша задача состоит в том, чтобы эмитировать эти запросы. Нашим подопытным кроликом будет приложение «Тюгяга»

Какие инструменты нам потребуются:

  • Python — Любимый всеми язык. Будем использовать только стандартную библиотеку.
  • Charles — простой HTTP-прокси. Его мы будем использовать для перехвата и анализа запросов.

Итак, приступим:

Для начала запустим Charles. Разобраться в нём сможет даже ребёнок. Приложение советую запускать в Firefox’е. Попробуйте выполнить какое-нибудь действие в «Тюряге», например собрать сигареты, и посмотрите на последний запрос. В общем случае вы увидите что-то вроде этого:

POST /prison/universal.php?office HTTP/1.1
Host: 109.234.156.250
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; ru; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ru-ru,ru;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Referer: xxxxx
Content-type: application/x-www-form-urlencoded
Content-length: 111

method=office&sig=4b8874255d3f868e4e9f4006e51635de&user=xxxxxxxxx&getidea=1&key=xxxxxxxxxxxxxx

Тут мы имеем URI, HTTP-заголовки, пустую строку, и данные, отправленные на сервер. Что же отправляется на сервер:

key — Ключ, необходимый для идентификации вас именно в этом приложении. Предоставляется контактом, для каждого приложения разный. По этому ключу невозможно взломать вашу страницу или узнать какие-нибудь ваши данные. Периодически меняется, кстати.

user — Ваш id.

sig — Сигнатура, генерируемая тюрягой. Честно говоря, я не разобрался для чего она служит и по какому принципу генерируется. Но без неё никак. Лично я просто отловил их несколько штук и рандомно подставляю для каждого запроса. :)

method — Сообщает серверу, что за действие вы совершили.

Отправляются ещё и дополнительные данные, такие как getidea — сообщает сколько сигарет вы собрали.

Переходим к питону:

#!/usr/bin/env python3
# t.py
 
import urllib, time, http.client, random, threading
from xml.dom import minidom

Импортируем необходимые модули из стандартной библиотеки
xml.dom.minidom нужен если вы собирайтесь обрабатывать XML-ответ.

sigs = ('21ddcf3ea352f24ebdfe65bce51258da','4b8874255d3f868e4e9f4006e51635de','8dbedd3e931c8fd4fc97fa0fa74a1a20',
'2243effc5a45a32c67b06898fb0b9548','7f47c0b6e9e385b8234ca9dce375a0c5','bdab387b62bed654492b8c93670a537e',
'f17687ea1a535d61124dadb30887d14c','938b2f649aec28319ae2433ead41dae5')
 
h ={
'Host':'188.93.20.139',
'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; ru; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15',
'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language':'ru-ru,ru;q=0.8,en-us;q=0.5,en;q=0.3',
'Accept-Charset':'windows-1251,utf-8;q=0.7,*;q=0.7',
'Keep-Alive':'115',
'Content-type':'application/x-www-form-urlencoded',
}
 
u = 'Ваш_ID'
k = 'Ваш key, для идентификации в приложении'

Создаём кортеж из сигнатур, заголовки в форме словаря(лишние я удалил), и две переменные.

def request(post):
global h # используем в функции глобальную переменную h
connection = http.client.HTTPConnection('109.234.155.196:80') # Создаём объект соединения
connection.request('POST', '/prison/universal.php', body = post, headers = h) # отправляем запрос
resp = connection.getresponse() # получаем ответ
return resp.read() # возвращаем ответ из функции

Т.к. отправлять данные на придётся часто, создадим для этого отдельную функцию

def take_sigareties():
    global sigs, u, k # используем в функции глобальные переменные
    post = urllib.parse.urlencode({
    'method' : 'office',
    'getidea' : '5',
    'sig' : random.choice(sigs),
    'user' : u,
    'key' : k
    }) # с помощью метода urllib.parse.urlencode подготавливаем данные для отправки. данные скармливаем методу в виде словаря
 
    while True: # запускаем бесконечный цикл
        for _ in range(0,20): # запускае цикл for на 20 раз
            request(post) # с помощью функции, которую мы создали ранее, отправляем данные на сервер
            print('Собрал сиги')
            time.sleep(5*20*60+15) # усыпляем поток выполнения на 6015 секунд. т.е. следующая итерация for произойдёт через указанное время.
        time.sleep(8*60*60) # после того как собрали 20 раз сиги, усыпляем поток на 8 часиков, чтобы нас не спалили ;)

Создаём функцию для сбора сигареток

По аналогии создадим функцию для сбора прибыли раз в 8 часов:

def take_rewards():
    global sigs, u, k
    post = urllib.parse.urlencode({
    'method' : 'getAllBuildingsRewards',
    'sig' : random.choice(sigs),
    'user' : u,
    'key' : k
    })
 
    while True:
        request(post)
        print('Собрал прибыль')
        time.sleep(8*60*60+15)

Т.к. нам надо чтобы функции работали независимо друг от друга, запустим их в отдельных потоках:

t1 = threading.Thread(target = take_sigareties)
# создаём объект потока, target'у подаётся созданная функция
t1.deamon = True # это нужно для того, чтобы при закрытии основного потока, дочерний поток тоже закрывался
 
t2 = threading.Thread(target = take_rewards)
t2.deamon = True
 
t1.start() # запускаем поток на выполнение 
t2.start()

На этом собственно всё, запускаем скрипт, и радуемся, что больше не надо заходить в приложение каждые 20 минут, чтобы собрать сигоретки.

По аналогии можно писать ботов для других приложений.

Вот полный код бота.

#!/usr/bin/env python3
# t.py

import urllib, time, http.client, random, threading
from xml.dom import minidom

sigs = ('21ddcf3ea352f24ebdfe65bce51258da','4b8874255d3f868e4e9f4006e51635de','8dbedd3e931c8fd4fc97fa0fa74a1a20',
'2243effc5a45a32c67b06898fb0b9548','7f47c0b6e9e385b8234ca9dce375a0c5','bdab387b62bed654492b8c93670a537e',
'f17687ea1a535d61124dadb30887d14c','938b2f649aec28319ae2433ead41dae5')

h ={
'Host':'188.93.20.139',
'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; ru; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15',
'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language':'ru-ru,ru;q=0.8,en-us;q=0.5,en;q=0.3',
'Accept-Charset':'windows-1251,utf-8;q=0.7,*;q=0.7',
'Keep-Alive':'115',
'Content-type':'application/x-www-form-urlencoded',
}

u = 'Ваш_ID'
k = 'Ваш key'

def request(post):
    global h # используем в функции глобальную переменную h
    connection = http.client.HTTPConnection('109.234.155.196:80') # Создаём объект соединения
    connection.request('POST', '/prison/universal.php', body = post, headers = h) # отправляем запрос
    resp = connection.getresponse() # получаем ответ
    return resp.read() # возвращаем ответ из функции
    

def take_rewards():
    global sigs, u, k
    post = urllib.parse.urlencode({
    'method' : 'getAllBuildingsRewards',
    'sig' : random.choice(sigs),
    'user' : u,
    'key' : k
    })

    while True:
        request(post)
        print('Собрал прибыль')
        time.sleep(8*60*60+15)

def take_sigareties():
    global sigs, u, k # используем в функции глобальные переменные
    post = urllib.parse.urlencode({
    'method' : 'office',
    'getidea' : '5',
    'sig' : random.choice(sigs),
    'user' : u,
    'key' : k
    }) # с помощью метода urllib.parse.urlencode подготавливаем данные для отправки. данные скармливаем методу в виде словаря

    while True: # запускаем бесконечный цикл
        for _ in range(0,20): # запускае цикл for на 20 раз
            request(post) # с помощью функции, которую мы создали ранее, отправляем данные на сервер
            print('Собрал сиги')
            time.sleep(5*20*60+15) # усыпляем поток выполнения на 6015 секунд. т.е. следующая итерация for произойдёт через указанное время.
        time.sleep(8*60*60) # после того как собрали 20 раз сиги, усыпляем поток на 8 часиков, чтобы нас не спалили ;)

def do_city_action():
    global sigs, u, k
    while True:
        action_id = 1
        while action_id < 8:
            for _ in range(0,5):
                post = urllib.parse.urlencode({
                'method' : 'doCityAction',
                'city' : '1',
                'action_id' : str(action_id),
                'action_type' : '3',
                'sig' : random.choice(sigs),
                'user' : u,
                'key' : k
                })
                response = request(post)
                print('Выполнил задание')
                if int(minidom.parseString(str(response, 'utf8')).getElementsByTagName('energy')[0].firstChild.data) < 10:
                    time.sleep(40*5*60)
            action_id +=1

def vote_friends_to_gym():
    global sigs, u, k
    friends = () # кортеж друзей, которых вы хотите позвать в спортзал
    while True:
        for friend in friends:
            post = urllib.parse.urlencode({
            'method' : 'voteForFriend',
            'model_id' : '1',
            'sex' : '0',
            'friend_uid' : friend,
            'vote' : '5',
            'username' : 'London Eyes',
            'sig' : random.choice(sigs),
            'user' : u,
            'key' : k
            })
            request(post)
            print('Позвал ' + friend + ' в спортзал')
        time.sleep(24*60*60+15)

def break_terpilas_faces():
    global sigs, u, k
    terpilas = () # кортеж друзей, на которых вы хотите наехать
    while True:
        for terpila in terpilas:
            post = urllib.parse.urlencode({
            'method' : 'challengeToDuel',
            'enemy' : terpilas,
            'sig' : random.choice(sigs),
            'user' : u,
            'key' : k
            })
            request(post)
            print('Наехал на ' + terpila)
        time.sleep(24*60*60+15)
        
def send_presents():
    recipients = '' # чезез запятую id друзей, которым вы хотите заслать подогрев
    while True:
        post = urllib.parse.urlencode({
        'method' : 'sendPresent',
        'recipients' : recipients,
        'present_id' : '5',
        'sig' : random.choice(sigs),
        'user' : u,
        'key' : k
        })
        request(post)
        print('Послал подогревы')
        time.sleep(24*60*60+15)        

t1 = threading.Thread(target = take_rewards) # создаём объект потока, target'у подаётся созданная функция
t1.deamon = True # это нужно для того, чтобы при закрытии основного потока, дочерний поток тоже закрывался

t2 = threading.Thread(target = take_sigareties)
t2.deamon = True

t3 = threading.Thread(target = do_city_action)
t3.deamon = True

t4 = threading.Thread(target = vote_friends_to_gym)
t4.deamon = True

t5 = threading.Thread(target = break_terpilas_faces)
t5.deamon = True

t6 = threading.Thread(target = send_presents)
t6.deamon = True

t1.start() # запускаем поток на выполнение 
t2.start()
t3.start()
t4.start()
t5.start()
t6.start()
Теги: рубрика Программирование
  • Похожие статьи
  • Предыдущие из рубрики