Skip to content

Commit 4ab707e

Browse files
committed
Merge remote-tracking branch 'origin/dev'
Conflicts: setup.py vk_api/__init__.py vk_api/vk_api.py
2 parents 9b15c73 + defe031 commit 4ab707e

5 files changed

Lines changed: 153 additions & 42 deletions

File tree

setup.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@
1212
from distutils.core import setup
1313
setup(
1414
name='vk_api',
15+
<<<<<<< HEAD
1516
version='4.7.6',
17+
=======
18+
version='5.0.0',
19+
>>>>>>> refs/remotes/origin/dev
1620
author='Kirill Python',
1721
author_email='siberianpython@gmail.com',
1822
url='https://github.com/python273/vk_api',

vk_api/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@
99
"""
1010

1111
__author__ = 'Kirill Python'
12+
<<<<<<< HEAD
1213
__version__ = '4.7.6'
14+
=======
15+
__version__ = '5.0.0'
16+
>>>>>>> refs/remotes/origin/dev
1317
__email__ = 'siberianpython@gmail.com'
1418
__contact__ = 'https://vk.com/python273'
1519

vk_api/vk_api.py

Lines changed: 103 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,23 @@
1313
import requests
1414
import time
1515

16-
DELAY = 1.0 / 3 # 3 requests per second
16+
DELAY = 0.36 # 3 requests per second
1717
CAPTCHA_ERROR_CODE = 14
1818
NEED_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

2128
class 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

307352
def 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

333379
class 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

344391
class 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+
360431
class 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({

vk_api/vk_tools.py

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,21 @@
1111
import json
1212
import sys
1313

14-
if sys.version_info[0] == 3:
15-
xrange = range
14+
if sys.version_info[0] != 3:
15+
range = xrange
1616

1717

1818
class VkTools(object):
1919
def __init__(self, vk):
20+
"""
21+
22+
:param vk: объект VkApi
23+
"""
24+
2025
self.vk = vk
2126

22-
def get_all(self, method, values=None, max_count=200, key='items'):
27+
def get_all(self, method, values=None, max_count=200, key='items',
28+
limit_count=None):
2329
""" Получить все элементы
2430
Работает в методах, где в ответе есть items или users
2531
За один запрос получает max_count * 25 элементов
@@ -29,6 +35,8 @@ def get_all(self, method, values=None, max_count=200, key='items'):
2935
:param max_count: максимальное количество элементов,
3036
которое можно получить за один раз
3137
:param key: ключ элементов, которые нужно получить
38+
:param limit_count: ограничение на кол-во получаемых элементов,
39+
но может прийти больше
3240
"""
3341

3442
if values:
@@ -40,16 +48,15 @@ def get_all(self, method, values=None, max_count=200, key='items'):
4048
offset = 0
4149

4250
while True:
43-
run_code = code_get_all_items % (
44-
max_count, offset, json.dumps(values),
45-
key, method, method
46-
)
51+
run_code = code_get_all_items % (max_count, offset,
52+
json.dumps(values), key,
53+
method, method)
4754

4855
response = self.vk.method('execute', {'code': run_code})
4956

5057
items += response['items']
5158

52-
if response['end']:
59+
if response['end'] or len(items) >= limit_count:
5360
break
5461

5562
offset = response['offset']
@@ -78,7 +85,7 @@ def get_all_slow(self, method, values=None, max_count=200, key='items'):
7885
count = response['count']
7986
items = response[key]
8087

81-
for i in xrange(max_count, count + 1, max_count):
88+
for i in range(max_count, count + 1, max_count):
8289
values.update({
8390
'offset': i
8491
})
@@ -89,8 +96,8 @@ def get_all_slow(self, method, values=None, max_count=200, key='items'):
8996
return {'count': len(items), key: items}
9097

9198
# Полный код в файле vk_procedures
92-
code_get_all_items = '''
99+
code_get_all_items = """
93100
var z=%s,x=%s,y=%s,k="%s",p={"count":z}+y,r=API.%s(p),c=r["count"],j=r[k],o=0,
94101
i=1;while(i<25&&o<c){o=i*z+x;p={"count":z,"offset":o}+y;r=API.%s(p);j=j+r[k];i
95102
=i+1;};return{"count":c,"items":j,"offset":o,"end":o+z>=c};
96-
'''.replace('\n', '')
103+
""".replace('\n', '')

0 commit comments

Comments
 (0)