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采集百度百科的方法
Jun 05 Python
python扫描proxy并获取可用代理ip的实例
Aug 07 Python
Python编程实现的简单神经网络算法示例
Jan 26 Python
Numpy数组转置的两种实现方法
Apr 17 Python
对python中的for循环和range内置函数详解
Apr 17 Python
Python爬虫框架Scrapy基本用法入门教程
Jul 26 Python
Python查找数组中数值和下标相等的元素示例【二分查找】
Feb 13 Python
Python3 实现爬取网站下所有URL方式
Jan 16 Python
Python3+Selenium+Chrome实现自动填写WPS表单
Feb 12 Python
python实现在内存中读写str和二进制数据代码
Apr 24 Python
如何利用python读取micaps文件详解
Oct 18 Python
python 利用Pyinstaller打包Web项目
Oct 23 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设计模式之单例模式使用示例
2014/01/20 PHP
PHP循环输出指定目录下的所有文件和文件夹路径例子(简单实用)
2014/05/10 PHP
ThinkPHP实现二级循环读取的方法
2014/11/03 PHP
IE6下CSS图片缓存问题解决方法
2010/12/09 Javascript
jquery 跨域访问问题解决方法(笔记)
2011/06/08 Javascript
容易被忽略的JS脚本特性
2011/09/13 Javascript
script的async属性以非阻塞的模式加载脚本
2013/01/15 Javascript
JavaScript动态操作表格实例(添加,删除行,列及单元格)
2013/11/25 Javascript
js关于命名空间的函数实例
2015/02/05 Javascript
JavaScript采用递归算法计算阶乘实例
2015/08/04 Javascript
Vue.js 2.0 和 React、Augular等其他前端框架大比拼
2016/10/08 Javascript
Form表单按回车自动提交表单的实现方法
2016/11/18 Javascript
jQuery Validate表单验证插件的基本使用方法及功能拓展
2017/01/04 Javascript
jQuery 插件实现随机自由弹跳气泡样式
2017/01/12 Javascript
原生JS实现垂直手风琴效果
2017/02/19 Javascript
jsonp跨域请求实现示例
2017/03/13 Javascript
在vue项目中,使用axios跨域处理
2018/03/07 Javascript
ES6中new Function()语法及应用实例分析
2020/02/19 Javascript
详谈Object.defineProperty 及实现数据双向绑定
2020/07/18 Javascript
[01:51]2014DOTA2国际邀请赛 这个赛场没有失败者VGTi5再见
2014/07/23 DOTA
python中 ? : 三元表达式的使用介绍
2013/10/09 Python
Python中的FTP通信模块ftplib的用法整理
2016/07/08 Python
Python面向对象程序设计示例小结
2019/01/30 Python
Python学习笔记之视频人脸检测识别实例教程
2019/03/06 Python
Python 控制终端输出文字的实例
2019/07/12 Python
python实现logistic分类算法代码
2020/02/28 Python
python批量替换文件名中的共同字符实例
2020/03/05 Python
Python爬虫Scrapy框架CrawlSpider原理及使用案例
2020/11/20 Python
CSS3中线性颜色渐变的一些实现方法
2015/07/14 HTML / CSS
一篇.NET面试题
2014/09/29 面试题
C#里面可以避免一个类被其他类继承么?如何?
2013/09/26 面试题
如何整合JQuery和Prototype
2014/01/31 面试题
挑战杯创业计划书的写作指南
2014/01/07 职场文书
项目经理聘任书
2014/03/29 职场文书
培训通知
2015/04/17 职场文书
《刷子李》教学反思
2016/02/20 职场文书