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之字典,你还记得吗?
Sep 20 Python
python中__call__方法示例分析
Oct 11 Python
Flask入门教程实例:搭建一个静态博客
Mar 27 Python
python检查序列seq是否含有aset中项的方法
Jun 30 Python
python二分查找算法的递归实现方法
May 12 Python
Python中如何导入类示例详解
Apr 17 Python
pyqt5对用qt designer设计的窗体实现弹出子窗口的示例
Jun 19 Python
Pandas之DataFrame对象的列和索引之间的转化
Jun 25 Python
selenium 多窗口切换的实现(windows)
Jan 18 Python
python中uuid模块实例浅析
Dec 29 Python
Python 实现进度条的六种方式
Jan 06 Python
python uuid生成唯一id或str的最简单案例
Jan 13 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
Cappuccino 卡布其诺咖啡之制作
2021/03/03 冲泡冲煮
PHP.MVC的模板标签系统(一)
2006/09/05 PHP
PHP写UltraEdit插件脚本实现方法
2011/12/26 PHP
PHP+jQuery实现自动补全功能源码
2013/05/15 PHP
PHP面向对象之工作单元(实例讲解)
2017/06/26 PHP
javascript实现简单的Map示例介绍
2013/12/23 Javascript
jQuery自带的一些常用方法总结
2014/09/03 Javascript
在JavaScript中如何解决用execCommand(
2015/10/19 Javascript
JavaScript数组操作函数汇总
2016/08/05 Javascript
微信小程序 加载 app-service.js 错误解决方法
2016/10/12 Javascript
js实现键盘自动打字效果
2016/12/23 Javascript
JavaScript实现经典排序算法之冒泡排序
2016/12/28 Javascript
Angular2入门教程之模块和组件详解
2017/05/28 Javascript
React中常见的动画实现的几种方式
2018/01/10 Javascript
一个基于react的图片裁剪组件示例
2018/04/18 Javascript
vue实现弹幕功能
2019/10/25 Javascript
vue递归获取父元素的元素实例
2020/08/07 Javascript
python实现从字符串中找出字符1的位置以及个数的方法
2014/08/25 Python
归纳整理Python中的控制流语句的知识点
2015/04/14 Python
详解Python中的strftime()方法的使用
2015/05/22 Python
Python文件右键找不到IDLE打开项解决办法
2015/06/08 Python
K-means聚类算法介绍与利用python实现的代码示例
2017/11/13 Python
Python如何基于rsa模块实现非对称加密与解密
2020/01/03 Python
python神经网络编程实现手写数字识别
2020/05/27 Python
无需JS和jQuery代码实现CSS3鼠标浮动放大图片
2016/11/21 HTML / CSS
使用HTML5做的导航条详细步骤
2020/10/19 HTML / CSS
Nordgreen英国官网:斯堪的纳维亚设计师手表
2018/10/24 全球购物
西班牙最好的在线购买葡萄酒的商店:Vinoseleccion
2019/10/30 全球购物
致裁判员加油稿
2014/02/08 职场文书
企业党员一句话承诺
2014/05/30 职场文书
绿色环保口号
2014/06/12 职场文书
春节超市活动方案
2014/08/14 职场文书
机关领导干部作风整顿整改措施
2014/09/19 职场文书
优秀少先队辅导员事迹材料
2014/12/24 职场文书
演讲稿之感恩老师(三篇范文)
2019/09/06 职场文书
NodeJs内存占用过高的排查实战记录
2021/05/10 NodeJs