requests vs aiohttp vs httpx: Ein tiefer Einblick in Python HTTP Clients
Daniel Hayes
Full-Stack Engineer · Leapcell

Bewertung von Python HTTP-Client-Bibliotheken: Requests, Aiohttp und Httpx
Unter der großen Vielfalt an Python HTTP-Client-Bibliotheken sind die bekanntesten Requests, Aiohttp und Httpx. Ohne die Hilfe anderer Bibliotheken von Drittanbietern kann Requests nur synchrone Anfragen senden; Aiohttp kann nur asynchrone Anfragen senden; während Httpx die Fähigkeit besitzt, sowohl synchrone als auch asynchrone Anfragen zu senden.
Konzepte synchroner und asynchroner Anfragen
- Synchrone Anfragen: In Code, der in einem einzelnen Prozess und einem einzelnen Thread läuft, ist es nach dem Initiieren einer Anfrage unmöglich, die nächste Anfrage zu initiieren, bis das Rückgabeergebnis empfangen wurde.
- Asynchrone Anfragen: In Code, der in einem einzelnen Prozess und einem einzelnen Thread läuft, können nach dem Initiieren einer Anfrage während der Wartezeit auf die Rückgabe des Ergebnisses durch die Website weitere Anfragen gesendet werden.
Oberflächliche Bewertung: Performance-Vergleich beim Senden mehrerer GET-Anfragen
Obwohl die Testergebnisse von der Netzwerkgeschwindigkeit abhängen, kann das Testen im gleichen Zeitraum und im gleichen Netzwerk dennoch die Performance-Unterschiede zwischen diesen Bibliotheken aufzeigen.
Senden von Anfragen mit Requests
import requests url = 'https://www.leapcell.io/' headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36' } def main(): res = requests.get(url, headers=headers) print(res.status_code) if __name__ == '__main__': main()
Senden von Anfragen mit Httpx
Synchrone Anfragen
import httpx url = 'https://www.leapcell.io/' headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36' } def main(): res = httpx.get(url, headers=headers) print(res.status_code) if __name__ == '__main__': main()
Der synchrone Modus von Httpx weist eine Code-Überschneidungsrate von bis zu 99 % mit dem von Requests auf. Ersetzen Sie einfach requests
durch httpx
, und der Code kann normal ausgeführt werden.
Asynchrone Anfragen
import httpx import asyncio url = 'https://www.leapcell.io/' headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36' } async def main(): async with httpx.AsyncClient() as client: resp = await client.get(url, headers=headers) print(resp.status_code) if __name__ == '__main__': asyncio.run(main())
Senden von Anfragen mit Aiohttp
import asyncio import aiohttp url = 'https://www.leapcell.io/' headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36' } async def main(): async with aiohttp.ClientSession() as client: async with client.get(url, headers=headers) as resp: print(await resp.text()) print(resp.status) if __name__ == '__main__': asyncio.run(main())
Der Code von Aiohttp weist eine ungefähre Code-Überschneidungsrate von 90 % mit dem asynchronen Moduscode von Httpx auf. Er ersetzt einfach AsyncClient
durch ClientSession
.
Performance-Test: Zeitaufwand für das Senden von 100 Anfragen
Requests
Ohne die Verbindung aufrechtzuerhalten
import time import requests url = 'https://www.leapcell.io/' headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36' } def make_request(): resp = requests.get(url, headers=headers) print(resp.status_code) def main(): start = time.time() for _ in range(100): make_request() end = time.time() print(f'sent 100 requests, cost:{end - start}') if __name__ == '__main__': main()
Zeitaufwand für das Senden von 100 Anfragen: 10.295854091644287
Aufrechterhaltung der Verbindung
import time import requests session = requests.session() url = 'https://www.leapcell.io/' headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36' } def make_request(): resp = session.get(url, headers=headers) print(resp.status_code) def main(): start = time.time() for _ in range(100): make_request() end = time.time() print(f'sent 100 requests, cost:{end - start}') if __name__ == '__main__': main()
Zeitaufwand für das Senden von 100 Anfragen: 4.679062128067017, was offensichtlich etwa 6 Sekunden schneller ist.
Httpx
Synchroner Modus
import time import httpx url = 'https://www.leapcell.io/' headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36' } def make_request(): resp = httpx.get(url, headers=headers) print(resp.status_code) def main(): start = time.time() for _ in range(100): make_request() end = time.time() print(f'sent 100 requests, cost:{end - start}') if __name__ == '__main__': main()
Zeitaufwand für das Senden von 100 Anfragen: 16.60569405555725
Asynchroner Modus: Erstellen von httpx.AsyncClient() nur einmal
import httpx import asyncio import time url = 'https://www.leapcell.io/' headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36' } async def make_request(client): resp = await client.get(url, headers=headers) print(resp.status_code) async def main(): async with httpx.AsyncClient() as client: start = time.time() tasks = [asyncio.create_task(make_request(client)) for _ in range(100)] await asyncio.gather(*tasks) end = time.time() print(f'sent 100 requests, cost:{end - start}') if __name__ == '__main__': asyncio.run(main())
Zeitaufwand für das Senden von 100 Anfragen: 4.359861135482788
Asynchroner Modus: Erstellen von httpx.AsyncClient() jedes Mal
import httpx import asyncio import time url = 'https://www.leapcell.io/' headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36' } async def make_request(): async with httpx.AsyncClient() as client: resp = await client.get(url, headers=headers) print(resp.status_code) async def main(): start = time.time() tasks = [asyncio.create_task(make_request()) for _ in range(100)] await asyncio.gather(*tasks) end = time.time() print(f'sent 100 requests, cost:{end - start}') if __name__ == '__main__': asyncio.run(main())
Zeitaufwand für das Senden von 100 Anfragen: 6.378381013870239
Aiohttp
Erstellen von aiohttp.ClientSession() nur einmal
import time import asyncio import aiohttp url = 'https://www.leapcell.io/' headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36' } async def make_request(client): async with client.get(url, headers=headers) as resp: print(resp.status) async def main(): async with aiohttp.ClientSession() as client: start = time.time() tasks = [asyncio.create_task(make_request(client)) for _ in range(100)] await asyncio.gather(*tasks) end = time.time() print(f'sent 100 requests, cost:{end - start}') if __name__ == '__main__': asyncio.run(main())
Zeitaufwand für das Senden von 100 Anfragen: 2.235464334487915
Erstellen von aiohttp.ClientSession() jedes Mal
import time import asyncio import aiohttp url = 'https://www.leapcell.io/' headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36' } async def make_request(): async with aiohttp.ClientSession() as client: async with client.get(url, headers=headers) as resp: print(resp.status) def main(): start = time.time() tasks = [asyncio.ensure_future(make_request()) for _ in range(100)] loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.wait(tasks)) end = time.time() print(f'sent 100 requests, cost:{end - start}') if __name__ == '__main__': main()
Zeitaufwand für das Senden von 100 Anfragen: 2.6662471294403076
Geschwindigkeitsrangfolge für 100 Anfragen
aiohttp (Client nur einmal erstellen) > aiohttp (Client jedes Mal erstellen) > httpx asynchron (Client nur einmal erstellen) > requests.session > httpx asynchron (Client jedes Mal erstellen) > requests
Fazit
- Kleine Anzahl von Anfragen: Wenn nur wenige Anfragen gesendet werden sollen, ist die Verwendung von Requests oder des synchronen Modus von Httpx die einfachste Möglichkeit, den Code zu gestalten.
- Verbindungsmanagement von Requests: Ob Requests eine Session erstellt, um die Verbindung aufrechtzuerhalten oder nicht, macht einen großen Unterschied in der Geschwindigkeit. Wenn keine Anti-Crawling-Maßnahmen vorhanden sind und nur Geschwindigkeit angestrebt wird, wird empfohlen,
requests.session()
zu verwenden. - Gemischte Anforderungsprofile: Wenn eine große Anzahl von Anfragen gesendet werden muss und einige synchrone und einige asynchrone Anfragen erfordern, ist die Verwendung von Httpx am bequemsten.
- Hochgeschwindigkeits-Anforderungen: Wenn eine große Anzahl von Anfragen gesendet werden muss und die höchste Geschwindigkeit angestrebt wird, ist die Verwendung von Aiohttp die beste Wahl.
Leapcell: Das Beste vom Serverless Webhosting
Abschließend möchte ich eine Plattform empfehlen, die sich am besten für die Bereitstellung von Python-Diensten eignet: Leapcell
🚀 Mit Ihrer Lieblingssprache entwickeln
Entwickeln Sie mühelos in JavaScript, Python, Go oder Rust.
🌍 Unbegrenzt Projekte kostenlos bereitstellen
Sie zahlen nur für das, was Sie nutzen – keine Anfragen, keine Gebühren.
⚡ Pay-as-You-Go, keine versteckten Kosten
Keine Leerlaufgebühren, nur nahtlose Skalierbarkeit.
📖 Entdecken Sie unsere Dokumentation
🔹 Folgen Sie uns auf Twitter: @LeapcellHQ