Добавить параметры в заданный URL в Python
Предположим, мне дали URL-адрес.
Он может уже иметь параметры GET (например, http://example.com/search?q=question
), или он может не отображаться (например, http://example.com/
).
И теперь мне нужно добавить к нему некоторые параметры, например {'lang':'en','tag':'python'}
. В первом случае у меня будет http://example.com/search?q=question&lang=en&tag=python
, а во втором - http://example.com/search?lang=en&tag=python
.
Есть ли стандартный способ сделать это?
Ответы
Ответ 1
Есть несколько причуд с модулями urllib
и urlparse
. Вот рабочий пример:
try:
import urlparse
from urllib import urlencode
except: # For Python 3
import urllib.parse as urlparse
from urllib.parse import urlencode
url = "http://stackoverflow.com/search?q=question"
params = {'lang':'en','tag':'python'}
url_parts = list(urlparse.urlparse(url))
query = dict(urlparse.parse_qsl(url_parts[4]))
query.update(params)
url_parts[4] = urlencode(query)
print(urlparse.urlunparse(url_parts))
ParseResult
, результат urlparse()
, доступен только для чтения, и нам нужно преобразовать его в list
, прежде чем мы может попытаться изменить свои данные.
Ответ 2
Вы хотите использовать кодировку URL, если строки могут иметь произвольные данные (например, символы, такие как амперсанды, косые черты и т.д., должны быть закодированы).
Проверьте urllib.urlencode:
>>> import urllib
>>> urllib.urlencode({'lang':'en','tag':'python'})
'lang=en&tag=python'
Ответ 3
Почему
Я не был доволен всеми решениями на этой странице (давайте, где наша любимая копия-паста?), поэтому я написал свои ответы на основе ответов здесь. Он пытается быть полным и более Pythonic. Я добавил обработчик для dict и bool значений в аргументах, чтобы они были более дружественными к потребителю (JS), но они еще не являются обязательными, вы можете их оставить.
Как это работает
Тест 1: Добавление новых аргументов, обработка массивов и значений Bool:
url = 'http://stackoverflow.com/test'
new_params = {'answers': False, 'data': ['some','values']}
add_url_params(url, new_params) == \
'http://stackoverflow.com/test?data=some&data=values&answers=false'
Тест 2: Перезапись существующих аргументов, обработка значений DICT:
url = 'http://stackoverflow.com/test/?question=false'
new_params = {'question': {'__X__':'__Y__'}}
add_url_params(url, new_params) == \
'http://stackoverflow.com/test/?question=%7B%22__X__%22%3A+%22__Y__%22%7D'
Обсуждение дешево. Покажите мне код.
Сам код. Я попытался описать его подробно:
from json import dumps
try:
from urllib import urlencode, unquote
from urlparse import urlparse, parse_qsl, ParseResult
except ImportError:
# Python 3 fallback
from urllib.parse import (
urlencode, unquote, urlparse, parse_qsl, ParseResult
)
def add_url_params(url, params):
""" Add GET params to provided URL being aware of existing.
:param url: string of target URL
:param params: dict containing requested params to be added
:return: string with updated URL
>> url = 'http://stackoverflow.com/test?answers=true'
>> new_params = {'answers': False, 'data': ['some','values']}
>> add_url_params(url, new_params)
'http://stackoverflow.com/test?data=some&data=values&answers=false'
"""
# Unquoting URL first so we don't loose existing args
url = unquote(url)
# Extracting url info
parsed_url = urlparse(url)
# Extracting URL arguments from parsed URL
get_args = parsed_url.query
# Converting URL arguments to dict
parsed_get_args = dict(parse_qsl(get_args))
# Merging URL arguments dict with new params
parsed_get_args.update(params)
# Bool and Dict values should be converted to json-friendly values
# you may throw this part away if you don't like it :)
parsed_get_args.update(
{k: dumps(v) for k, v in parsed_get_args.items()
if isinstance(v, (bool, dict))}
)
# Converting URL argument to proper query string
encoded_get_args = urlencode(parsed_get_args, doseq=True)
# Creating new parsed result object based on provided with new
# URL arguments. Same thing happens inside of urlparse.
new_url = ParseResult(
parsed_url.scheme, parsed_url.netloc, parsed_url.path,
parsed_url.params, encoded_get_args, parsed_url.fragment
).geturl()
return new_url
Помните, что могут быть некоторые проблемы, если вы найдете их, сообщите мне, и мы сделаем это лучше.
Ответ 4
Вы также можете использовать модуль furl https://github.com/gruns/furl
>>> from furl import furl
>>> print furl('http://example.com/search?q=question').add({'lang':'en','tag':'python'}).url
http://example.com/search?q=question&lang=en&tag=python
Ответ 5
Да: используйте urllib.
Из examples в документации:
>>> import urllib
>>> params = urllib.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0})
>>> f = urllib.urlopen("http://www.musi-cal.com/cgi-bin/query?%s" % params)
>>> print f.geturl() # Prints the final URL with parameters.
>>> print f.read() # Prints the contents
Ответ 6
На основе этого ответа, однострочный для простых случаев (код Python 3):
from urllib.parse import urlparse, urlencode
url = "https://stackoverflow.com/search?q=question"
params = {'lang':'en','tag':'python'}
url += ('&' if urlparse(url).query else '?') + urlencode(params)
или
url += ('&', '?')[urlparse(url).query == ''] + urlencode(params)
Ответ 7
Мне понравилась версия Łukasz, но поскольку функции urllib и urllparse несколько неудобны для использования в этом случае, я думаю, что более просто сделать что-то вроде этого:
params = urllib.urlencode(params)
if urlparse.urlparse(url)[4]:
print url + '&' + params
else:
print url + '?' + params
Ответ 8
Используйте различные функции urlparse
, чтобы разрывать существующий URL, urllib.urlencode()
в объединенном словаре, затем urlparse.urlunparse()
, чтобы снова соединить все.
Или просто возьмите результат urllib.urlencode()
и соедините его с URL соответствующим образом.
Ответ 9
Еще один ответ:
def addGetParameters(url, newParams):
(scheme, netloc, path, params, query, fragment) = urlparse.urlparse(url)
queryList = urlparse.parse_qsl(query, keep_blank_values=True)
for key in newParams:
queryList.append((key, newParams[key]))
return urlparse.urlunparse((scheme, netloc, path, params, urllib.urlencode(queryList), fragment))
Ответ 10
В python 2.5
import cgi
import urllib
import urlparse
def add_url_param(url, **params):
n=3
parts = list(urlparse.urlsplit(url))
d = dict(cgi.parse_qsl(parts[n])) # use cgi.parse_qs for list values
d.update(params)
parts[n]=urllib.urlencode(d)
return urlparse.urlunsplit(parts)
url = "http://stackoverflow.com/search?q=question"
add_url_param(url, lang='en') == "http://stackoverflow.com/search?q=question&lang=en"
Ответ 11
Вот как я его реализовал.
import urllib
params = urllib.urlencode({'lang':'en','tag':'python'})
url = ''
if request.GET:
url = request.url + '&' + params
else:
url = request.url + '?' + params
Работал как шарм. Тем не менее, мне бы понравился более чистый способ реализовать это.
Другой способ реализации вышеизложенного заключается в методе.
import urllib
def add_url_param(request, **params):
new_url = ''
_params = dict(**params)
_params = urllib.urlencode(_params)
if _params:
if request.GET:
new_url = request.url + '&' + _params
else:
new_url = request.url + '?' + _params
else:
new_url = request.url
return new_ur
Ответ 12
Если вы используете запросы lib:
import requests
...
params = {'tag': 'python'}
requests.get(url, params=params)