在Python中对多维字典进行url编码

13 投票
9 回答
10709 浏览
提问于 2025-04-16 06:03

我怎么才能在Python中得到一个多维字典的URL编码版本呢?可惜的是,urllib.urlencode() 只能处理一维的字典。我需要一个可以递归编码字典的版本。

比如说,如果我有下面这个字典:

{'a': 'b', 'c': {'d': 'e'}}

我想得到下面这个字符串:

a=b&c[d]=e

9 个回答

3

根据@malaney的代码,我觉得下面的代码很好地模拟了PHP中的http_build_query()函数。

#!/usr/bin/env python3

import urllib.parse

def http_build_query(data):
    parents = list()
    pairs = dict()

    def renderKey(parents):
        depth, outStr = 0, ''
        for x in parents:
            s = "[%s]" if depth > 0 or isinstance(x, int) else "%s"
            outStr += s % str(x)
            depth += 1
        return outStr

    def r_urlencode(data):
        if isinstance(data, list) or isinstance(data, tuple):
            for i in range(len(data)):
                parents.append(i)
                r_urlencode(data[i])
                parents.pop()
        elif isinstance(data, dict):
            for key, value in data.items():
                parents.append(key)
                r_urlencode(value)
                parents.pop()
        else:
            pairs[renderKey(parents)] = str(data)

        return pairs
    return urllib.parse.urlencode(r_urlencode(data))

if __name__ == '__main__':
    payload = {
        'action': 'add',
        'controller': 'invoice',
        'code': 'debtor',
        'InvoiceLines': [
            {'PriceExcl': 150, 'Description': 'Setupfee'},
            {'PriceExcl':49.99, 'Description':'Subscription'}
        ],
        'date': '2016-08-01',
        'key': 'Yikes&ampersand'
    }
    print(http_build_query(payload))

    payload2 = [
        'item1',
        'item2'
    ]
    print(http_build_query(payload2))
3

像这样吗?

a = {'a': 'b', 'c': {'d': 'e'}}

url = urllib.urlencode([('%s[%s]'%(k,v.keys()[0]), v.values()[0] ) if type(v)==dict else (k,v) for k,v in a.iteritems()])

url = 'a=b&c%5Bd%5D=e'
13

好的,大家。我自己实现了这个:

import urllib

def recursive_urlencode(d):
    """URL-encode a multidimensional dictionary.

    >>> data = {'a': 'b&c', 'd': {'e': {'f&g': 'h*i'}}, 'j': 'k'}
    >>> recursive_urlencode(data)
    u'a=b%26c&j=k&d[e][f%26g]=h%2Ai'
    """
    def recursion(d, base=[]):
        pairs = []

        for key, value in d.items():
            new_base = base + [key]
            if hasattr(value, 'values'):
                pairs += recursion(value, new_base)
            else:
                new_pair = None
                if len(new_base) > 1:
                    first = urllib.quote(new_base.pop(0))
                    rest = map(lambda x: urllib.quote(x), new_base)
                    new_pair = "%s[%s]=%s" % (first, ']['.join(rest), urllib.quote(unicode(value)))
                else:
                    new_pair = "%s=%s" % (urllib.quote(unicode(key)), urllib.quote(unicode(value)))
                pairs.append(new_pair)
        return pairs

    return '&'.join(recursion(d))

if __name__ == "__main__":
    import doctest
    doctest.testmod()

不过,我还是想知道有没有更好的方法来做到这一点。我真不敢相信Python的标准库居然没有实现这个功能。

撰写回答