Изменение имени хоста в URL-адресе

Я пытаюсь использовать python для изменения имени хоста в URL-адресе и уже некоторое время играю с модулем urlparse, не найдя удовлетворительного решения. В качестве примера рассмотрим URL:

https://www.google.dk:80/barbaz

Я хотел бы заменить "www.google.dk", например. "www.foo.dk", поэтому я получаю следующий URL:

https://www.foo.dk:80/barbaz.

Итак, часть, которую я хочу заменить, - это то, что urlparse.urlsplit относится к имени хоста. Я надеялся, что результат urlsplit позволит мне вносить изменения, но результирующий тип ParseResult не позволяет мне это делать. Если я еще не смогу, конечно, восстановить новый url, добавив все части вместе с +, но это оставит меня с довольно уродливым кодом с большим количеством условных выражений, чтобы получить "://" и ":" в правильных местах.

Ответ 1

Вы можете использовать urlparse.urlparse и ParseResult._replace метод:

>>> import urlparse
>>> parsed = urlparse.urlparse("https://www.google.dk:80/barbaz")
>>> replaced = parsed._replace(netloc="www.foo.dk:80")
>>> print replaced
ParseResult(scheme='https', netloc='www.foo.dk:80', path='/barbaz', params='', query='', fragment='')

ParseResult является подклассом namedtuple и _replace является namedtuple метод, который:

возвращает новый экземпляр именованного кортежа, заменяющего указанные поля с новыми значениями

UPDATE

В качестве атрибута @2rs2ts в атрибуте comment netloc используется номер порта.

Хорошие новости: ParseResult имеет атрибуты hostname и port. Плохие новости: hostname и port не являются членами namedtuple, они являются динамическими свойствами, и вы не можете сделать parsed._replace(hostname="www.foo.dk"). Это вызовет исключение.

Если вы не хотите разбивать на :, и ваш url всегда имеет номер порта и не имеет username и password (который ссылается как https://username:[email protected]:80/barbaz ") вы можете:

parsed._replace(netloc="{}:{}".format(parsed.hostname, parsed.port))

Ответ 2

Вы можете использовать urlsplit и urlunsplit из Python urlparse:

>>> from urlparse import urlsplit, urlunsplit
>>> url = list(urlsplit('https://www.google.dk:80/barbaz'))
>>> url
['https', 'www.google.dk:80', '/barbaz', '', '']
>>> url[1] = 'www.foo.dk:80'
>>> new_url = urlunsplit(url)
>>> new_url
'https://www.foo.dk:80/barbaz'

Как состояние docs, аргумент, передаваемый urlunsplit(), может быть любым итерабельным с пятью пунктами, поэтому приведенный выше код работает так, как ожидалось.

Ответ 3

Использование методов urlparse и urlunparse модуля urlparse:

import urlparse

old_url = 'https://www.google.dk:80/barbaz'
url_lst = list(urlparse.urlparse(old_url))
# Now url_lst is ['https', 'www.google.dk:80', '/barbaz', '', '', '']
url_lst[1] = 'www.foo.dk:80'
# Now url_lst is ['https', 'www.foo.dk:80', '/barbaz', '', '', '']
new_url = urlparse.urlunparse(url_lst)

print(old_url)
print(new_url)

Вывод:

https://www.google.dk:80/barbaz
https://www.foo.dk:80/barbaz

Ответ 4

Простая замена строки хоста в netloc также работает в большинстве случаев:

>>> p = urlparse.urlparse('https://www.google.dk:80/barbaz')
>>> p._replace(netloc=p.netloc.replace(p.hostname, 'www.foo.dk')).geturl()
'https://www.foo.dk:80/barbaz'

Это не будет работать, если, случайно, имя пользователя или пароль совпадают с именем хоста. Вы не можете ограничить str.replace заменять только последнее вхождение, поэтому вместо этого мы можем использовать split и join:

>>> p = urlparse.urlparse('https://www.google.dk:[email protected]:80/barbaz')
>>> new_netloc = 'www.foo.dk'.join(p.netloc.rsplit(p.hostname, 1))
>>> p._replace(netloc=new_netloc).geturl()
'https://www.google.dk:[email protected]:80/barbaz'

Ответ 5

Я бы рекомендовал также использовать urlsplit и urlunsplit как ответ @linkyndy, но для Python3 это будет:

>>> from urllib.parse import urlsplit, urlunsplit
>>> url = list(urlsplit('https://www.google.dk:80/barbaz'))
>>> url
['https', 'www.google.dk:80', '/barbaz', '', '']
>>> url[1] = 'www.foo.dk:80'
>>> new_url = urlunsplit(url)
>>> new_url
'https://www.foo.dk:80/barbaz'

Ответ 6

Вы всегда можете сделать этот трюк:

>>> p = parse.urlparse("https://stackoverflow.com/questions/21628852/changing-hostname-in-a-url")
>>> parse.ParseResult(**dict(p._asdict(), netloc='perrito.com.ar')).geturl()
'https://perrito.com.ar/questions/21628852/changing-hostname-in-a-url'

Ответ 7

Чтобы просто заменить хост, не касаясь используемого порта (если есть), используйте это:

import re, urlparse

p = list(urlparse.urlsplit('https://www.google.dk:80/barbaz'))
p[1] = re.sub('^[^:]*', 'www.foo.dk', p[1])
print urlparse.urlunsplit(p)

печатает

https://www.foo.dk:80/barbaz

Если вы не дали никакого порта, это также прекрасно работает.

Если вы предпочитаете метод _replace, который указал Найджел, вы можете использовать это вместо:

p = urlparse.urlsplit('https://www.google.dk:80/barbaz')
p = p._replace(netloc=re.sub('^[^:]*', 'www.foo.dk', p.netloc))
print urlparse.urlunsplit(p)