1616DELAY = 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 ,
2432 api_version = '5.21' , app_id = 2895443 , scope = 2097151 ):
@@ -116,7 +124,7 @@ def vk_login(self, captcha_sid=None, captcha_key=None):
116124 self .sid = remixsid
117125
118126 elif 'sid=' in response .url :
119- captcha_sid = regexp ( r'sid=(\d+)' , response .url )[ 0 ]
127+ captcha_sid = search_re ( RE_CAPTCHAID , response .url )
120128 captcha = Captcha (self , captcha_sid , self .vk_login )
121129
122130 if self .error_handlers [CAPTCHA_ERROR_CODE ]:
@@ -135,22 +143,16 @@ def security_check(self, url=None, response=None):
135143 if 'security_check' not in response .url :
136144 return
137145
138- phone_prefix = regexp (r'label ta_r">(.*?)<' ,
139- response .text )
140- phone_prefix = phone_prefix [0 ].strip ()
141-
142- phone_postfix = regexp (r'phone_postfix">(.*?)<' ,
143- response .text )
144- phone_postfix = phone_postfix [0 ].strip ()
146+ phone_prefix = search_re (RE_PHONE_PREFIX , response .text ).strip ()
147+ phone_postfix = search_re (RE_PHONE_POSTFIX , response .text ).strip ()
145148
146149 if self .number :
147150 code = code_from_number (phone_prefix , phone_postfix , self .number )
148151 else :
149152 code = code_from_number (phone_prefix , phone_postfix , self .login )
150153
151154 if code :
152- number_hash = regexp (r'security_check.*?hash: \'(.*?)\'\};' ,
153- response .text )[0 ]
155+ number_hash = search_re (RE_NUMBER_HASH , response .text )
154156
155157 values = {
156158 'act' : 'security_check' ,
@@ -200,7 +202,7 @@ def api_login(self):
200202 response = self .http .post (url , values )
201203
202204 if 'access_token' not in response .url :
203- url = regexp ( r'location\.href = "(.*?)"\+addr;' , response .text )[ 0 ]
205+ url = search_re ( RE_TOKEN_URL , response .text )
204206 response = self .http .get (url )
205207
206208 if 'access_token' in response .url :
@@ -236,6 +238,9 @@ def need_validation_handler(self, error):
236238 # TODO: write me
237239 pass
238240
241+ def http_handler (self , error ):
242+ pass
243+
239244 def method (self , method , values = None , captcha_sid = None , captcha_key = None ):
240245 """ Использование методов API
241246
@@ -270,16 +275,27 @@ def method(self, method, values=None, captcha_sid=None, captcha_key=None):
270275 if delay > 0 :
271276 time .sleep (delay )
272277
273- response = self .http .post (url , values ). json ()
278+ response = self .http .post (url , values )
274279 self .last_request = time .time ()
275280
281+ if response .ok :
282+ response = response .json ()
283+ else :
284+ error = ApiHttpError (self , method , values , response )
285+ response = self .http_handler (error )
286+
287+ if response is not None :
288+ return response
289+
290+ raise error
291+
276292 if 'error' in response :
277293 error = ApiError (self , method , values , response ['error' ])
278294 error_code = error .code
279295
280296 if error_code in self .error_handlers :
281297 if error_code == CAPTCHA_ERROR_CODE :
282- # TODO: wtf
298+
283299 error = Captcha (
284300 self ,
285301 error .error ['captcha_sid' ],
@@ -295,8 +311,8 @@ def method(self, method, values=None, captcha_sid=None, captcha_key=None):
295311 return response
296312
297313 raise error
298- else :
299- return response ['response' ]
314+
315+ return response ['response' ]
300316
301317
302318def doc (method = None ):
@@ -314,12 +330,13 @@ def doc(method=None):
314330 webbrowser .open (url )
315331
316332
317- def regexp (reg , string ):
333+ def search_re (reg , string ):
318334 """ Поиск по регулярке """
335+ m = reg .search (string )
336+ groups = m .groups ()
319337
320- reg = re .compile (reg , re .IGNORECASE | re .DOTALL )
321- reg = reg .findall (string )
322- return reg
338+ if groups :
339+ return groups [0 ]
323340
324341
325342def code_from_number (phone_prefix , phone_postfix , number ):
@@ -330,6 +347,7 @@ def code_from_number(phone_prefix, phone_postfix, number):
330347 return
331348
332349 # Сравниваем начало номера
350+ # TODO: ignore "+" symbole
333351 if not number [:prefix_len ] == phone_prefix :
334352 return
335353
@@ -349,17 +367,19 @@ class BadPassword(AuthorizationError):
349367
350368
351369class SecurityCheck (AuthorizationError ):
370+
352371 def __init__ (self , phone_prefix , phone_postfix ):
353372 self .phone_prefix = phone_prefix
354373 self .phone_postfix = phone_postfix
355374
356375 def __str__ (self ):
357- return 'Security check. Enter number: {}...{}' .format (
376+ return 'Security check. Enter number: {} ... {}' .format (
358377 self .phone_prefix , self .phone_postfix
359378 )
360379
361380
362381class ApiError (Exception ):
382+
363383 def __init__ (self , vk , method , values , error ):
364384 self .vk = vk
365385 self .method = method
@@ -379,7 +399,27 @@ def __str__(self):
379399 self .error ['error_msg' ])
380400
381401
402+ class ApiHttpError (object ):
403+
404+ def __init__ (self , vk , method , values , response ):
405+ self .vk = vk
406+ self .method = method
407+ self .values = values
408+ self .response = response
409+
410+ def try_method (self ):
411+ """ Пробует отправить запрос заново
412+
413+ """
414+
415+ return self .vk .method (self .method , self .values )
416+
417+ def __str__ (self ):
418+ return 'Response code {}' .format (self .response .status_code )
419+
420+
382421class Captcha (Exception ):
422+
383423 def __init__ (self , vk , captcha_sid ,
384424 func , args = None , kwargs = None , url = None ):
385425 self .vk = vk
0 commit comments