用 Python 替换 URL 中的主机名的最简洁方法是什么?

问题描述 投票:0回答:1

在Python中,有一个标准库模块

urllib.parse
处理解析URL:

>>> import urllib.parse
>>> urllib.parse.urlparse("https://127.0.0.1:6443")
ParseResult(scheme='https', netloc='127.0.0.1:6443', path='', params='', query='', fragment='')

urllib.parse.ParseResult
上还有返回主机名和端口的属性:

>>> p.hostname
'127.0.0.1'
>>> p.port
6443

并且,由于 ParseResult 是一个命名元组,它有一个

_replace()
方法,该方法返回一个新的 ParseResult 并替换给定的字段:

>>> p._replace(netloc="foobar.tld")
ParseResult(scheme='https', netloc='foobar.tld', path='', params='', query='', fragment='')

但是,它不能取代

hostname
port
,因为它们是动态属性而不是元组的字段:

>>> p._replace(hostname="foobar.tld")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.11/collections/__init__.py", line 455, in _replace
    raise ValueError(f'Got unexpected field names: {list(kwds)!r}')
ValueError: Got unexpected field names: ['hostname']

简单地将新主机名与现有端口连接起来并将其作为新的 netloc 传递可能很诱人:

>>> p._replace(netloc='{}:{}'.format("foobar.tld", p.port))
ParseResult(scheme='https', netloc='foobar.tld:6443', path='', params='', query='', fragment='')

但是,如果我们考虑一下,这很快就会变得一团糟

  • 端口是可选的;
  • netloc 还可能包含用户名和可能的密码(例如
    https://user:[email protected]
    );
  • IPv6 文字必须括在括号中(即
    https://::1
    无效,但
    https://[::1]
    有效);
  • 也许我还缺少其他东西。

在 Python 中替换 URL 中的主机名的最简洁、正确的方法是什么?

该解决方案必须处理 IPv6(既作为原始 URL 的一部分,又作为替换值)、包含用户名/密码的 URL,以及所有格式正确的 URL。

(有各种各样的现有帖子试图提出相同的问题,但没有一个帖子要求(或提供)符合上述所有标准的解决方案。)

python urllib urlparse url-parsing
1个回答
0
投票

在 netloc 上使用字符串操作似乎是安全的。

import urllib.parse

def host_replace(url, new_host):
    parsed = urllib.parse.urlparse(url)
    old_hostname = parsed.hostname
    left, sep, right = parsed.netloc.rpartition(old_hostname)
    return parsed._replace(netloc=left + new_hostname + right).geturl()
© www.soinside.com 2019 - 2024. All rights reserved.