Изменение имени хоста в 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)