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
を、2番目のケースではhttp://example.com/search?lang=en&tag=python
を使用します。
これを行うための標準的な方法はありますか?
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
に変換する必要がありますデータ。
私はこのページのすべての解決策に満足していません(上に来ます、私たちのお気に入りのコピー&ペーストはどこですか?)ここの回答に基づいています。完全かつより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
いくつかの問題があるかもしれないことに注意してください、あなたが1つを見つけるならば、私に知らせてください、そして、我々はこのことをより良くします
文字列に任意のデータを含めることができる場合は、URLエンコードを使用します(たとえば、アンパサンド、スラッシュなどの文字をエンコードする必要があります)。
Urllib.urlencodeを確認してください。
>>> import urllib
>>> urllib.urlencode({'lang':'en','tag':'python'})
'lang=en&tag=python'
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
this answerに基づいて、単純な場合のワンライナー(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)
requests lib を使用している場合:
import requests
...
params = {'tag': 'python'}
requests.get(url, params=params)
テスト済みのバトルに外部委託します requests library 。
これは私がそれをする方法です:
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)
私はŁukaszバージョンが好きでしたが、この場合urllibとurllparse関数を使用するのはやや厄介なので、このようなことをする方が簡単だと思います:
params = urllib.urlencode(params)
if urlparse.urlparse(url)[4]:
print url + '&' + params
else:
print url + '?' + params
これは、2つの上位の回答よりもエレガントです。
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'
私が一番の答えで嫌う最も重要なこと(それでも良いことです):
query
がURLコンポーネントにあるインデックスを覚えておく必要があるParseResult
を作成する非常に冗長な方法私の応答の悪い点は、アンパックを使用して魔法のように見えるdict
マージですが、可変性に対する偏見のために、既存の辞書を更新することを好みます。
さらに別の答え:
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))
さまざまな urlparse
関数を使用して、既存のURLを分解します。 urllib.urlencode()
結合辞書で、次にurlparse.urlunparse()
すべてを元に戻すには。
または、urllib.urlencode()
の結果を取得し、適切にURLに連結します。
In 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"
実装方法は次のとおりです。
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