Python请求:Session中的URL基础

paj*_*j28 16 python python-requests

使用Session时,似乎每次都需要提供完整的URL,例如

session = requests.Session()
session.get('http://myserver/getstuff')
session.get('http://myserver/getstuff2')
Run Code Online (Sandbox Code Playgroud)

这有点单调乏味.有没有办法做这样的事情:

session = requests.Session(url_base='http://myserver')
session.get('/getstuff')
session.get('/getstuff2')
Run Code Online (Sandbox Code Playgroud)

rou*_*ble 12

此功能已被要求在论坛上几次1,2,3.这里记录的首选方法是子类化,如下所示:

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)
Run Code Online (Sandbox Code Playgroud)

你可以简单地使用它如下:

baseUrl = 'http://api.twitter.com'
with LiveServerSession(baseUrl) as s:
    resp = s.get('/1/statuses/home_timeline.json')
Run Code Online (Sandbox Code Playgroud)

  • 我喜欢这个解决方案,但有点不幸的是,我们必须在以下 14 个参数丢失输入和复制所有这些参数及其类型的情况下实现该方法之间做出选择。 (7认同)

rob*_*one 11

你可以像这样子类化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)
Run Code Online (Sandbox Code Playgroud)

然后你可以使用你的子类代替requests.Session你的代码:

from my_requests import SessionWithUrlBase


session = SessionWithUrlBase(url_base='https://stackoverflow.com/')
session.get('documentation')  # https://stackoverflow.com/documentation
Run Code Online (Sandbox Code Playgroud)

你也可以使用monkey-patch requests.Session来避免修改现有的代码库(这个实现应该是100%兼容的),但是在任何代码调用之前一定要做实际的修补requests.Session():

# monkey_patch.py
import requests


class SessionWithUrlBase(requests.Session):
    ...

requests.Session = SessionWithUrlBase
Run Code Online (Sandbox Code Playgroud)

然后:

# main.py
import requests
import monkey_patch


session = requests.Session()
repr(session)  # <monkey_patch.SessionWithUrlBase object at ...>
Run Code Online (Sandbox Code Playgroud)


khl*_*asd 5

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'
Run Code Online (Sandbox Code Playgroud)

要么

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             
Run Code Online (Sandbox Code Playgroud)

  • 我确信删除 URI 中的“api”部分是有一定道理的,但是天哪,如果不是一大早喝一杯新鲜的咖啡,我会在这上面呆上几个小时想知道为什么我的请求电话不起作用。 (3认同)
  • 在 python3 中,urlparse 模块已被重命名。您应该使用“from urllib.parse import urljoin”代替 (2认同)