web-dev-qa-db-ja.com

urlencode python)を使用してクエリ文字列を作成します

urllibモジュールを使用してgetリクエストを送信できるようにURLを作成しようとしています。

私の_final_url_は

_url = "www.example.com/find.php?data=http%3A%2F%2Fwww.stackoverflow.com&search=Generate+value"
_

これを達成するために、私は次の方法を試しました。

_>>> initial_url = "http://www.stackoverflow.com"
>>> search = "Generate+value"
>>> params = {"data":initial_url,"search":search}
>>> query_string = urllib.urlencode(params)
>>> query_string
'search=Generate%2Bvalue&data=http%3A%2F%2Fwww.stackoverflow.com'
_

私の_query_string_を_final_url_の形式と比較すると、2つのことがわかります。

1)data=()&search=ではなくパラメータの順序が逆になっていますsearch=()&data=

2)urlencodeも_+_を_Generate+value_にエンコードしました

最初の変更は、辞書のランダムな動作によるものだと思います。だから、私は OrderedDictを使って辞書を逆にする を使うことを考えました。として、私は_python 2.6.5_を使用しています

_pip install ordereddict
_

しかし、試してみるとコードで使用できません

_>>> od = OrderedDict((('a', 'first'), ('b', 'second')))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'OrderedDict' is not defined
_

だから、私の質問は、python 2.6.5でOrderedDictを使用する正しい方法は何ですか?また、urlencodeが_+_を無視するようにするにはどうすればよいですか? _Generate+value_で。

また、これはURLを構築するための正しいアプローチですか。

11
RanRag

+のエンコードについて心配する必要はありません。URLをエスケープ解除した後、サーバーに復元する必要があります。名前付きパラメーターの順序も重要ではありません。

OrderedDictを考慮すると、Pythonに組み込まれているわけではありません。collectionsからインポートする必要があります。

from urllib import urlencode, quote
# from urllib.parse import urlencode # python3
from collections import OrderedDict

initial_url = "http://www.stackoverflow.com"
search = "Generate+value"
query_string = urlencode(OrderedDict(data=initial_url,search=search))
url = 'www.example.com/find.php?' + query_string 

pythonが古すぎるで、モジュールcollectionsにOrderedDictがない場合は、次を使用します。

encoded = "&".join( "%s=%s" % (key, quote(parameters[key], safe="+")) 
    for key in ordered(parameters.keys()))

とにかく、パラメータの順序は重要ではありません。

safequoteパラメーターに注意してください。 +がエスケープされるのを防ぎますが、サーバーがGenerate+valueGenerate valueとして解釈することを意味します。 +を書き込み、%2Bを安全な文字としてマークすることにより、手動で%をエスケープできます。

20
Aleš Kotnik

まず、httpリクエストのパラメータの順序は完全に無関係である必要があります。そうでない場合は、反対側の解析ライブラリが何か問題を抱えています。

次に、もちろん+がエンコードされます。 +は、エンコードされたURLのスペースのプレースホルダーとして使用されるため、生の文字列に+が含まれている場合は、これをエスケープする必要があります。 urlencodeはエンコードされていない文字列を想定しているため、すでにエンコードされている文字列を渡すことはできません。

3
mata

質問と他の回答に関するいくつかのコメント:

  1. _urllib.urlencode_で順序を保持したい場合は、mapping(dict)の代わりにk/vペアの順序付けられたシーケンスを送信します。 dictを渡すと、urlencodefoo.items()を呼び出して反復可能なシーケンスを取得します。

# urllib.urlencode accepts a mapping or sequence # the output of this can vary, because `items()` is called on the dict urllib.urlencode({"data": initial_url,"search": search}) # the output of this will not vary urllib.urlencode((("data", initial_url), ("search", search)))

また、secondard doseq引数を渡して、反復可能な値の処理方法を調整することもできます。

  1. パラメータの順序は関係ありません。これらの2つのURLを例にとってみましょう。

    https://example.com?foo=bar&bar=foohttps://example.com?bar=foo&foo=bar

    Httpサーバーは、これらのパラメーターの順序は無関係であると見なす必要がありますが、URLを比較するように設計された関数はそうではありません。 URLを安全に比較するには、これらのパラメータを並べ替える必要があります。

    ただし、重複するキーを検討してください。

    https://example.com?foo=3&foo=2&foo=1

URI仕様は重複キーをサポートしていますが、優先順位や順序には対応していません。

特定のアプリケーションでは、これらはそれぞれ異なる結果をトリガーし、同様に有効である可能性があります。

_https://example.com?foo=1&foo=2&foo=3
https://example.com?foo=1&foo=3&foo=2
https://example.com?foo=2&foo=3&foo=1
https://example.com?foo=2&foo=1&foo=3
https://example.com?foo=3&foo=1&foo=2
https://example.com?foo=3&foo=2&foo=1
_
  1. _+_は、スペースをurlencoded形式で表す予約文字です(パスの一部の_%20_に対して)。 _urllib.urlencode_は、urllib.quote_plus()ではなくurllib.quote()を使用してエスケープします。 OPはおそらくこれを実行したかっただけです。

initial_url = "http://www.stackoverflow.com" search = "Generate value" urllib.urlencode((("data", initial_url), ("search", search)))

生成するもの:

_data=http%3A%2F%2Fwww.stackoverflow.com&search=Generate+value_

出力として。

1