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=pythonhttp://example.com/search?lang=en&tag=python.

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

답변:


180

urlliburlparse모듈 에는 몇 가지 단점이 있습니다. 다음은 작동하는 예입니다.

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하려고 노력합니다. 소비자 측이되기 위해 인수 에 dictbool 값에 대한 처리기를 추가했습니다 ( 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.