Python에서 주어진 URL에 매개 변수 추가


125

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.

이를 수행하는 표준 방법이 있습니까?

답변:


180

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우리가 데이터를 수정하려고하기 전에.


13
urlparse.parse_qs대신 사용하고 싶을 것입니다 parse_qsl. 후자는 목록을 반환하지만 사전을 원합니다. docs.python.org/library/urlparse.html#urlparse.parse_qs를 참조 하세요 .
— Florian Brucker 2012-06-06

11
@florian : 적어도 파이썬 2.7 urlencode에서는 urllib.urlencode(query, doseq=True). 그들이 @ parse_qs @에서 튜플로 반환되기 때문에 그렇지 않으면, 원래 URL에 존재 매개 변수 (제대로 보존되지 않습니다
— rluba

5
나는 이것을 파이썬 3에서도 작동하도록 다시 작성했습니다. 여기에 코드를 입력하십시오 .
— duality_

12
의 결과 urlparse()와는 urlsplit()실제로 namedtuple인스턴스. 따라서 변수에 직접 할당하고이를 url_parts = url_parts._replace(query = …)업데이트하는 데 사용할 수 있습니다.
— Feuermurmel 2016

2
주의-이 구현은 일부 RESTful 서비스에서 사용하는 반복 쿼리 매개 변수를 제거합니다. 약간의 수정으로이 문제를 해결할 수 있습니다. query = urlparse.parse_qsl (url_parts [4]) query + = params.items ()하지만 dict를 사용하여 기존 쿼리 매개 변수를 대체하려면 조금 더 걸립니다.
— ombre42

51

왜

이 페이지의 모든 솔루션에 만족하지 못했기 때문에 (자 , 우리가 가장 좋아하는 복사-붙여 넣기는 어디에 있습니까? ) 여기에 답변을 기반으로 직접 작성했습니다. 그것은 완전하고 더 Pythonic하려고 노력합니다. 소비자 측이되기 위해 인수 에 dict 및 bool 값에 대한 처리기를 추가했습니다 ( JS ) 친화적 인 했지만 아직 선택 사항이므로 삭제할 수 있습니다.

작동 원리

테스트 1 : 새 인수 추가, 배열 및 부울 값 처리 :

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

몇 가지 문제가있을 수 있습니다. 문제를 찾으면 알려 주시면이 문제를 개선하겠습니다.


Python 3 지원을 포함하기 위해 urllib.parse를 제외하고 시도를 추가 할 수 있습니까? 스 니펫 감사합니다. 매우 유용합니다!
— MattV

어쩌면 수입도 추가할까요?
— Christophe Roussy

인코딩 된 URL (예 : http://stackoverflow.com/with%2Fencoded?data=some&data=values&answe%2rs=false. 또한 3 개의 쉐브론 >>>을 사용 하여 doctest가 doctest를 선택하도록 도와주세요
— pelson

왜 변화하지 parsed_get_args = dict(parse_qsl(get_args))에parsed_get_args = parse_qs(get_args)
— 매트 M.

41

문자열에 임의의 데이터가있을 수있는 경우 URL 인코딩을 사용하려고합니다 (예 : 앰퍼샌드, 슬래시 등의 문자를 인코딩해야 함).

urllib.urlencode를 확인하십시오.

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

python3에서 :

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

5
파이썬 3에서, 이것은 이동되었습니다 urllib.parse.urlencode
— shad0w_wa1k3r

23

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

21

전투 테스트 요청 라이브러리에 아웃소싱 .

이것이 내가 할 방법입니다.

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)


11

예 : urllib를 사용하십시오 .

문서 의 예 에서 :

>>> 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
간단한 예를 들어 주시겠습니까?
— z4y4ts 2010 년

1
f.read ()는 HTML 페이지를 보여줄 것입니다. 호출 URL을 보려면 f.geturl ()
— ccheneson

5
-1은 URL을 구문 분석하기 위해 HTTP 요청을 사용하는 경우 (실제로는 기본 문자열 조작)입니다. 또한 쿼리 문자열을 올바르게 추가하려면 URL이 어떻게 보이는지 알아야하므로 실제 문제는 고려되지 않습니다.
— 찌르기

저자가 질문을 편집했거나이 답변은 관련이 없습니다.
— simplylizz 2013

11

이 답변을 기반으로 간단한 사례에 대한 한 줄짜리 (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)

4
"간단한 경우"를 언급 한 것을 알고 있지만 명확히하기 위해 ?앵커 ( #?stuff) 에있는 경우 제대로 작동하지 않습니다 .
— Yann Dìnendal

7

나는 이것이 두 가지 상위 답변보다 더 우아하다고 생각합니다.

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'

내가 최고 답변에서 싫어하는 가장 중요한 것 (그럼에도 불구하고 좋다) :

  • Łukasz : queryURL 구성 요소에있는 색인을 기억해야 함
  • Sapphire64 : 업데이트 된 파일을 만드는 매우 장황한 방법 ParseResult

내 응답에 대해 나쁜 점은 dict압축 해제를 사용하여 마법처럼 보이는 병합이지만, 변경 가능성에 대한 편견 때문에 이미 존재하는 사전을 업데이트하는 것을 선호합니다.


6

나는 Łukasz 버전을 좋아했지만 urllib 및 urllparse 함수는이 경우 사용하기 다소 어색하기 때문에 다음과 같이하는 것이 더 간단하다고 생각합니다.

params = urllib.urlencode(params)

if urlparse.urlparse(url)[4]:
    print url + '&' + params
else:
    print url + '?' + params

4
[4] 대신 .query는 어떻습니까?
— Debby Mendez

4

다양한 urlparse기능을 사용하여 urllib.urlencode()결합 된 사전 에서 기존 URL을 분리 한 다음 urlparse.urlunparse()모두 다시 합칩니다.

또는 결과를 가져 와서 urllib.urlencode()URL에 적절하게 연결하십시오.


3

또 다른 대답 :

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))

2

구현 방법은 다음과 같습니다.

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

1

파이썬 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"
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.