python实现rest请求api示例


Posted in Python onApril 22, 2014

该代码参考新浪python api,适用于各个开源api请求

# -*- coding: utf-8 -*-
import collections
import gzip
import urllib
import urllib2
from urlparse import urlparse
try:
    from cStringIO import StringIO
except ImportError:
    from StringIO import StringIO
try:
    import json
except ImportError:
    import simplejson as json

__author__ = 'myth'

_HTTP_GET = 1
_HTTP_POST = 2
# 超时时间(秒)
TIMEOUT = 45
RETURN_TYPE = {"json": 0, "xml": 1, "html": 2, "text": 3}
_METHOD_MAP = {'GET': _HTTP_GET, 'POST': _HTTP_POST}

class APIError(StandardError):
    """
    raise APIError if receiving json message indicating failure.
    """
    def __init__(self, error_code, error, request):
        self.error_code = error_code
        self.error = error
        self.request = request
        StandardError.__init__(self, error)
    def __str__(self):
        return 'APIError: %s: %s, request: %s' % (self.error_code, self.error, self.request)

# def callback_type(return_type='json'):
#
#     default_type = "json"
#     default_value = RETURN_TYPE.get(default_type)
#     if return_type:
#         if isinstance(return_type, (str, unicode)):
#             default_value = RETURN_TYPE.get(return_type.lower(), default_value)
#     return default_value

def _format_params(_pk=None, encode=None, **kw):
    """
    :param kw:
    :type kw:
    :param encode:
    :type encode:
    :return:
    :rtype:
    """
    __pk = '%s[%%s]' % _pk if _pk else '%s'
    encode = encode if encode else urllib.quote
    for k, v in kw.iteritems():
        _k = __pk % k
        if isinstance(v, basestring):
            qv = v.encode('utf-8') if isinstance(v, unicode) else v
            _v = encode(qv)
            yield _k, _v
        elif isinstance(v, collections.Iterable):
            if isinstance(v, dict):
                for _ck, _cv in _format_params(_pk=_k, encode=encode, **v):
                    yield _ck, _cv
            else:
                for i in v:
                    qv = i.encode('utf-8') if isinstance(i, unicode) else str(i)
                    _v = encode(qv)
                    yield _k, _v
        else:
            qv = str(v)
            _v = encode(qv)
            yield _k, _v

def encode_params(**kw):
    """
    do url-encode parameters
    >>> encode_params(a=1, b='R&D')
    'a=1&b=R%26D'
    >>> encode_params(a=u'\u4e2d\u6587', b=['A', 'B', 123])
    'a=%E4%B8%AD%E6%96%87&b=A&b=B&b=123'
    >>> encode_params(**{
        'a1': {'aa1': 1, 'aa2': {'aaa1': 11}},
        'b1': [1, 2, 3, 4],
        'c1': {'cc1': 'C', 'cc2': ['Q', 1, '@'], 'cc3': {'ccc1': ['s', 2]}}
    })
    'a1[aa1]=1&a1[aa2][aaa1]=11&c1[cc1]=C&c1[cc3][ccc1]=s&c1[cc3][ccc1]=2&c1[cc2]=Q&c1[cc2]=1&c1[cc2]=%40&b1=1&b1=2&b1=3&b1=4'
    """
    # args = []
    # for k, v in kw.iteritems():
    #     if isinstance(v, basestring):
    #         qv = v.encode('utf-8') if isinstance(v, unicode) else v
    #         args.append('%s=%s' % (k, urllib.quote(qv)))
    #     elif isinstance(v, collections.Iterable):
    #         for i in v:
    #             qv = i.encode('utf-8') if isinstance(i, unicode) else str(i)
    #             args.append('%s=%s' % (k, urllib.quote(qv)))
    #     else:
    #         qv = str(v)
    #         args.append('%s=%s' % (k, urllib.quote(qv)))
    # return '&'.join(args)
    args = []
    _urlencode = kw.pop('_urlencode', urllib.quote)
    for k, v in _format_params(_pk=None, encode=_urlencode, **kw):
        args.append('%s=%s' % (k, v))
    args = sorted(args, key=lambda s: s.split("=")[0])
    return '&'.join(args)

def _read_body(obj):
    using_gzip = obj.headers.get('Content-Encoding', '') == 'gzip'
    body = obj.read()
    if using_gzip:
        gzipper = gzip.GzipFile(fileobj=StringIO(body))
        fcontent = gzipper.read()
        gzipper.close()
        return fcontent
    return body

class JsonDict(dict):
    """
    general json object that allows attributes to be bound to and also behaves like a dict
    """
    def __getattr__(self, attr):
        try:
            return self[attr]
        except KeyError:
            raise AttributeError(r"'JsonDict' object has no attribute '%s'" % attr)
    def __setattr__(self, attr, value):
        self[attr] = value

def _parse_json(s):
    """
    parse str into JsonDict
    """
    def _obj_hook(pairs):
        """
        convert json object to python object
        """
        o = JsonDict()
        for k, v in pairs.iteritems():
            o[str(k)] = v
        return o
    return json.loads(s, object_hook=_obj_hook)

def _parse_xml(s):
    """
    parse str into xml
    """
    raise NotImplementedError()

def _parse_html(s):
    """
    parse str into html
    """
    raise NotImplementedError()

def _parse_text(s):
    """
    parse str into text
    """
    raise NotImplementedError()

def _http_call(the_url, method, return_type="json", request_type=None, request_suffix=None, headers={}, _timeout=30, **kwargs):
    """
    the_url: 请求地址
    method 请求方法(get,post)
    return_type: 返回格式解析
    request_suffix: 请求地址的后缀,如jsp,net
    _timeout: 超时时间
    kwargs: 请求参数
    """
    http_url = "%s.%s" (the_url, request_suffix) if request_suffix else the_url
    if request_type == 'json':
        headers['Content-Type'] = 'application/json'
        # method = _HTTP_POST
        # json_data = json.dumps(kwargs)
        # # convert str to bytes (ensure encoding is OK)
        # params = json_data.encode('utf-8')
        params = json.dumps(kwargs)
    else:
        params = encode_params(**kwargs)
        http_url = '%s?%s' % (http_url, params) if method == _HTTP_GET else http_url
    print http_url
    # u = urlparse(http_url)
    # headers.setdefault("host", u.hostname)
    http_body = None if method == _HTTP_GET else params
    req = urllib2.Request(http_url, data=http_body, headers=headers)
    callback = globals().get('_parse_{0}'.format(return_type))
    if not hasattr(callback, '__call__'):
        print "return '%s' unable to resolve" % return_type
        callback = _parse_json
    try:
        resp = urllib2.urlopen(req, timeout=_timeout if _timeout else TIMEOUT)
        body = _read_body(resp)
        r = callback(body)
        # if hasattr(r, 'error_code'):
        #     raise APIError(r.error_code, r.get('error', ''), r.get('request', ''))
        return r
    except urllib2.HTTPError, e:
        try:
            body = _read_body(e)
            r = callback(body)
            return r
        except:
            r = None
        # if hasattr(r, 'error_code'):
        #     raise APIError(r.error_code, r.get('error', ''), r.get('request', ''))
            raise e

class HttpObject(object):
    def __init__(self, client, method):
        self.client = client
        self.method = method
    def __getattr__(self, attr):
        def wrap(**kw):
            if attr:
                the_url = '%s/%s' % (self.client.api_url, attr.replace('__', '/'))
            else:
                the_url = self.client.api_url
            return _http_call(the_url, self.method, **kw)
        return wrap
    def __call__(self, **kw):
        return _http_call(self.client.api_url, self.method, **kw)

class APIClient(object):
    """
    使用方法:
        比如:api 请求地址为:http://api.open.zbjdev.com/kuaiyinserv/kuaiyin/billaddress
             请求方式为: GET
             需要的参数为:user_id 用户的UID
                         is_all 是否查询所有数据,0为默认邮寄地址 1为全部邮寄地址
                         access_token 平台认证
             返回数据为:json
        那么此时使用如下:
        domain = "api.open.zbjdev.com"
        #如果是https请求,需要将is_https设置为True
        client = APIClient(domain)
        data = {"user_id": "14035462", "is_all": 1, "access_token": "XXXXXXXXXX"}
        # 如果是post请求,请将get方法改为post方法
        result = client.kuaiyinserv.kuaiyin.billaddress.get(return_type="json", **data)
        #等同于
        # result = client.kuaiyinserv__kuaiyin__billaddress__get(return_type="json", **data)
        # result = client.kuaiyinserv__kuaiyin__billaddress(return_type="json", **data)
    """
    def __init__(self, domain, is_https=False):
        http = "http"
        if domain.startswith("http://") or domain.startswith("https://"):
            http, domain = domain.split("://")
        # else:
        if is_https:
            http = "https"
        self.api_url = ('%s://%s' % (http, domain)).rstrip("/")
        self.get = HttpObject(self, _HTTP_GET)
        self.post = HttpObject(self, _HTTP_POST)
    def __getattr__(self, attr):
        if '__' in attr:
            method = self.get
            if attr[-6:] == "__post":
                attr = attr[:-6]
                method = self.post
            elif attr[-5:] == "__get":
                attr = attr[:-5]
            if attr[:2] == '__':
                attr = attr[2:]
            return getattr(method, attr)
        return _Callable(self, attr)

class _Executable(object):
    def __init__(self, client, method, path):
        self._client = client
        self._method = method
        self._path = path
    def __call__(self, **kw):
        method = _METHOD_MAP[self._method]
        return _http_call('%s/%s' % (self._client.api_url, self._path), method, **kw)
    def __str__(self):
        return '_Executable (%s %s)' % (self._method, self._path)
    __repr__ = __str__

class _Callable(object):
    def __init__(self, client, name):
        self._client = client
        self._name = name
    def __getattr__(self, attr):
        if attr == 'get':
            return _Executable(self._client, 'GET', self._name)
        if attr == 'post':
            return _Executable(self._client, 'POST', self._name)
        name = '%s/%s' % (self._name, attr)
        return _Callable(self._client, name)
    def __str__(self):
        return '_Callable (%s)' % self._name
    __repr__ = __str__

def test_logistics():
    domain = "https://api.kuaidi100.com/api"
    #如果是https请求,需要将is_https设置为True
    client = APIClient(domain)
    data = {"id": "45f2d1f2sds", "com": "yunda", "nu": "1500066330925"}
    result = client.__get(_timeout=2, **data)
    print result
    print result["message"]
    print result.get("message")
    print result.message

if __name__ == '__main__':

    # test_logistics()
    data = {
        "data":{
            "id": 1,
            "pid": 3,
            "name": u'中的阿斯顿'
        },
        "sign": 'asdfdsdsfsdf',
    }
    domain = "kuaiyin.zhubajie.com"
    client = APIClient(domain)
    # headers = {'Content-Type': 'application/json'}
    headers = {"host": domain}
    result = client.api.zhubajie.fz.info.post(return_type="json", request_type="json", headers=headers, **data)
    print result
    print result['data']['msg']
    c = APIClient('task.6.zbj.cn')
    r = getattr(c.api, 'kuaiyin-action-delcache').post(request_type="json",
                                                       headers={},
                                                       **{"sign": "",
                                                          "data": {
                                                              "product": "pvc",
                                                              "category": "card",
                                                              "req_type": "pack_list"
                                                          }})
    print r
    print r['data']['msg']
Python 相关文章推荐
python中合并两个文本文件并按照姓名首字母排序的例子
Apr 25 Python
浅谈Python2获取中文文件名的编码问题
Jan 09 Python
解决pip install的时候报错timed out的问题
Jun 12 Python
Python中的支持向量机SVM的使用(附实例代码)
Jun 26 Python
python实现数据分析与建模
Jul 11 Python
Python Django的安装配置教程图文详解
Jul 17 Python
如何基于Python实现自动扫雷
Jan 06 Python
Python异常处理机制结构实例解析
Jul 23 Python
Python环境配置实现pip加速过程解析
Nov 27 Python
python基础详解之if循环语句
Apr 24 Python
python opencv通过4坐标剪裁图片
Jun 05 Python
Selenium浏览器自动化如何上传文件
Apr 06 Python
python 七种邮件内容发送方法实例
Apr 22 #Python
sqlalchemy对象转dict的示例
Apr 22 #Python
用pywin32实现windows模拟鼠标及键盘动作
Apr 22 #Python
python实现linux服务器批量修改密码并生成execl
Apr 22 #Python
python中精确输出JSON浮点数的方法
Apr 18 #Python
python中使用OpenCV进行人脸检测的例子
Apr 18 #Python
在python的WEB框架Flask中使用多个配置文件的解决方法
Apr 18 #Python
You might like
PHP实现支持GET,POST,Multipart/form-data的HTTP请求类
2014/09/24 PHP
PHP实现图片防盗链破解操作示例【解决图片防盗链问题/反向代理】
2020/05/29 PHP
ajax中get和post的说明及使用与区别
2012/12/23 Javascript
jQuery使用addClass()方法给元素添加多个class样式
2015/03/26 Javascript
原创jQuery弹出层插件分享
2015/04/02 Javascript
jquery带有索引按钮且自动轮播切换特效代码分享
2015/09/15 Javascript
JS模拟按钮点击功能的方法
2015/12/22 Javascript
基于jQuery仿淘宝产品图片放大镜特效
2020/10/19 Javascript
解决angularJS中input标签的ng-change事件无效问题
2018/09/13 Javascript
nodejs实现范围请求的实现代码
2018/10/12 NodeJs
Element Table的row-class-name无效与动态高亮显示选中行背景色
2018/11/30 Javascript
layui 数据表格+分页+搜索+checkbox+缓存选中项数据的方法
2019/09/21 Javascript
初学Python实用技巧两则
2014/08/29 Python
Python文件右键找不到IDLE打开项解决办法
2015/06/08 Python
Python实现文件复制删除
2016/04/19 Python
Python用模块pytz来转换时区
2016/08/19 Python
Python使用QRCode模块生成二维码实例详解
2017/06/14 Python
详解Python进程间通信之命名管道
2017/08/28 Python
使用Python通过win32 COM实现Word文档的写入与保存方法
2018/05/08 Python
python 文件转成16进制数组的实例
2018/07/09 Python
pygame游戏之旅 按钮上添加文字的方法
2018/11/21 Python
python实现切割url得到域名、协议、主机名等各个字段的例子
2019/07/25 Python
python openCV获取人脸部分并存储功能
2019/08/28 Python
Django Admin后台添加数据库视图过程解析
2020/04/01 Python
六道php面试题附答案
2014/06/05 面试题
以下的初始化有什么区别
2013/12/16 面试题
什么是继承
2013/12/07 面试题
理工大学毕业生自荐信
2013/11/01 职场文书
小学教研工作制度
2014/01/15 职场文书
新文化运动的基本口号
2014/06/21 职场文书
开服装店计划书
2014/08/15 职场文书
门卫岗位职责
2015/02/09 职场文书
小学教师求职信范文
2015/03/20 职场文书
总经理司机岗位职责
2015/04/10 职场文书
MySQL悲观锁与乐观锁的实现方案
2021/11/02 MySQL
SQL使用复合索引实现数据库查询的优化
2022/05/25 SQL Server