Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # -*- coding: utf-8 -*-
- import os
- import re
- import time
- import requests
- import urlparse
- DEFAULT_API_VERSION = 5.27
- # Для приложений есть лимиты обращения к API (https://vk.com/dev/api_requests).
- # Чтобы избежать возникновения ошибки в результате частого обращения к API,
- # мы будем задерживать возвращение ответа от сервера.
- DEFAULT_API_DELAY = 0.34
- DEFAULT_USER_AGENT = "Mozilla/5.0"
- class VKClient(object):
- def __init__(self, access_token=None, api_version=None, api_delay=None, \
- user_agent=None, timeout=None):
- u"""Клиент для работы с API Вконтакте.
- К методам API можно обращаться как к методам класса:
- <object VKClient>.users.get(user_id=123)
- """
- self.accessToken = access_token
- if api_version is None:
- api_version = DEFAULT_API_VERSION
- self.apiVersion = api_version
- if api_delay is None:
- api_delay = DEFAULT_API_DELAY
- self.apiDelay = api_delay
- if user_agent is None:
- user_agent = DEFAULT_USER_AGENT
- self.userAgent = user_agent
- self.timeout = timeout
- self.session = requests.session()
- def request(self, method, url, **kwargs):
- u"""Отправляет запрос и возвращает ответ в виде результата парсинга
- json либо строки(эта возможность может понадобиться в классах
- наследниках)."""
- options = dict(headers={"User-Agent": self.userAgent},
- timeout=self.timeout)
- options.update(kwargs)
- response = self.session.request(method, url, **options)
- try:
- return response.json()
- except ValueError:
- return response.text
- def post(self, url, data=None, files=None, **kwargs):
- u"""По сути для работы с API нужен только метод POST. Вконтакте не
- различает POST и GET запросы, данные берутся из массива $_REQUEST,
- т.е. параметры можно передавать даже через cookie."""
- kwargs['data'] = data
- kwargs['files'] = files
- return self.request('POST', url, **kwargs)
- def api(self, method, params={}):
- u"""Отправляет запрос к API.
- :param method: Имя метода.
- :param params: - словарь, необязательный. Параметры запроса.
- :return: Значение поля ``response``.
- """
- params = dict(params)
- if self.accessToken and not 'access_token' in params:
- params['access_token'] = self.accessToken
- if self.apiVersion and not 'v' in params:
- params['v'] = self.apiVersion
- url = 'https://api.vk.com/method/{}'.format(method)
- response = self.post(url, params)
- if not isinstance(response, dict):
- raise VKClientError("Bad response.")
- if self.apiDelay:
- time.sleep(self.apiDelay)
- if 'error' in response:
- error = VKAPIError(response['error'])
- if error.code == 14:
- return self.captchaHandler(error)
- elif error.code == 17:
- return self.validationHandler(error)
- raise error
- return response['response']
- def captchaHandler(self, error):
- raise error
- def validationHandler(self, error):
- raise error
- def upload(self, url, files):
- u"""Загружает файлы на сервер.
- :param url: Адрес сервера для загрузки файлов.
- :param files: Словарь, где "имя поля" => "путь до файла"(может быть
- ссылкой). Так же можно передавать кортеж или список вида
- ("имя файла", "содержимое"). На сервере проверяется расширение
- файла, передаваемый mime тип не учитывается(поэтому он не
- передается). Проверяются сигнатуры при загрузке изображений.
- """
- files = dict(files)
- for fieldname, data in files.items():
- if not isinstance(data, basestring):
- continue
- filename = data
- if re.match('(?i)https?://', filename):
- content = self.session.get(filename).content
- # http://example.com/path/to/file?query -> path/to/file
- filename = urlparse.urlparse(filename).path
- else:
- content = open(filename, 'rb').read()
- # path/to/file -> file
- filename = os.path.basename(filename)
- files[fieldname] = (filename, content)
- response = self.post(url, None, files)
- return response
- def uploadWallPhoto(self, photo, group_id=None):
- u"""Метод для тестирования загрузки фото на стену."""
- params = {}
- if group_id:
- params['group_id'] = group_id
- url = self.photos.getWallUploadServer(params)['upload_url']
- result = self.upload(url, {'photo': photo})
- data = self.photos.saveWallPhoto(result)
- # attachment = "photo{owner_id}_{id}".format(**data[0])
- return data
- def __getattr__(self, name):
- return _VKClientAttribute(self, name)
- class VKClientError(Exception):
- pass
- # Ошибка генерируются на стороне клиента, а значит должна наследоваться от
- # VKClientError.
- class VKAPIError(VKClientError):
- def __init__(self, details):
- self.code = details['error_code']
- self.message = details['error_msg']
- self.captchaSid = details.get('captcha_sid')
- self.captchaImg = details.get('captcha_img')
- self.redirectUri = details.get('redirect_uri')
- params = {param['key']: param['value']
- for param in details['request_params']}
- self.oauth = params.pop('oauth')
- self.method = params.pop('method')
- self.params = params
- def __str__(self):
- return "[{}] {}".format(self.code, self.message)
- class _VKClientAttribute(object):
- def __init__(self, client, name, prefix=''):
- if not re.match('[a-zA-Z]+$', name):
- raise VKClientError("Bad attribute.")
- self._client = client
- self._name = name
- self._prefix = prefix
- # Принимает словарь либо именованные аргументы.
- def __call__(self, *args, **kwargs):
- if not len(kwargs) and len(args) == 1 and isinstance(args[0], dict):
- kwargs = args[0]
- return self._client.api(self._prefix + self._name, kwargs)
- # Создаем цепочку фейковых атрибутов.
- def __getattr__(self, name):
- prefix = self._prefix + self._name + '.'
- return self.__class__(self._client, name, prefix)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement