解析URL,覆盖部分,并在Python中将其重新组合在一起

时间:2012-09-11 11:10:17

标签: python parsing url

在我的程序中,我希望用户能够为CouchDB数据库指定一个URL。

我想为此网址的部分内容提供合理的默认值;例如,localhost,5984和mushin分别是host,port和path的默认值。

urlparse.urlparse返回一个元组子类,它也有属性访问器,但没有setter。

主机和端口(以及稍后的用户名和密码)是解析元组的netloc部分的属性。这些属性只是获得。所以这段代码对我来说是理想的,但却失败了:

   try:
        jane = urlparse(args[0])
    except IndexError:
        self.stdout.write('Please give a database to replicate with.\n')
        return

    if not jane.hostname:
        jane.hostname = HOST
    if not jane.port:
        jane.port = PORT
    if not jane.path:
        jane.path = DB

    url = jane.geturl()

使用元组接口没有帮助,因为netloc没有拆分成用户名/密码/主机/端口组件,所以我仍然必须自己负责工作。

有没有更好的方法来解析URL,覆盖它的各个部分,并将新的URL重新组合在一起?

4 个答案:

答案 0 :(得分:2)

我用来解决这个问题的片段:

netloc_regex = re.compile(r"(?:([^:]+)(?::(.*))?@)?([^:]+)(?::([\d]+))?")
endpoint = # some value

scheme, netloc, path, params, query, fragment = urlparse(endpoint)
username, password, host, port = netloc_regex.search(netloc).groups()

# manipulate components here

auth = ":".join(filter(None, (username, password)))
address = ":".join(filter(None, (host, port)))
netloc = "@".join(filter(None, (auth, address)))
endpoint = urlunparse((scheme, netloc, path, params, query, fragment))

我希望存在错误和未捕获的案例,例如,如果密码不是None,则不会强制您必须拥有用户名。但它完成了工作。

答案 1 :(得分:0)

对元组的操作副本使用urlparse.urlunparse

  

parts参数可以是任何六项可迭代的。

p = urlparse.urlparse(url)
l = list(p)
l[4] = "foo=bar" # manipulate query parameters
urlparse.urlunparse(l)

答案 2 :(得分:0)

class DbUrl(object):

    def __init__(self, db_url):
        split = urlparse.urlparse(db_url)
        self.scheme = split.scheme
        self.hostname = split.hostname
        self.port = split.port
        self.username = split.username
        self.password = split.password
        self.database = split.path.lstrip('/')

    def __str__(self):
        auth = ":".join(filter(None, (self.username, self.password)))
        address = ":".join(filter(None, (self.hostname, str(self.port))))
        netloc = "@".join(filter(None, (auth, address)))
        return urlparse.urlunparse((self.scheme, netloc, self.database, '', '', ''))

    def __repr__(self):
        return '%s(%s)' % (self.__class__.__name__, ', '.join(
            '%s=%r' % (attr_name, attr_value)
            for attr_name, attr_value in self.__dict__.iteritems()))

    def replace(self, **kwargs):
        db_url = copy.copy(self)
        for attr_name, attr_value in kwargs.iteritems():
            assert attr_name in db_url.__dict__, 'Unknown attribute'
            setattr(db_url, attr_name, attr_value)
        return db_url

和用法:

>>> DbUrl('postgresql://username:password@127.0.0.1:5433/postgres').replace(password='****')
DbUrl(username='username', password='****', hostname='127.0.0.1', database='postgres', scheme='postgresql', port=5433)
>>> str(DbUrl('postgresql://username:password@127.0.0.1:5433/postgres').replace(password='****'))
'postgresql://username:****@127.0.0.1:5433/postgres'
>>> str(DbUrl('postgresql://username:password@127.0.0.1:5433/postgres').replace(password=None))
'postgresql://username@127.0.0.1:5433/postgres'
>>> 

答案 3 :(得分:0)

您可以使用yurl库在一行中执行此操作:

>>> import yurl
>>> user_url = yurl.URL('http://without.port/#hash')
>>> your_defaults = yurl.URL('//:33/default')  # or URL(port=33, path='/default')

>>> print user_url.replace(*map(lambda x: x or None, your_defaults))
http://without.port:33/default#hash

mapNone替换空部分(空字符串),然后作为参数传递给user_url.replace()方法。