为什么套接字实现比请求慢?

时间:2014-09-06 23:49:52

标签: python sockets python-requests

我有一个python 3.4脚本获取多个网页。起初,我使用请求库来获取页面:

def get_page_requsets(url):
    r = requests.get(url)
    return r.content

以上代码的平均速度为每秒4.6个请求。 为了提高速度,我重新编写了使用套接字库的函数:

def get_page_socket(url):

    url = urlparse(url)
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((url.netloc, 80))
    req = '''
GET {} HTTP/1.1\r
Host: {}\r
Connection: Keep-Alive\r
\r
    '''.format(url.path, url.host, uagent)
    sock.send(req.encode())
    reply = b''
    while True:
        chunk = sock.recv(65535)
        if chunk:
            reply += chunk
        else:
            break
    sock.close()
    return reply

平均速度降至每秒4.04个请求。我并不希望提高速度,但是希望稍微增加,因为套接字更低。 这个图书馆问题还是我做错了什么?

2 个答案:

答案 0 :(得分:7)

requests使用urllib3,它可以非常有效地处理HTTP连接。尽可能重用与同一服务器的连接,从而节省套接字连接和拆卸成本:

  
      
  • 通过可选的客户端证书验证,为多个请求重用相同的套接字连接。请参阅:HTTPConnectionPoolHTTPSConnectionPool
  •   

此外,urllib3requests向服务器通告他们可以处理压缩的响应;通过压缩,您可以在相同的时间内传输更多数据,从而导致每秒更多的请求。

  
      
  • 支持gzip和deflate解码。请参阅:decode_gzip()decode_deflate()
  •   

urllib3也使用套接字(虽然通过http.client module);重新发明这个轮子没什么意义。也许您应该考虑并行获取URL,使用线程或多处理或eventlet; requests作者有gevents-requests integration package可以提供帮助。

答案 1 :(得分:2)

缓慢可能只是因为你做错了HTTP:你发出HTTP / 1.1请求甚至显式指定连接保持活动(甚至不需要,因为这是HTTP / 1.1隐含的)。但是,您只需从套接字读取并期望服务器在请求完成后关闭连接。但是服务器不会这样做,它将等待更多来自您的请求,因为保持活动并且仅在一段时间不活动后关闭连接,这取决于服务器配置。您很幸运能够连接到服务器,其超时非常短,您仍然可以获得每秒4.04个请求,而对于其他服务器,您的代码每分钟只需要几个请求。

如果要使用普通套接字创建简单的HTTP请求,请使用HTTP / 1.0,不要使用keep-alive。然后你就可以阅读直到服务器关闭,你也不必处理HTTP / 1.1引入的分块传输编码。您也不必处理压缩编码,因为您没有特别接受它们(但是一些损坏的服务器无论如何都会发送它们)。

但是,虽然这会使你的代码比现在更快,但它不会像请求那么快,因为所有这些保持活动,压缩等都被添加以提高速度。要正确地重新实现所有这些并不容易,所以我建议您继续使用请求库。