Advertisement
stuppid_bot

Untitled

Dec 16th, 2014
337
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.70 KB | None | 0 0
  1. # -*- coding: utf-8 -*-
  2. import os
  3. import re
  4. import time
  5. import requests
  6. import urlparse
  7.  
  8. DEFAULT_API_VERSION = 5.27
  9. # Для приложений есть лимиты обращения к API (https://vk.com/dev/api_requests).
  10. # Чтобы избежать возникновения ошибки в результате частого обращения к API,
  11. # мы будем задерживать возвращение ответа от сервера.
  12. DEFAULT_API_DELAY = 0.34
  13. DEFAULT_USER_AGENT = "Mozilla/5.0"
  14.  
  15. class VKClient(object):    
  16.     def __init__(self, access_token=None, api_version=None, api_delay=None, \
  17.                  user_agent=None, timeout=None):
  18.         u"""Клиент для работы с API Вконтакте.
  19.        
  20.        К методам API можно обращаться как к методам класса:
  21.            <object VKClient>.users.get(user_id=123)
  22.        """
  23.         self.accessToken = access_token
  24.        
  25.         if api_version is None:
  26.             api_version = DEFAULT_API_VERSION
  27.        
  28.         self.apiVersion = api_version
  29.        
  30.         if api_delay is None:
  31.             api_delay = DEFAULT_API_DELAY
  32.          
  33.         self.apiDelay = api_delay
  34.        
  35.         if user_agent is None:
  36.             user_agent = DEFAULT_USER_AGENT
  37.        
  38.         self.userAgent = user_agent
  39.         self.timeout = timeout
  40.         self.session = requests.session()
  41.        
  42.     def request(self, method, url, **kwargs):
  43.         u"""Отправляет запрос и возвращает ответ в виде результата парсинга
  44.        json либо строки(эта возможность может понадобиться в классах
  45.        наследниках)."""
  46.         options = dict(headers={"User-Agent": self.userAgent},
  47.                        timeout=self.timeout)
  48.         options.update(kwargs)
  49.         response = self.session.request(method, url, **options)
  50.        
  51.         try:
  52.             return response.json()
  53.         except ValueError:
  54.             return response.text
  55.        
  56.     def post(self, url, data=None, files=None, **kwargs):
  57.         u"""По сути для работы с API нужен только метод POST. Вконтакте не
  58.        различает POST и GET запросы, данные берутся из массива $_REQUEST,
  59.        т.е. параметры можно передавать даже через cookie."""
  60.         kwargs['data'] = data
  61.         kwargs['files'] = files
  62.         return self.request('POST', url, **kwargs)
  63.  
  64.     def api(self, method, params={}):
  65.         u"""Отправляет запрос к API.
  66.        
  67.        :param method: Имя метода.
  68.        :param params: - словарь, необязательный. Параметры запроса.
  69.        :return: Значение поля ``response``.
  70.        """
  71.         params = dict(params)
  72.  
  73.         if self.accessToken and not 'access_token' in params:
  74.             params['access_token'] = self.accessToken
  75.  
  76.         if self.apiVersion and not 'v' in params:
  77.             params['v'] = self.apiVersion
  78.            
  79.         url = 'https://api.vk.com/method/{}'.format(method)
  80.         response = self.post(url, params)
  81.        
  82.         if not isinstance(response, dict):
  83.             raise VKClientError("Bad response.")
  84.  
  85.         if self.apiDelay:
  86.             time.sleep(self.apiDelay)
  87.  
  88.         if 'error' in response:
  89.             error = VKAPIError(response['error'])
  90.            
  91.             if error.code == 14:
  92.                 return self.captchaHandler(error)
  93.             elif error.code == 17:
  94.                 return self.validationHandler(error)
  95.            
  96.             raise error
  97.  
  98.         return response['response']    
  99.  
  100.     def captchaHandler(self, error):
  101.         raise error
  102.  
  103.     def validationHandler(self, error):
  104.         raise error
  105.  
  106.     def upload(self, url, files):
  107.         u"""Загружает файлы на сервер.
  108.        
  109.        :param url: Адрес сервера для загрузки файлов.
  110.        :param files: Словарь, где "имя поля" => "путь до файла"(может быть
  111.            ссылкой). Так же можно передавать кортеж или список вида
  112.            ("имя файла", "содержимое"). На сервере проверяется расширение
  113.            файла, передаваемый mime тип не учитывается(поэтому он не
  114.            передается). Проверяются сигнатуры при загрузке изображений.
  115.        """
  116.         files = dict(files)
  117.  
  118.         for fieldname, data in files.items():
  119.             if not isinstance(data, basestring):
  120.                 continue
  121.            
  122.             filename = data
  123.            
  124.             if re.match('(?i)https?://', filename):
  125.                 content = self.session.get(filename).content
  126.                 # http://example.com/path/to/file?query -> path/to/file
  127.                 filename = urlparse.urlparse(filename).path
  128.             else:
  129.                 content = open(filename, 'rb').read()
  130.  
  131.             # path/to/file -> file
  132.             filename = os.path.basename(filename)
  133.             files[fieldname] = (filename, content)
  134.            
  135.         response = self.post(url, None, files)    
  136.         return response
  137.    
  138.     def uploadWallPhoto(self, photo, group_id=None):
  139.         u"""Метод для тестирования загрузки фото на стену."""
  140.         params = {}
  141.        
  142.         if group_id:
  143.             params['group_id'] = group_id
  144.            
  145.         url = self.photos.getWallUploadServer(params)['upload_url']
  146.         result = self.upload(url, {'photo': photo})
  147.         data = self.photos.saveWallPhoto(result)
  148.         # attachment = "photo{owner_id}_{id}".format(**data[0])
  149.         return data
  150.    
  151.     def __getattr__(self, name):
  152.         return _VKClientAttribute(self, name)
  153.    
  154. class VKClientError(Exception):
  155.     pass
  156.    
  157. # Ошибка генерируются на стороне клиента, а значит должна наследоваться от
  158. # VKClientError.
  159. class VKAPIError(VKClientError):
  160.     def __init__(self, details):
  161.         self.code = details['error_code']
  162.         self.message = details['error_msg']
  163.         self.captchaSid = details.get('captcha_sid')
  164.         self.captchaImg = details.get('captcha_img')
  165.         self.redirectUri = details.get('redirect_uri')
  166.         params = {param['key']: param['value']
  167.                   for param in details['request_params']}
  168.         self.oauth = params.pop('oauth')
  169.         self.method = params.pop('method')
  170.         self.params = params
  171.    
  172.     def __str__(self):
  173.         return "[{}] {}".format(self.code, self.message)
  174.    
  175. class _VKClientAttribute(object):
  176.     def __init__(self, client, name, prefix=''):
  177.         if not re.match('[a-zA-Z]+$', name):
  178.             raise VKClientError("Bad attribute.")
  179.            
  180.         self._client = client
  181.         self._name = name
  182.         self._prefix = prefix
  183.    
  184.     # Принимает словарь либо именованные аргументы.
  185.     def __call__(self, *args, **kwargs):
  186.         if not len(kwargs) and len(args) == 1 and isinstance(args[0], dict):
  187.             kwargs = args[0]
  188.  
  189.         return self._client.api(self._prefix + self._name, kwargs)
  190.  
  191.     # Создаем цепочку фейковых атрибутов.
  192.     def __getattr__(self, name):
  193.         prefix = self._prefix + self._name + '.'
  194.         return self.__class__(self._client, name, prefix)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement