如何在Python中对查询字符串进行URL编码?

757

在提交之前,我试图对这个字符串进行urlencode。

queryString = 'eventName=' + evt.fields["eventName"] + '&' + 'eventDescription=' + evt.fields["eventDescription"]; 
15个回答

1297

Python 2

你需要的是 urllib.quote_plus

safe_string = urllib.quote_plus('string_of_characters_like_these:$#@=?%^Q^$')

#Value: 'string_of_characters_like_these%3A%24%23%40%3D%3F%25%5EQ%5E%24'

Python 3

在Python 3中,urllib包已经被拆分成较小的组件。您将使用urllib.parse.quote_plus(请注意parse子模块)。

import urllib.parse
safe_string = urllib.parse.quote_plus(...)

9
谢谢!然而,在我的情况下,我需要输入:import urllib.parse ... urllib.parse.quote_plus(query) - ivkremer
3
很好,但为什么不使用Unicode?如果URL字符串是Unicode,我必须将其编码为UTF-8。还有其他的方法吗? - Karl Doenitz
8
这很有效,但在添加了参数 safe=';/?:@&=+$,' 之前,我无法访问一些在线服务(REST)。 - rovyko
1
在命令行中使用以下一行代码:python3 -c "import urllib.parse, sys; print(urllib.parse.quote_plus(sys.argv[1])) ",用于编码字符串。 - Amos Joshua
2
@AmosJoshua 我认为您在双括号“))”之后漏掉了一个双引号",应该是:python3 -c "import urllib.parse, sys; print(urllib.parse.quote_plus(sys.argv[1]))" "要编码的字符串" - lgespee
显示剩余4条评论

721

您需要将参数作为映射(字典)或2元组序列传递到urlencode()中:

>>> import urllib
>>> f = { 'eventName' : 'myEvent', 'eventDescription' : 'cool event'}
>>> urllib.urlencode(f)
'eventName=myEvent&eventDescription=cool+event'

Python 3或更高版本

使用urllib.parse.urlencode

>>> urllib.parse.urlencode(f)
eventName=myEvent&eventDescription=cool+event

请注意,这并不是通常意义上的url编码(请查看输出)。如果需要,请使用 urllib.parse.quote_plus

17
请注意,urllib.urlencode 并不总是解决问题。问题在于有些服务关心参数的顺序,而当你创建字典时,顺序会丢失。对于这种情况,像 Ricky 建议的那样使用 urllib.quote_plus 更好。 - Blairg23
33
从技术上讲,那是服务中的一个漏洞,不是吗? - holdenweb
11
如果你只想使一个字符串符合 URL 规范,而不是构建完整的查询参数字符串,该怎么做? - Mike 'Pomax' Kamermans
1
@Mike'Pomax'Kamermans -- 请参见例如https://dev59.com/V2ct5IYBdhLWcg3wc9Eg或Ricky对此问题的回答。 - bgporter
1
@bk0 看起来你的方法只适用于字典,而不是字符串。 - JD Gamboa
显示剩余9条评论

97

尝试使用 requests 代替 urllib,您就不需要烦恼 urlencode 了!

import requests
requests.get('http://youraddress.com', params=evt.fields)

编辑:

如果您需要有序的名称-值对或一个名称的多个值,请设置参数如下:

params=[('name1','value11'), ('name1','value12'), ('name2','value21'), ...]

使用字典的代替方法。


8
这并不解决对名称数值对进行排序的问题,同时这需要获取安装外部库的权限,而该项目可能无法实现这一点。 - dreftymac
1
我发布了最小的代码,可以为OP工作。OP没有要求有序对,但也是可行的,请参见我的更新。 - Barney Szabolcs
@drefymac:这个确实解决了排序问题(虽然这不是问题的一部分),请阅读我的更新答案。 - Barney Szabolcs

41

背景

  • Python(版本2.7.2)

问题

  • 您想生成一个url编码的查询字符串。
  • 您有一个包含名称-值对的字典或对象。
  • 您希望能够控制名称-值对的输出顺序。

解决方案

  • urllib.urlencode
  • urllib.quote_plus

注意事项

示例

以下是一个完整的解决方案,包括如何处理一些注意事项。

### ********************
## init python (version 2.7.2 )
import urllib

### ********************
## first setup a dictionary of name-value pairs
dict_name_value_pairs = {
  "bravo"   : "True != False",
  "alpha"   : "http://www.example.com",
  "charlie" : "hello world",
  "delta"   : "1234567 !@#$%^&*",
  "echo"    : "user@example.com",
  }

### ********************
## setup an exact ordering for the name-value pairs
ary_ordered_names = []
ary_ordered_names.append('alpha')
ary_ordered_names.append('bravo')
ary_ordered_names.append('charlie')
ary_ordered_names.append('delta')
ary_ordered_names.append('echo')

### ********************
## show the output results
if('NO we DO NOT care about the ordering of name-value pairs'):
  queryString  = urllib.urlencode(dict_name_value_pairs)
  print queryString 
  """
  echo=user%40example.com&bravo=True+%21%3D+False&delta=1234567+%21%40%23%24%25%5E%26%2A&charlie=hello+world&alpha=http%3A%2F%2Fwww.example.com
  """

if('YES we DO care about the ordering of name-value pairs'):
  queryString  = "&".join( [ item+'='+urllib.quote_plus(dict_name_value_pairs[item]) for item in ary_ordered_names ] )
  print queryString
  """
  alpha=http%3A%2F%2Fwww.example.com&bravo=True+%21%3D+False&charlie=hello+world&delta=1234567+%21%40%23%24%25%5E%26%2A&echo=user%40example.com
  """ 

36

29
жҲ‘дёӘдәәжӣҙе–ңж¬ўдҪҝз”Ёurllib.parse.quote()пјҢеӣ дёәе®ғдҪҝз”Ё%20иҖҢдёҚжҳҜ+жқҘд»ЈиЎЁз©әж јгҖӮ - binki

27

试试这个:

urllib.pathname2url(stringToURLEncode)

urlencode无法使用,因为它只适用于字典。 quote_plus未能产生正确的输出。


1
这真的很有帮助!在我的情况下,我只有一个要进行URL编码的字符串部分,例如我想将 my string 转换为 my%20string。你的解决方案对此非常有效! - TanguyP
对我来说,使用%20代替+有效。谢谢。 - Jossef Harush Kadouri
2
在Python 3中,现在是urllib.request.pathname2url - Alex Montoya

22

请注意,urllib.urlencode 并不总是能达到预期效果。问题在于,有些服务关心参数的顺序,在创建字典时可能会丢失。对于这种情况,正如Ricky所建议的那样,使用 urllib.quote_plus 更好。


2
如果您传递一个元组列表,它可以正常工作并保留顺序:>>> import urllib >>> urllib.urlencode([('name', 'brandon'), ('uid', 1000)]) 'name=brandon&uid=1000' - Brandon Rhodes

15
在Python 3中,这对我起作用了。
import urllib

urllib.parse.quote(query)

将字符串编码为整个URL的一部分对我很有效。 - Alvaro Castro
我必须执行import urllib.parse,否则会出现"AttributeError: module 'urllib' has no attribute 'parse'"的错误。 - undefined

6

供日后参考(例如:针对Python3)

>>> import urllib.request as req
>>> query = 'eventName=theEvent&eventDescription=testDesc'
>>> req.pathname2url(query)
>>> 'eventName%3DtheEvent%26eventDescription%3DtestDesc'

1
通常你只需要对值进行URL编码,而你在这里所做的会导致一个无效的GET查询。 - Codewithcheese
1
'c:/2 < 3' 在 Windows 上的输出是 '///C://2%20%3C%203'。我想要的是只输出 'c:/2%20%3C%203' - binki

6
import urllib.parse
query = 'Hellö Wörld@Python'
urllib.parse.quote(query) // returns Hell%C3%B6%20W%C3%B6rld%40Python


urllib.parse.quote已经在此前的答案中提到。 - Gino Mempin
@GinoMempin 另一个答案的问题在于它说的是import urllib,而应该是urllib.parse。是的,他们也可以建议进行编辑,但就目前而言,这个答案是两个中最正确的一个。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接