使用会话时,您似乎每次都需要提供完整的网址,例如
session = requests.Session()
session.get('http://myserver/getstuff')
session.get('http://myserver/getstuff2')
这有点乏味。有没有办法做类似的事情:
session = requests.Session(url_base='http://myserver')
session.get('/getstuff')
session.get('/getstuff2')
答案 0 :(得分:8)
您可以将request.Session
作为子类并重载其__init__
和request
方法,如下所示:
# my_requests.py
import requests
class SessionWithUrlBase(requests.Session):
# In Python 3 you could place `url_base` after `*args`, but not in Python 2.
def __init__(self, url_base=None, *args, **kwargs):
super(SessionWithUrlBase, self).__init__(*args, **kwargs)
self.url_base = url_base
def request(self, method, url, **kwargs):
# Next line of code is here for example purposes only.
# You really shouldn't just use string concatenation here,
# take a look at urllib.parse.urljoin instead.
modified_url = self.url_base + url
return super(SessionWithUrlBase, self).request(method, modified_url, **kwargs)
然后您可以在代码中使用子类而不是requests.Session
:
from my_requests import SessionWithUrlBase
session = SessionWithUrlBase(url_base='https://stackoverflow.com/')
session.get('documentation') # https://stackoverflow.com/documentation
此外,您可以修补requests.Session
以避免修改现有代码库(此实现应该100%兼容),但请确保在任何代码调用requests.Session()
之前进行实际修补:
# monkey_patch.py
import requests
class SessionWithUrlBase(requests.Session):
...
requests.Session = SessionWithUrlBase
然后:
# main.py
import requests
import monkey_patch
session = requests.Session()
repr(session) # <monkey_patch.SessionWithUrlBase object at ...>
答案 1 :(得分:8)
此功能已在论坛上多次问过1,2,3。 here中记录的首选方法是子类化,如下所示:
from requests import Session
from urlparse import urljoin
class LiveServerSession(Session):
def __init__(self, prefix_url=None, *args, **kwargs):
super(LiveServerSession, self).__init__(*args, **kwargs)
self.prefix_url = prefix_url
def request(self, method, url, *args, **kwargs):
url = urljoin(self.prefix_url, url)
return super(LiveServerSession, self).request(method, url, *args, **kwargs)
您可以简单地按以下方式使用它:
baseUrl = 'http://api.twitter.com'
with LiveServerSession(baseUrl) as s:
resp = s.get('/1/statuses/home_timeline.json')
答案 2 :(得分:2)
requests_toolbelt.sessions.BaseUrlSession https://github.com/requests/toolbelt/blob/f5c86c51e0a01fbc8b3b4e1c286fd5c7cb3aacfa/requests_toolbelt/sessions.py#L6
注意:这使用标准库中的urljoin。提防urljoin的行为。
In [14]: from urlparse import urljoin
In [15]: urljoin('https://localhost/api', '/resource')
Out[15]: 'https://localhost/resource'
In [16]: urljoin('https://localhost/api', 'resource')
Out[16]: 'https://localhost/resource'
In [17]: urljoin('https://localhost/api/', '/resource')
Out[17]: 'https://localhost/resource'
In [18]: urljoin('https://localhost/api/', 'resource')
Out[18]: 'https://localhost/api/resource'
OR
import requests
from functools import partial
def PrefixUrlSession(prefix=None):
if prefix is None:
prefix = ""
else:
prefix = prefix.rstrip('/') + '/'
def new_request(prefix, f, method, url, *args, **kwargs):
return f(method, prefix + url, *args, **kwargs)
s = requests.Session()
s.request = partial(new_request, prefix, s.request)
return s
答案 3 :(得分:1)
我没有看到内置的方法,但您可以使用包装函数添加所需的功能:
from functools import wraps
import inspect
import requests
from requests.compat import urljoin
def _base_url(func, base):
'''Decorator for adding a base URL to func's url parameter'''
@wraps(func)
def wrapper(*args, **kwargs):
argname = 'url'
argspec = inspect.getargspec(func)
if argname in kwargs:
kwargs[argname] = urljoin(base, kwargs[argname])
else:
# Find and replace url parameter in positional args. The argspec
# includes self while args doesn't, so indexes have to be shifted
# over one
for i, name in enumerate(argspec[0]):
if name == argname:
args = list(args)
args[i-1] = urljoin(base, args[i-1])
break
return func(*args, **kwargs)
return wrapper
def inject_base_url(func):
'''Decorator for adding a base URL to all methods that take a url param'''
@wraps(func)
def wrapper(*args, **kwargs):
argname = 'base_url'
if argname in kwargs:
obj = args[0]
# Add base_url decorator to all methods that have a url parameter
for name, method in inspect.getmembers(obj, inspect.ismethod):
argspec = inspect.getargspec(method.__func__)
if 'url' in argspec[0]:
setattr(obj, name, _base_url(method, kwargs[argname]))
del kwargs[argname]
return func(*args, **kwargs)
return wrapper
# Wrap requests.Session.__init__ so it takes a base_url parameter
setattr(
requests.Session,
'__init__',
inject_base_url(getattr(requests.Session, '__init__'))
)
现在,您可以在构造新的requests.Session对象时指定基本URL:
s = requests.Session(base_url='http://stackoverflow.com')
s.get('questions') # http://stackoverflow.com/questions
s.post('documentation') # http://stackoverflow.com/documentation
# With no base_url, you get the default behavior
s = requests.Session()
s.get('http://google.com')
答案 4 :(得分:0)
保持简单,并使用内置方法进行加入(无后缀“ /”):
import urllib.parse
session = requests.Session()
session.my_base_url_join = lambda path: urllib.parse.urljoin(str_BASE_URL, path)
# use: session.get(session.my_base_url_join(path='/message'))