1313import requests
1414import time
1515
16- DELAY = 1.0 / 3 # 3 requests per second
16+ DELAY = 0.36 # 3 requests per second
1717CAPTCHA_ERROR_CODE = 14
1818NEED_VALIDATION_CODE = 17
19+ HTTP_ERROR_CODE = - 1
20+
21+ RE_CAPTCHAID = re .compile (r'sid=(\d+)' )
22+ RE_NUMBER_HASH = re .compile (r'security_check.*?hash: \'(.*?)\'\};' )
23+ RE_TOKEN_URL = re .compile (r'location\.href = "(.*?)"\+addr;' )
24+ RE_PHONE_PREFIX = re .compile (r'phone_number">(.*?)<' )
25+ RE_PHONE_POSTFIX = re .compile (r'phone_postfix">(.*?)<' )
1926
2027
2128class VkApi (object ):
29+
2230 def __init__ (self , login = None , password = None , number = None , token = None ,
2331 proxies = None , captcha_handler = None , config_filename = None ,
24- api_version = '5.21 ' , app_id = 2895443 , scope = 2097151 ):
32+ api_version = '5.24 ' , app_id = 2895443 , scope = 2097151 ):
2533 """
2634 :param login: Логин ВКонтакте
2735 :param password: Пароль ВКонтакте
@@ -51,13 +59,16 @@ def __init__(self, login=None, password=None, number=None, token=None,
5159 self .app_id = app_id
5260 self .scope = scope
5361
62+ if not config_filename :
63+ config_filename = 'vk_config.json'
64+
5465 self .settings = jconfig .Config (login , filename = config_filename )
5566
5667 self .http = requests .Session ()
5768 self .http .proxies = proxies # Ставим прокси
5869 self .http .headers = { # Притворимся браузером
59- 'User-agent' : 'Mozilla/5.0 (Windows NT 6.2; WOW64; rv:28 .0) ' \
60- ' Gecko/20100101 Firefox/28 .0'
70+ 'User-agent' : 'Mozilla/5.0 (Windows NT 6.1; rv:31 .0)'
71+ ' Gecko/20100101 Firefox/31 .0'
6172 }
6273 self .http .verify = False
6374
@@ -75,7 +86,7 @@ def __init__(self, login=None, password=None, number=None, token=None,
7586 if not self .check_sid ():
7687 self .vk_login ()
7788 else :
78- self .security_check ('http ://vk.com' )
89+ self .security_check ('https ://vk.com/ ' )
7990
8091 if not self .check_token ():
8192 self .api_login ()
@@ -113,7 +124,7 @@ def vk_login(self, captcha_sid=None, captcha_key=None):
113124 self .sid = remixsid
114125
115126 elif 'sid=' in response .url :
116- captcha_sid = regexp ( r'sid=(\d+)' , response .url )[ 0 ]
127+ captcha_sid = search_re ( RE_CAPTCHAID , response .url )
117128 captcha = Captcha (self , captcha_sid , self .vk_login )
118129
119130 if self .error_handlers [CAPTCHA_ERROR_CODE ]:
@@ -129,25 +140,29 @@ def vk_login(self, captcha_sid=None, captcha_key=None):
129140 def security_check (self , url = None , response = None ):
130141 if url :
131142 response = self .http .get (url )
132- if not 'security_check' in response .url :
143+ if 'security_check' not in response .url :
133144 return
134145
146+ < << << << HEAD
135147 phone_prefix = regexp (r'phone_number">(.*?)<' ,
136148 response .text )
137149 phone_prefix = phone_prefix [0 ].strip ()
138150
139151 phone_postfix = regexp (r'phone_postfix">(.*?)<' ,
140152 response .text )
141153 phone_postfix = phone_postfix [0 ].strip ()
154+ == == == =
155+ phone_prefix = search_re (RE_PHONE_PREFIX , response .text ).strip ()
156+ phone_postfix = search_re (RE_PHONE_POSTFIX , response .text ).strip ()
157+ >> >> >> > refs / remotes / origin / dev
142158
143159 if self .number :
144160 code = code_from_number (phone_prefix , phone_postfix , self .number )
145161 else :
146162 code = code_from_number (phone_prefix , phone_postfix , self .login )
147163
148164 if code :
149- number_hash = regexp (r'security_check.*?hash: \'(.*?)\'\};' ,
150- response .text )[0 ]
165+ number_hash = search_re (RE_NUMBER_HASH , response .text )
151166
152167 values = {
153168 'act' : 'security_check' ,
@@ -196,8 +211,8 @@ def api_login(self):
196211
197212 response = self .http .post (url , values )
198213
199- if not 'access_token' in response .url :
200- url = regexp ( r'location\.href = "(.*?)"\+addr;' , response .text )[ 0 ]
214+ if 'access_token' not in response .url :
215+ url = search_re ( RE_TOKEN_URL , response .text )
201216 response = self .http .get (url )
202217
203218 if 'access_token' in response .url :
@@ -233,6 +248,9 @@ def need_validation_handler(self, error):
233248 # TODO: write me
234249 pass
235250
251+ def http_handler (self , error ):
252+ pass
253+
236254 def method (self , method , values = None , captcha_sid = None , captcha_key = None ):
237255 """ Использование методов API
238256
@@ -249,7 +267,7 @@ def method(self, method, values=None, captcha_sid=None, captcha_key=None):
249267 else :
250268 values = {}
251269
252- if not 'v' in values :
270+ if 'v' not in values :
253271 values .update ({'v' : self .api_version })
254272
255273 if self .token :
@@ -267,16 +285,27 @@ def method(self, method, values=None, captcha_sid=None, captcha_key=None):
267285 if delay > 0 :
268286 time .sleep (delay )
269287
270- response = self .http .post (url , values ). json ()
288+ response = self .http .post (url , values )
271289 self .last_request = time .time ()
272290
291+ if response .ok :
292+ response = response .json ()
293+ else :
294+ error = ApiHttpError (self , method , values , response )
295+ response = self .http_handler (error )
296+
297+ if response is not None :
298+ return response
299+
300+ raise error
301+
273302 if 'error' in response :
274303 error = ApiError (self , method , values , response ['error' ])
275304 error_code = error .code
276305
277306 if error_code in self .error_handlers :
278307 if error_code == CAPTCHA_ERROR_CODE :
279- # TODO: wtf
308+
280309 error = Captcha (
281310 self ,
282311 error .error ['captcha_sid' ],
@@ -292,26 +321,43 @@ def method(self, method, values=None, captcha_sid=None, captcha_key=None):
292321 return response
293322
294323 raise error
295- else :
296- return response ['response' ]
297324
325+ return response ['response' ]
326+
327+
328+ def doc (method = None ):
329+ """ Открывает документацию на метод или список всех методов
330+
331+ :param method: метод
332+ """
333+
334+ if not method :
335+ method = 'methods'
298336
299- def regexp (reg , string ):
337+ url = 'https://vk.com/dev/{}' .format (method )
338+
339+ import webbrowser
340+ webbrowser .open (url )
341+
342+
343+ def search_re (reg , string ):
300344 """ Поиск по регулярке """
345+ m = reg .search (string )
346+ groups = m .groups ()
301347
302- reg = re .compile (reg , re .IGNORECASE | re .DOTALL )
303- reg = reg .findall (string )
304- return reg
348+ if groups :
349+ return groups [0 ]
305350
306351
307352def code_from_number (phone_prefix , phone_postfix , number ):
308353 prefix_len = len (phone_prefix )
309354 postfix_len = len (phone_postfix )
310355
311- if (prefix_len + postfix_len ) > len (number ):
356+ if (prefix_len + postfix_len ) >= len (number ):
312357 return
313358
314359 # Сравниваем начало номера
360+ # TODO: ignore "+" symbole
315361 if not number [:prefix_len ] == phone_prefix :
316362 return
317363
@@ -331,17 +377,19 @@ class BadPassword(AuthorizationError):
331377
332378
333379class SecurityCheck (AuthorizationError ):
380+
334381 def __init__ (self , phone_prefix , phone_postfix ):
335382 self .phone_prefix = phone_prefix
336383 self .phone_postfix = phone_postfix
337384
338385 def __str__ (self ):
339- return 'Security check. Enter number: {}...{}' .format (
386+ return 'Security check. Enter number: {} ... {}' .format (
340387 self .phone_prefix , self .phone_postfix
341388 )
342389
343390
344391class ApiError (Exception ):
392+
345393 def __init__ (self , vk , method , values , error ):
346394 self .vk = vk
347395 self .method = method
@@ -350,14 +398,38 @@ def __init__(self, vk, method, values, error):
350398 self .error = error
351399
352400 def try_method (self ):
401+ """ Пробует отправить запрос заново
402+
403+ """
404+
353405 return self .vk .method (self .method , self .values )
354406
355407 def __str__ (self ):
356408 return '[{}] {}' .format (self .error ['error_code' ],
357409 self .error ['error_msg' ])
358410
359411
412+ class ApiHttpError (object ):
413+
414+ def __init__ (self , vk , method , values , response ):
415+ self .vk = vk
416+ self .method = method
417+ self .values = values
418+ self .response = response
419+
420+ def try_method (self ):
421+ """ Пробует отправить запрос заново
422+
423+ """
424+
425+ return self .vk .method (self .method , self .values )
426+
427+ def __str__ (self ):
428+ return 'Response code {}' .format (self .response .status_code )
429+
430+
360431class Captcha (Exception ):
432+
361433 def __init__ (self , vk , captcha_sid ,
362434 func , args = None , kwargs = None , url = None ):
363435 self .vk = vk
@@ -370,12 +442,21 @@ def __init__(self, vk, captcha_sid,
370442 self .url = url
371443
372444 def get_url (self ):
445+ """ Возвращает ссылку на изображение капчи
446+
447+ """
448+
373449 if not self .url :
374450 self .url = 'http://api.vk.com/captcha.php?sid={}' .format (self .sid )
375451
376452 return self .url
377453
378454 def try_again (self , key ):
455+ """ Отправляет запрос заново с ответом капчи
456+
457+ :param key: текст капчи
458+ """
459+
379460 self .key = key
380461
381462 self .kwargs .update ({
0 commit comments