HttpClientFactory和Agent有什么区别?

时间:2013-07-30 13:29:21

标签: python twisted.web

在提出问题之前,需要一些背景知识。我正在尝试向网站发出HTTP GETPOST请求,但有以下警告:

  • 预计会重定向
  • 需要Cookie
  • 请求必须通过SOCKS代理(v4a)

到目前为止,我一直在使用twisted.web.client.Agent及其子类(例如BrowserLikeRedirectAgent),但遗憾的是,似乎还没有支持SOCKS代理(并且ProxyAgent是一个禁止,因为这个类是用于HTTP代理的。)

我偶然发现twisted-socks,这似乎让我做了我想做的事,但我发现它使用HttpClientFactory代替代理,因此我的问题是:有什么区别HttpClientFactoryAgent我应该何时使用每一个?

下面是一些使用twisted-socks的示例代码。我还有两个问题:

  1. 如何在此示例中使用Cookie?我尝试将dictcookielib.CookieJar实例传递给HttpClientFactory的{​​{1}} kwarg,但是这会引发错误(关于字符串的预期......就在地球上怎么样我将cookie作为字符串发送?)

  2. 可以重构此代码以使用cookies吗?这将是理想的,因为我已经有一个相当大的代码库,其中考虑了Agent

  3. ```

    Agent

    ```

1 个答案:

答案 0 :(得分:3)

我认为你通常不会使用HTTPClientFactory,因为它似乎只是做HTTP请求而不是更多。这是非常低级别的。

如果您只想触发请求,则有一些函数(twisted.web.client.getPage.downloadPage)可以为您构建工厂,同时处理HTTP和HTTPS。

Agent是一个为您提供更高级别抽象的东西:它保留连接池,根据URL处理HTTP / HTTPS选择,处理代理等等。对,这是您通常想要的东西使用。

他们似乎没有共享太多代码,而代理人是HTTP11ClientProtocol(和HTTP11ClientFactory),因为getPage是旧的HTTPClientFactory(及其协议, HTTPPageGetter)。所以有一个twisted.web.client vs ._newclientAgent作为其公共API)二元性。我猜,历史原因和向后兼容性。

无论如何,这个库与开箱即用的Agent混合起来并不好,因为API已被破坏。 twisted-socks的SOCKSWrapper声明它实现了IStreamClientEndpoint接口,但是接口要求.connect方法返回一个将被IProtocol提供者触发的deffered(参见docs }),而SOCKSWrapper返回一个用地址(here's the line that does this)触发的。 看起来您可以轻松修复它,将行更改为:

self.handshakeDone.callback(self.transport.protocol)

一旦你这样做,你应该可以使用Agent的扭曲袜子。以下是一个示例:(使用inlineCallbacks和新的react,但您也可以使用带延迟的标准.addCallback和reactor.run()

from twisted.internet.endpoints import TCP4ClientEndpoint
from twisted.internet.defer import inlineCallbacks
from twisted.internet.task import react
from twisted.web.client import ProxyAgent, readBody

from socksclient import SOCKSWrapper

@react
@inlineCallbacks
def main(reactor):
    target = TCP4ClientEndpoint(reactor, 'example.com', 80)
    proxy = SOCKSWrapper(reactor, 'localhost', 9050, target)
    agent = ProxyAgent(proxy)
    request = yield agent.request('GET', 'http://example.com/')
    print (yield readBody(request))

此外,还有一个txsocksx库似乎更好用(并且可以安装pip!)。 API几乎相同,但是您将传递目标端点,在此之前您将通过代理端点:

from twisted.internet.endpoints import TCP4ClientEndpoint
from twisted.internet.defer import inlineCallbacks
from twisted.internet.task import react
from twisted.web.client import ProxyAgent, readBody

from txsocksx.client import SOCKS5ClientEndpoint

@react
@inlineCallbacks
def main(reactor):
    proxy = TCP4ClientEndpoint(reactor, 'localhost', 9050)
    proxied_endpoint = SOCKS5ClientEndpoint('example.com', 80, proxy)
    agent = ProxyAgent(proxied_endpoint)
    request = yield agent.request('GET', 'http://example.com/')
    print (yield readBody(request))