在Python中向给定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
。
有没有什么标准的方法来做到这一点呢?
15 个回答
72
为什么
我对这个页面上的所有解决方案都不太满意(来吧,我们最喜欢的复制粘贴的东西在哪里?),所以我根据这里的回答写了自己的解决方案。这个方案尽量做到全面,并且更符合Python的风格。我添加了对字典和布尔值参数的处理,以便让它更适合消费者(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: 重写现有参数,处理字典值:
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 = 'https://stackoverflow.com/test?answers=true'
>> new_params = {'answers': False, 'data': ['some','values']}
>> add_url_params(url, new_params)
'https://stackoverflow.com/test?data=some&data=values&answers=false'
"""
# Unquoting URL first so we don't lose 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 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
请注意,可能会有一些问题,如果你发现了,请告诉我,我们会一起改进这个东西。
95
把这个任务交给经过多次考验的requests库来处理。
我会这样做:
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)
234
在使用 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
。