最佳的Python HTTP客户端用于网页抓取

发现2024年顶级Python HTTP客户端、它们的功能及其在网页抓取中的最佳应用场景。
4 min read
最佳Python HTTP客户端

HTTP客户端是有用的Python库,使您的代码能够向Web服务器或API发送请求并接收响应。它们使发送各种类型的HTTP请求(GET、POST、PUT、DELETE等)、获取数据、提交数据或在网站或API上执行操作变得容易。

在网页抓取方面,这些客户端通常与HTML解析库如Beautiful Soup或html5lib一起使用。

在本文中,您将了解一些最佳的Python HTTP客户端,包括Requests、urllib3、Uplink、GRequests、HTTPX和aiohttp。您将根据它们的功能、易用性、文档和支持以及流行度来评估每个客户端。本文结束时,您将更清楚哪个库最适合您的用例。

Requests

让我们从最流行的Python HTTP客户端:Requests库开始,每周下载量达到惊人的3000万次。

以下是如何使用Requests处理HTTP请求和响应的示例:

import requests

print("Testing `requests` library...")
resp = requests.get('https://httpbin.org/get', params={"foo": "bar"})
if resp.status_code == 200:     # success
    print(f"Response Text: {resp.text} (HTTP-{resp.status_code})")
else:   # error
    print(f"Error: HTTP-{resp.status_code}")

请注意,httpbin.org提供了用于测试各种HTTP方法的示例响应。

在这个代码片段中,requests.get(...)方法接受所需的URL和一个查询参数foo。您可以使用params参数传递任何查询参数。

使用Requests和其他HTTP客户端,您不需要手动将查询字符串添加到URL或编码您的数据;库会为您处理这些操作。要发送JSON数据,可以使用data参数传递Python字典,并可以使用resp.json()直接接收JSON响应。

Requests库默认自动处理HTTP重定向(3xx),这在网页抓取时非常有用,可以访问从重定向URL获取的内容。它还支持安全套接字层(SSL)连接。

在底层,Requests使用urllib3来管理低级别的HTTP任务,如连接池和SSL验证,为开发人员提供更高级别、更Python化的API。

此外,Requests支持会话管理,允许您在多个请求之间持久化参数,如cookies、headers或认证令牌。这对于网页抓取任务特别有用,因为在访问受限内容时,维护这些参数是必需的。

Requests库还支持流媒体,这对于涉及大响应的网页抓取任务(如下载文件或处理来自API的流媒体数据)非常有用。

为了有效处理响应数据而不将其全部加载到内存中,您可以使用iter_content()iter_lines()等方法:

import requests

print("Testing `requests` library with streaming...")
resp = requests.get('https://httpbin.org/stream/10', stream=True)
for chunk in resp.iter_content(chunk_size=1024):
    print(chunk.decode('utf-8'))

然而,Requests库缺乏内置的异步功能和内置的缓存支持(尽管可以通过requests-cache获得)。此外,Requests不支持HTTP/2,并且不太可能很快添加此功能,如此讨论中所述。

注意:HTTP/2是HTTP协议的较新版本,设计为比HTTP/1.1更快、更高效。它允许通过多路复用在单个传输控制协议(TCP)连接上发送多个请求和响应,从而减少客户端和服务器的连接并加快页面加载速度。然而,对HTTP/2的支持仍然有限。

Requests库简化了Python的HTTP交互。它因其简单的方法、简洁的语法、自动连接池以提高效率以及内置的JSON解码功能而脱颖而出。其易用性、会话管理、流媒体功能和广泛的文档使其成为开发人员的热门选择。

urllib3

urllib3是一个经过良好测试并广泛使用的库,不仅被开发人员使用,还被许多其他HTTP客户端使用。它为处理低级别的HTTP请求提供了有用的功能和自定义选项,适用于网页抓取。

以下是一个使用urllib3发出HTTP请求的基本示例:

import urllib3

print("Testing `urllib3` library...")
http = urllib3.PoolManager()    # PoolManager for connection pooling
resp = http.request('GET', 'https://httpbin.org/get', fields={"foo": "bar"})

if resp.status == 200:     # success
    print(f"Response: {resp.data.decode('utf-8')} (HTTP-{resp.status})")
else:    # error
    print(f"Error: HTTP-{resp.status}")

在这个代码片段中,urllib3.PoolManager()创建了一个连接池,可以在多个请求中重复使用,从而提高性能,避免为每个请求建立新连接的开销。除了URL,您可以使用fields参数传递所需的查询参数。

urllib3的一个显著特点是其处理流媒体响应的能力,使您能够有效处理大量数据而不将其全部加载到内存中。这在下载大文件或在网页抓取期间使用流媒体API时非常有用。

urllib3默认支持自动重定向,并具有内置的SSL支持。然而,它缺乏内置的异步功能、缓存支持和会话管理(如cookies),并且不支持HTTP/2。

尽管urllib3的连接池处理使其比Requests库更难使用,但urllib3使用简单的脚本语法,不像一些需要基于类的方法或装饰器的客户端,这使得urllib3在进行基本HTTP交互时非常有用。此外,urllib3有良好的文档

如果您想要一个功能强大的库而不需要会话管理,urllib3非常适合用于简单的网页抓取任务。

Uplink

Uplink是一个强大但较不为人知的Python HTTP客户端。它使用基于类的接口简化了与RESTful API的交互,使其在涉及API调用的网页抓取中特别有用。

看一下这个使用Uplink调用API端点的示例代码:

import uplink

@uplink.json
class JSONPlaceholderAPI(uplink.Consumer):
    @uplink.get("/posts/{post_id}")
    def get_post(self, post_id):
        pass


def demo_uplink():
    print("Testing `uplink` library...")
    api = JSONPlaceholderAPI(base_url="https://jsonplaceholder.typicode.com")
    resp = api.get_post(post_id=1)
    if resp.status_code == 200:     # success
        print(f"Response: {resp.json()} (HTTP-{resp.status_code})")
    else:   # error
        print(f"Error:HTTP-{resp.status_code}")

这个代码片段定义了一个JSONPlaceholderAPI类,它继承自uplink.Consumer。它使用@uplink.get装饰器为JSONPlaceholder API创建一个HTTP GET请求以检索特定的帖子。post_id参数通过@uplink.get("/posts/{post _id}")装饰器动态包含在端点中。网站https://jsonplaceholder.typicode.com模拟了一个REST API,提供用于测试和开发的JSON响应。

Uplink支持SSL并自动处理重定向以获取最终响应。它还提供了带您自己的HTTP库等高级功能。

然而,Uplink没有内置支持流媒体响应、异步请求、缓存(尽管可以使用requests-cache)和HTTP/2。

Uplink为其强大的功能提供了足够的文档,但它没有积极维护(最后一次发布是在2022年3月的0.9.7版本)且不太流行。虽然其基于类的方法和装饰器语法可能会吸引面向对象的开发人员,但对于那些更喜欢Python脚本风格的人来说,其易用性只有中等。

用户通常在需要主要从不同的RESTful API端点而不是HTML页面收集数据时选择Uplink。

GRequests

GRequests是著名的Requests库的扩展,增加了对异步请求的支持。它允许同时从多个网站或API获取数据。

与等待每个响应后再发送下一个请求的顺序请求不同,GRequests通过同时发送请求提高了效率。这在从多个网站或API获取数据时特别有益。

看一下这个示例:

import grequests

print("Testing `grequests` library...")
# Fetching data from multiple URLs
urls = [
    'https://www.python.org/',
    'http://httpbin.org/get',
    'http://httpbin.org/ip',
]

responses = grequests.map((grequests.get(url) for url in urls))
for resp in responses:
    print(f"Response for: {resp.url} ==> HTTP-{resp.status_code}")

在这个代码中,GRequests使用grequests.map(...)同时向不同的URL发送三个GET请求,并将响应收集到一个名为responses的列表中。然后,它迭代这些响应并打印它们。在内部,GRequests使用gevent,一个基于协程的网络库,用于异步HTTP请求。这允许您同时发送多个HTTP请求而无需管理复杂的并发。一个实际应用是抓取不同网站上的新闻以获取特定主题或类别的内容。

GRequests还支持自动处理重定向、SSL支持以及在不将其全部加载到内存中的情况下处理流媒体响应。然而,请记住,GRequests没有内置的HTTP/2支持或缓存功能,尽管可以使用requests-cache

GRequests通过类似于其基础库Requests的直观方法简化了异步HTTP请求。它消除了使用复杂的async/await构造来处理并发的需求,使其易于使用。然而,由于其小型代码库(0.7.0版本中有213行代码)和较少的开发活动,GRequests的文档较少。这些因素导致其流行度较低。

当您需要同时从多个来源收集数据时,应该考虑使用GRequests,因为它具有易于使用的异步功能。

HTTPX

HTTPX是一个现代且功能丰富的Python HTTP客户端,广泛用于各种网页抓取项目。它旨在替代Python的Requests库,同时提供异步支持和更好的性能。

以下示例演示了使用HTTPX的异步HTTP GET请求:

import httpx
import asyncio

async def fetch_posts():
    async with httpx.AsyncClient() as client:
        response = await client.get('https://jsonplaceholder.typicode.com/posts')
        return response.json()

async def httpx_demo():
    print("Testing `httpx` library...")
    posts = await fetch_posts()
    for idx, post in enumerate(posts):
        print(f"Post #{idx+1}: {post['title']}")

# async entry point to execute the code
asyncio.run(httpx_demo())

此代码定义了一个名为fetch_posts()的异步函数,使用httpx.AsyncClient()https://jsonplaceholder.typicode.com/postsAPI检索虚拟博客帖子。另一个异步函数httpx_demo()等待fetch_posts()返回这些帖子,然后在循环中打印它们的标题。最后,asyncio.run(httpx_demo())作为入口点异步执行httpx_demo()

除了内置的异步HTTP客户端支持,HTTPX还提供内置的HTTP/2支持。这允许通过单个TCP连接同时加载多个资源,从而加快网页加载速度并使网站更难跟踪您的浏览器指纹。

要发送HTTP/2请求,只需在创建HTTPX客户端时设置http2=True参数:

import httpx

client = httpx.Client(http2=True)
response = client.get("https://http2.github.io/")
print(response)

请记住,要使用HTTP/2,您需要安装支持http2的HTTPX:

pip install httpx[http2]

此外,HTTPX提供了出色的流媒体响应支持,使您能够有效处理大响应或数据流而不将整个响应加载到内存中。

以下是使用HTTPX流式文本响应的示例:

with httpx.stream("GET", "https://httpbin.org/stream/10") as resp:
   for text in resp.iter_text():
       print(text)

虽然HTTPX没有内置的缓存功能,但您可以使用Hishel

HTTPX默认不跟随HTTP重定向,但您可以使用follow_redirects参数启用此功能:

import httpx

# test http --> https redirect
response = httpx.get('http://github.com/', follow_redirects=True)

尽管其异步功能增加了一些复杂性,HTTPX提供了用于HTTP通信的简单方法,并支持易于使用的同步请求。这使其对初学者和有经验的开发人员都很容易访问。此外,由于其广泛文档和活跃的开发者社区构建的HTTPX集成工具,HTTPX的使用量正在增长。

如果您正在寻找一个功能丰富的异步HTTP客户端,请考虑使用HTTPX。

aiohttp

与HTTPX类似,aiohttp提供了内置的异步HTTP请求支持。然而,aiohttp专为异步编程设计,使其在需要并发和非阻塞请求的情况下表现出色。这使其非常适合高性能的网页抓取项目,并且易于与代理一起使用

以下是如何使用aiohttp同时抓取多个URL的示例:

import asyncio
import aiohttp

async def fetch_data(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.text()

async def demo_aiohttp():
    print("Testing `aiohttp` library...")
    urls = [
        'https://www.python.org/',
        'http://httpbin.org/get',
        'http://httpbin.org/ip',
    ]
    tasks = [fetch_data(url) for url in urls]
    responses = await asyncio.gather(*tasks)
    for resp_text in responses:
        print(f"Response: {resp_text}")

# async entry point to execute the code
asyncio.run(demo_aiohttp())

异步函数fetch_data(...)创建了一个aiohttp.ClientSession()并向指定URL发送GET请求。然后它为每个URL创建一个任务列表并使用asyncio.gather(...)并发执行这些任务。所有任务完成后,收集并打印抓取的数据(在本例中为响应文本)。实际执行通过asyncio.run(demo_aiohttp())启动。

aiohttp自动处理HTTP重定向并支持流媒体响应,确保在不使用过多内存的情况下有效管理大文件或数据流。它还提供了灵活性,可以使用广泛的第三方中间件和扩展。

此外,如果需要,aiohttp还可以作为开发服务器,尽管本文仅关注其HTTP客户端功能。

然而,aiohttp缺乏对HTTP/2的支持和内置的缓存功能。尽管如此,当需要时可以使用如aiohttp-client-cache等库来集成缓存。

与更简单的HTTP客户端如Requests相比,aiohttp可能更复杂,特别是对于初学者。其异步性质和附加功能需要对Python中的异步编程有较好的理解。然而,aiohttp非常受欢迎,在GitHub上有14.7K星,并且有许多第三方库构建在其之上。aiohttp还提供了全面的文档供开发人员使用。

如果您正在寻找完整的异步支持,请考虑使用aiohttp。其异步性能使其非常适合实时数据抓取任务,如监控股价或跟踪选举等实时事件。

查看下表以快速了解顶级Python HTTP客户端:

Requests urllib3 Uplink GRequests HTTPX aiohttp
易用性 简单 简单到中等 中等 简单 中等 中等
自动重定向 需要启用
SSL支持
异步功能
流媒体响应
HTTP/2支持
缓存支持 通过:requests-cache 通过:requests-cache 通过:requests-cache 通过:Hishel 通过:aiohttp-client-cache

结论

在本文中,您了解了一些流行的Python HTTP客户端,包括Requests、urllib3、Uplink、GRequests、HTTPX和aiohttp,每个客户端都有独特的功能,如简单性、异步支持、流媒体和HTTP/2。

虽然Requests、Uplink和GRequests以其简单性而闻名,但aiohttp和HTTPX提供了强大的异步功能。尽管Requests仍然最受欢迎,但由于其异步能力,aiohttp和HTTPX正在获得越来越多的关注。最终,您需要审查每个客户端以选择最适合您需求的客户端。

在实际的网页抓取中,您需要考虑的不仅仅是HTTP客户端,如绕过反机器人措施和使用代理。幸运的是,Bright Data可以提供帮助。

Bright Data通过网页抓取IDE等工具使网页抓取变得更容易,提供现成的JavaScript函数和模板,以及网页解锁器,它可以绕过CAPTCHA和反机器人措施。Bright Data的抓取浏览器与Puppeteer、Playwright和Selenium集成以进行多步骤数据收集。此外,Bright Data的代理网络和服务允许从不同位置访问。这些工具处理复杂任务,如管理代理和解决CAPTCHA,因此您可以专注于获取所需数据。

今天开始您的免费试用,体验Bright Data提供的一切。