Skip to content

Commit aff8fc8

Browse files
committed
4.7
1 parent f7bf409 commit aff8fc8

5 files changed

Lines changed: 161 additions & 64 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ vk_api
33

44
**vk_api** - модуль для использования API сайта ВКонтакте (vk.com). Пример смотрите в файле [example.py](https://github.com/python273/vk_api/blob/master/example.py)
55

6-
Тестовая поддержка **Python 3**!
6+
Python 2 / 3
77

88
С вопросами или советами можете [написать автору в ВК](https://vk.com/im?sel=183433824).
99

example.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,18 @@ def main():
1919

2020
try:
2121
vk = vk_api.VkApi(login, password) # Авторизируемся
22-
except vk_api.authorization_error as error_msg:
22+
except vk_api.AuthorizationError as error_msg:
2323
print(error_msg) # В случае ошибки выведем сообщение
2424
return # и выйдем
2525

2626
values = {
27-
'count': 1 # Получаем только одно сообщение
27+
'count': 1 # Получаем только один пост
2828
}
2929
response = vk.method('wall.get', values) # Используем метод wall.get
30-
print(response['items'][0]['text']) # Печатаем текст последнего поста со стены
30+
31+
if response['items']:
32+
# Печатаем текст последнего поста со стены
33+
print(response['items'][0]['text'])
3134

3235
if __name__ == '__main__':
3336
main()

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
from distutils.core import setup
1313
setup(name='vk_api',
14-
version='4.6.6',
14+
version='4.7',
1515
description='Module to use API vk.com',
1616
author='Kirill Python',
1717
author_email='mikeking568@gmail.com',

vk_api/vk_api.py

Lines changed: 149 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,25 @@
1414
import time
1515

1616
DELAY = 1.0 / 3 # 3 requests per second
17+
CAPTCHA_ERROR_CODE = 14
18+
NEED_VALIDATION_CODE = 17
1719

1820

1921
class VkApi(object):
20-
def __init__(self,
21-
login=None, password=None, number=None,
22-
token=None,
23-
proxies=None,
24-
version='5.5', app_id=2895443, scope=2097151):
22+
def __init__(self, login=None, password=None, number=None, token=None,
23+
proxies=None, captcha_handler=None,
24+
api_version='5.21', app_id=2895443, scope=2097151):
2525
'''
2626
:param login: Логин ВКонтакте
2727
:param password: Пароль ВКонтакте
28-
:param number: Номер при проверке безопасности
29-
Номер: +7 12345678 90
30-
number = 12345678
28+
:param number: Номер для проверке безопасности (указывать, если
29+
в качестве логина используется не номер)
30+
3131
:param token: access_token
3232
:param proxies: proxy server
3333
{'http': 'http://127.0.0.1:8888/',
34-
'https' : 'https://127.0.0.1:8888/'}
35-
:param version: Версия API (default: '5.0')
34+
'https': 'https://127.0.0.1:8888/'}
35+
:param api_version: Версия API (default: '5.21')
3636
:param app_id: Standalone-приложение (default: 2895443)
3737
:param scope: Запрашиваемые права (default: 2097151)
3838
'''
@@ -44,7 +44,7 @@ def __init__(self,
4444
self.sid = None
4545
self.token = {'access_token': token}
4646

47-
self.version = version
47+
self.api_version = api_version
4848
self.app_id = app_id
4949
self.scope = scope
5050

@@ -53,19 +53,26 @@ def __init__(self,
5353
self.http = requests.Session()
5454
self.http.proxies = proxies # Ставим прокси
5555
self.http.headers = { # Притворимся браузером
56-
'User-agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:20.0) ' \
57-
'Gecko/20100101 Firefox/20.0'
56+
'User-agent': 'Mozilla/5.0 (Windows NT 6.2; WOW64; rv:28.0) ' \
57+
'Gecko/20100101 Firefox/28.0'
5858
}
5959
self.http.verify = False
6060

6161
self.last_request = 0.0
6262

63+
self.error_handlers = {
64+
NEED_VALIDATION_CODE: self.need_validation_handler,
65+
CAPTCHA_ERROR_CODE: captcha_handler or self.captcha_handler
66+
}
67+
6368
if login and password:
6469
self.sid = self.settings['remixsid']
6570
self.token = self.settings['access_token']
6671

6772
if not self.check_sid():
6873
self.vk_login()
74+
else:
75+
self.security_check('http://vk.com')
6976

7077
if not self.check_token():
7178
self.api_login()
@@ -103,39 +110,47 @@ def vk_login(self, captcha_sid=None, captcha_key=None):
103110
self.sid = remixsid
104111

105112
elif 'sid=' in response.url:
106-
raise authorization_error('Authorization error (capcha)')\
107-
# TODO: write me
108-
# Capcha handler
109-
# Capcha object
113+
captcha_sid = regexp(r'sid=(\d+)', response.url)[0]
114+
captcha = Captcha(self, captcha_sid, self.vk_login)
115+
116+
if self.error_handlers[CAPTCHA_ERROR_CODE]:
117+
self.error_handlers[CAPTCHA_ERROR_CODE](captcha)
118+
else:
119+
raise AuthorizationError('Authorization error (capcha)')
110120
else:
111-
raise authorization_error('Authorization error (bad password)')
121+
raise BadPassword('Bad password')
112122

113123
if 'security_check' in response.url:
114-
self.security_check(response)
124+
self.security_check(response=response)
115125

116126
def security_check(self, url=None, response=None):
117127
if url:
118128
response = self.http.get(url)
129+
if not 'security_check' in response.url:
130+
return
119131

120-
# Проверяем, является ли логин номером
121-
if not self.number:
122-
phone_postfix = regexp(r'class="phone_postfix">(.*?)</span>',
123-
response.text)
124-
125-
phone_postfix = phone_postfix[0].strip()
132+
phone_prefix = regexp(r'label ta_r">(.*?)<',
133+
response.text)
134+
phone_prefix = phone_prefix[0].strip()
126135

127-
if self.login[-len(phone_postfix):] == phone_postfix:
128-
self.number = self.login
136+
phone_postfix = regexp(r'phone_postfix">(.*?)<',
137+
response.text)
138+
phone_postfix = phone_postfix[0].strip()
129139

130140
if self.number:
141+
code = code_from_number(phone_prefix, phone_postfix, self.number)
142+
else:
143+
code = code_from_number(phone_prefix, phone_postfix, self.login)
144+
145+
if code:
131146
number_hash = regexp(r'security_check.*?hash: \'(.*?)\'\};',
132147
response.text)[0]
133148

134149
values = {
135150
'act': 'security_check',
136151
'al': '1',
137152
'al_page': '3',
138-
'code': self.number,
153+
'code': code,
139154
'hash': number_hash,
140155
'to': ''
141156
}
@@ -145,8 +160,7 @@ def security_check(self, url=None, response=None):
145160
if response.text.split('<!>')[4] == '4':
146161
return True
147162

148-
raise authorization_error('Security check (enter number)')
149-
163+
raise SecurityCheck('Enter number')
150164

151165
def check_sid(self):
152166
''' Прверка Cookies remixsid на валидность '''
@@ -194,28 +208,38 @@ def api_login(self):
194208
self.settings['access_token'] = token
195209
self.token = token
196210
else:
197-
raise authorization_error('Authorization error (api)')
211+
raise AuthorizationError('Authorization error (api)')
198212

199213
def check_token(self):
200214
''' Прверка access_token на валидность '''
201215

202216
if self.token:
203217
try:
204218
self.method('isAppUser')
205-
except apiError:
219+
except ApiError:
206220
return False
207221

208222
return True
209223

210-
def method(self, method, values=None):
211-
''' Использование методов API
224+
def captcha_handler(self, captcha):
225+
''' http://vk.com/dev/captcha_error '''
226+
pass
212227

213-
param: method - название метода
214-
'users.get'
228+
def need_validation_handler(self, error):
229+
''' http://vk.com/dev/need_validation '''
230+
# TODO: write me
231+
pass
232+
233+
def method(self, method, values=None, captcha_sid=None, captcha_key=None):
234+
'''
235+
Использование методов API
215236
216-
param: values - параметры
217-
{'uids': 1}
237+
:param method: метод
238+
:param values: параметры
239+
:param captcha_sid:
240+
:param captcha_key:
218241
'''
242+
219243
url = 'https://api.vk.com/method/%s' % method
220244

221245
if values:
@@ -224,30 +248,46 @@ def method(self, method, values=None):
224248
values = {}
225249

226250
if not 'v' in values:
227-
values.update({'v': self.version})
251+
values.update({'v': self.api_version})
228252

229253
if self.token:
230254
values.update({'access_token': self.token['access_token']})
231255

256+
if captcha_sid and captcha_key:
257+
values.update({
258+
'captcha_sid': captcha_sid,
259+
'captcha_key': captcha_key
260+
})
261+
232262
# Ограничение 3 запроса в секунду
233-
sleep = DELAY - (time.time() - self.last_request)
263+
delay = DELAY - (time.time() - self.last_request)
234264

235-
if sleep > 0:
236-
time.sleep(sleep)
265+
if delay > 0:
266+
time.sleep(delay)
237267

238268
response = self.http.post(url, values).json()
239269
self.last_request = time.time()
240270

241271
if 'error' in response:
242-
# TODO: write me
243-
# Capcha handler
244-
# Capcha object
245-
246-
error = apiError(response['error'], self, method, values)
247-
248-
if error.code == 17:
249-
print 'HANDLER 17'
250-
# TODO: number handler
272+
error = ApiError(self, method, values, response['error'])
273+
error_code = error.code
274+
275+
if error_code in self.error_handlers:
276+
if error_code == CAPTCHA_ERROR_CODE:
277+
# TODO: wtf
278+
error = Captcha(
279+
self,
280+
error.error['captcha_sid'],
281+
self.method,
282+
(method,),
283+
{'values': values},
284+
error.error['captcha_img']
285+
)
286+
287+
response = self.error_handlers[error_code](error)
288+
289+
if response is not None:
290+
return response
251291

252292
raise error
253293
else:
@@ -262,29 +302,79 @@ def regexp(reg, string):
262302
return reg
263303

264304

265-
class vk_api_error(Exception):
305+
def code_from_number(phone_prefix, phone_postfix, number):
306+
prefix_len = len(phone_prefix)
307+
postfix_len = len(phone_postfix)
308+
309+
if (prefix_len + postfix_len) > len(number):
310+
return
311+
312+
# Сравниваем начало номера
313+
if not number[:prefix_len] == phone_prefix:
314+
return
315+
316+
# Сравниваем конец номера
317+
if not number[-postfix_len:] == phone_postfix:
318+
return
319+
320+
return number[prefix_len:-postfix_len]
321+
322+
323+
class AuthorizationError(Exception):
266324
pass
267325

268326

269-
class authorization_error(vk_api_error):
327+
class BadPassword(AuthorizationError):
270328
pass
271329

272330

273-
class apiError(Exception):
274-
def __init__(self, error, vk, method, values):
275-
self.error = error
331+
class SecurityCheck(AuthorizationError):
332+
pass
333+
334+
335+
class ApiError(Exception):
336+
def __init__(self, vk, method, values, error):
276337
self.vk = vk
277338
self.method = method
278339
self.values = values
279340
self.code = error['error_code']
341+
self.error = error
280342

281343
def try_method(self):
282344
return self.vk.method(self.method, self.values)
283345

284346
def __str__(self):
285-
return self.error['error_msg']
347+
return '[{}] {}'.format(self.error['error_code'],
348+
self.error['error_msg'])
286349

287350

288-
class Capcha():
289-
pass
351+
class Captcha(Exception):
352+
def __init__(self, vk, captcha_sid,
353+
func, args=None, kwargs=None, url=None):
354+
self.vk = vk
355+
self.sid = captcha_sid
356+
self.func = func
357+
self.args = args or ()
358+
self.kwargs = kwargs or {}
359+
360+
self.key = None
361+
self.url = url
362+
363+
def get_url(self):
364+
if not self.url:
365+
self.url = 'http://api.vk.com/captcha.php?sid={}'.format(self.sid)
366+
367+
return self.url
290368

369+
def try_again(self, key):
370+
self.key = key
371+
372+
self.kwargs.update({
373+
'captcha_sid': self.sid,
374+
'captcha_key': self.key
375+
})
376+
377+
return self.func(*self.args, **self.kwargs)
378+
379+
def __str__(self):
380+
return 'Captcha needed'

vk_api/vk_tools.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# encoding: utf-8
22
import json
3+
import sys
4+
5+
if sys.version_info[0] == 3:
6+
xrange = range
37

48

59
class VkTools(object):

0 commit comments

Comments
 (0)