190 votes

Ajouter des paramètres à une URL donnée en Python

Supposons qu'on me donne une URL.
Il peut déjà avoir des paramètres GET (par ex. http://example.com/search?q=question ) ou non (par ex. http://example.com/ ).

Et maintenant, j'ai besoin de lui ajouter des 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 .

Existe-t-il une manière standard de procéder ?

0 votes

Ce n'est pas une bonne réponse, car elle ne fait que renvoyer à la page d'accueil du site. yarl pour une solution en une ligne. Mais la documentation l'explique bien mieux que moi. Attention : si vous ne voyez pas d'inconvénient à ce qu'une librairie supplémentaire

236voto

Łukasz Points 5614

Il y a quelques bizarreries avec les urllib y urlparse modules. Voici un exemple concret :

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 un list avant que nous puissions tenter de modifier ses données.

21 votes

Vous voulez probablement utiliser urlparse.parse_qs au lieu de parse_qsl . Ce dernier renvoie une liste alors que vous voulez un dict. Voir docs.python.org/library/urlparse.html#urlparse.parse_qs .

12 votes

@florian : Au moins dans python 2.7 vous devez alors appeler urlencode como urllib.urlencode(query, doseq=True) . Sinon, les paramètres qui existaient dans l'url d'origine ne sont pas préservés correctement (parce qu'ils sont renvoyés sous forme de tuples à partir de @parse_qs@.

5 votes

Je l'ai réécrit pour qu'il fonctionne également avec Python 3. Code ici .

71voto

Sapphire64 Points 46

Pourquoi

Je n'ai pas été satisfait de toutes les solutions proposées sur cette page ( Allez, où est notre copier-coller préféré ? ) alors j'ai écrit le mien en me basant sur les réponses données ici. Il essaie d'être complet et plus pythonique. J'ai ajouté un gestionnaire pour dict y bool dans les arguments pour être davantage du côté du consommateur ( JS ) sympathiques, mais ils sont encore facultatifs, vous pouvez les laisser tomber.

Comment cela fonctionne

Test 1 : Ajout de nouveaux arguments, gestion des tableaux et des valeurs 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 args existants, gestion 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'

La parole ne vaut rien. Montrez-moi le code.

Le 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

Sachez qu'il peut y avoir des problèmes, si vous en trouvez un, faites-le moi savoir et nous l'améliorerons.

0 votes

Peut-être ajouter un try except with à partir de urllib.parse pour inclure le support de Python 3 ? Merci pour le snippet, très utile !

0 votes

Peut-être ajouter des importations aussi ?

1 votes

Désencode les urls codées telles que http://stackoverflow.com/with%2Fencoded?data=some&data=value‌​s&answe%2rs=false . Utilisez également trois chevrons >>> pour aider les doctests à ramasser vos doctests

65voto

Mike Mueller Points 1007

Vous souhaitez utiliser le codage URL si les chaînes de caractères peuvent contenir des données arbitraires (par exemple, les caractères tels que les esperluettes, les barres obliques, etc. devront être codés).

Vérifiez urllib.urlencode :

>>> import urllib
>>> urllib.urlencode({'lang':'en','tag':'python'})
'lang=en&tag=python'

Dans python3 :

from urllib import parse
parse.urlencode({'lang':'en','tag':'python'})

13 votes

Dans python 3, cette fonction a été déplacée vers urllib.parse.urlencode

29voto

surfeurX Points 570

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

11voto

unwind Points 181987

Oui : utiliser urllib .

De la 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

1 votes

Pouvez-vous donner un bref exemple ?

1 votes

F.read() vous montrera la page HTML. Pour voir l'url d'appel, f.geturl()

9 votes

-1 pour l'utilisation d'une requête HTTP pour l'analyse d'une URL (qui est en fait une manipulation de base des chaînes de caractères). De plus, le problème réel n'est pas pris en compte, car vous devez savoir à quoi ressemble l'URL pour pouvoir ajouter la chaîne de requête correctement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X