我有一个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个请求。我并不希望提高速度,但是希望稍微增加,因为套接字更低。 这个图书馆问题还是我做错了什么?
答案 0 :(得分:7)
requests
使用urllib3
,它可以非常有效地处理HTTP连接。尽可能重用与同一服务器的连接,从而节省套接字连接和拆卸成本:
- 通过可选的客户端证书验证,为多个请求重用相同的套接字连接。请参阅:
HTTPConnectionPool
和HTTPSConnectionPool
此外,urllib3
和requests
向服务器通告他们可以处理压缩的响应;通过压缩,您可以在相同的时间内传输更多数据,从而导致每秒更多的请求。
- 支持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引入的分块传输编码。您也不必处理压缩编码,因为您没有特别接受它们(但是一些损坏的服务器无论如何都会发送它们)。
但是,虽然这会使你的代码比现在更快,但它不会像请求那么快,因为所有这些保持活动,压缩等都被添加以提高速度。要正确地重新实现所有这些并不容易,所以我建议您继续使用请求库。