Supposons qu'on me donne une URL.
Il peut déjà avoir des paramètres GET (par exemple, http://example.com/search?q=question
) ou non (par exemple, http://example.com/
).
Et maintenant, je dois ajouter quelques paramètres comme {'lang':'en','tag':'python'}
. Dans le premier cas, je vais avoir http://example.com/search?q=question&lang=en&tag=python
et dans le second - http://example.com/search?lang=en&tag=python
.
Y at-il un moyen standard de le faire?
Il y a quelques bizarreries avec les modules urllib
et urlparse
. Voici un exemple de travail:
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
, le résultat de urlparse()
, est en lecture seule et nous devons le convertir en list
avant de pouvoir modifier sa Les données.
Je ne suis pas satisfait de toutes les solutions sur cette page ( allez, où est notre chose de copier-coller préférée? ) alors j'ai écrit moi-même basé sur les réponses ici. Il essaie d'être complet et plus pythonique. J'ai ajouté un gestionnaire pour dict et bool les valeurs dans les arguments pour être plus consommateur ( [~ # ~] js [ ~ # ~] ) amical, mais ils sont encore facultatifs, vous pouvez les laisser tomber.
Test 1: Ajout de nouveaux arguments, traitement des valeurs Arrays et 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'
Test 2: Réécriture des arguments existants, traitement des valeurs 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'
Code lui-même. J'ai essayé de le décrire en détail:
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
S'il vous plaît être conscient qu'il peut y avoir quelques problèmes, si vous en trouvez un s'il vous plaît faites le moi savoir et nous allons améliorer cette chose
Vous souhaitez utiliser le codage d'URL si les chaînes peuvent contenir des données arbitraires (par exemple, des caractères tels que des esperluettes, des barres obliques, etc. devront être codés).
Découvrez urllib.urlencode:
>>> import urllib
>>> urllib.urlencode({'lang':'en','tag':'python'})
'lang=en&tag=python'
Vous pouvez également utiliser le module 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
Basé sur this answer, one-liner pour les cas simples (code 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)
ou:
url += ('&', '?')[urlparse(url).query == ''] + urlencode(params)
Si vous utilisez le request lib :
import requests
...
params = {'tag': 'python'}
requests.get(url, params=params)
Oui: utilisez rllib .
Parmi les exemples dans la documentation:
>>> 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
Externalisez-le à la bataille testée bibliothèque de requêtes .
Voici comment je vais le faire:
from requests.models import PreparedRequest
url = 'http://example.com/search?q=question'
params = {'lang':'en','tag':'python'}
req = PreparedRequest()
req.prepare_url(url, params)
print(req.url)
J'ai aimé la version de Łukasz, mais comme les fonctions urllib et urllparse sont un peu difficiles à utiliser dans ce cas, je pense qu'il est plus simple de faire quelque chose comme ça:
params = urllib.urlencode(params)
if urlparse.urlparse(url)[4]:
print url + '&' + params
else:
print url + '?' + params
Je trouve cela plus élégant que les deux premières réponses:
from urllib.parse import urlencode, urlparse, parse_qs
def merge_url_query_params(url: str, additional_params: dict) -> str:
url_components = urlparse(url)
original_params = parse_qs(url_components.query)
# Before Python 3.5 you could update original_params with
# additional_params, but here all the variables are immutable.
merged_params = {**original_params, **additional_params}
updated_query = urlencode(merged_params, doseq=True)
# _replace() is how you can create a new NamedTuple with a changed field
return url_components._replace(query=updated_query).geturl()
assert merge_url_query_params(
'http://example.com/search?q=question',
{'lang':'en','tag':'python'},
) == 'http://example.com/search?q=question&lang=en&tag=python'
Les choses les plus importantes que je n'aime pas dans les réponses les plus fréquentes (elles sont néanmoins bonnes):
query
dans les composants de l'URLParseResult
Ce qui ne va pas dans ma réponse, c’est la fusion magique dict
qui utilise la décompression, mais je préfère cela à la mise à jour d’un dictionnaire existant en raison de mes préjugés contre la mutabilité.
Encore une autre réponse:
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))
Utilisez les différentes fonctions urlparse
pour séparer l'URL existante, urllib.urlencode()
dans le dictionnaire combiné, puis urlparse.urlunparse()
de tout remettre en place.
Ou prenez simplement le résultat de urllib.urlencode()
et concaténez-le correctement dans l'URL.
Dans 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"
Voici comment je l'ai implémenté.
import urllib
params = urllib.urlencode({'lang':'en','tag':'python'})
url = ''
if request.GET:
url = request.url + '&' + params
else:
url = request.url + '?' + params
Travaillé comme un charme. Cependant, j'aurais souhaité une méthode plus propre pour mettre cela en œuvre.
Une autre façon de mettre en œuvre ce qui précède est de le mettre dans une méthode.
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