底子库httpx的使用

打印 上一主题 下一主题

主题 837|帖子 837|积分 2511

urllib 库和 requests 库的使用,已经可以爬取绝大多数网站的数据,但对于某些网站依然无能为力。什么情况?这些网站强制使用HTTP/2
.0协议访问,这时 urllib 和requests 是无法爬取数据的,由于它们只支持 HTTP/1.1,不支持 HTTP/2
.0。那这种情况下应该怎么办呢?
还是有办法的,只需要使用一些支持 HTTP/2
.0的请求库就好了,目前来说,比较有代表性的是hyper 和 httpx,后者使用起来更加方便,功能也更强大,requests 已有的功能它几乎都支持。
示例

下面我们来看一个案例,https://spa16.scrape.center/ 就是强制使用 HTTP/2
.0访问的一个网站,用欣赏器打开此网站,检察 Network面板,可以看到 Protocol 一列都是 h2,证明请求所用的协议是HTTP/2
.0,如下图所示。

这个网站用requests 是无法爬取的,不妨来尝试一下:
  1. import requests
  2. url = 'https://spa16.scrape.center/'
  3. response = requests.get(url)
  4. print(response.text)
复制代码
运行结果如下:
  1. requests.exceptions.ConnectionError: ('Connection aborted.', ConnectionResetError(10054, '远程主机强迫关闭了一个现有的连接。', None, 10054, None))
复制代码
可能有人认为这是没有设置请求头导致的,其实不是,真实原因是requests 这个库是使用 HTTP/1.1访问的目的网站,而目的网站会检测请求使用的协议是不是 HTTP/2
.0,如果不是就拒绝返回任何结果。
安装

httpx 可以直接使用 pip3 工具安装,所需的 Python 版本是 3.6及以上,安装命令如下:
  1. pip3 install httpx
复制代码
但如许安装完的 httpx 是不支持 HTTP/2
.0的,如果想支持,可以如许安装:
  1. pip3 install 'httpx[http2]'
复制代码
如许就既安装了 httpx,又安装了 httpx 对 HTTP/2
.0 的支持模块。
基本使用

httpx 和 requests 的很多 API存在相似之处,我们先看下最基本的 GET 请求的用法:
  1. import httpx
  2. response = httpx.get('https://www.httpbin.org/get')
  3. print(response.status_code)
  4. print(response.headers)
  5. print(response.text)
复制代码
这里我们还是请求之前的测试网站,直接使用htpx的get方法即可,用法和requests 里的一模一样,将返回结果赋值为response 变量,然后打印出它的status code、headers、text 等属性,运行结果如下:
  1. 200
  2. Headers({'date': 'Thu, 19 Dec 2024 14:27:23 GMT', 'content-type': 'application/json', 'content-length': '312', 'connection': 'keep-alive', 'server': 'gunicorn/19.9.0', 'access-control-allow-origin': '*', 'access-control-allow-credentials': 'true'})
  3. {
  4.   "args": {},
  5.   "headers": {
  6.     "Accept": "*/*",
  7.     "Accept-Encoding": "gzip, deflate",
  8.     "Host": "www.httpbin.org",
  9.     "User-Agent": "python-httpx/0.28.1",
  10.     "X-Amzn-Trace-Id": "Root=1-67642d4b-31795bb819573e2e7516a357"
  11.   },
  12.   "origin": "36.163.154.16",
  13.   "url": "https://www.httpbin.org/get"
  14. }
复制代码
输出结果包罗三项内容,status code 属性对应状态码,为 200;headers 属性对应相应头,是一Headers 对象,雷同于一个字典;text 属性对应相应体,可以看到其中的 User-Agent 是个、python-httpx/0.18.1,代表我们是用 httpx 请求的。
下面换一个 User-Agent 再请求一次,代码改写如下:
  1. import httpx
  2. headers = {
  3.     "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac 0s X 10 15 7)AppleWebKit/537.36 (KHTML, like Gecko)Chrome/90.0.4430.93 Safari/537.36"}
  4. response = httpx.get('https://www.httpbin.org/get', headers=headers)
  5. print(response.text)
复制代码
这里我们换了一个 User-Agent重新请求,并将其赋值为 headers 变量,然后通报给headers 参数,运行结果如下:
  1. {
  2.   "args": {},
  3.   "headers": {
  4.     "Accept": "*/*",
  5.     "Accept-Encoding": "gzip, deflate",
  6.     "Host": "www.httpbin.org",
  7.     "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac 0s X 10 15 7)AppleWebKit/537.36 (KHTML, like Gecko)Chrome/90.0.4430.93 Safari/537.36",
  8.     "X-Amzn-Trace-Id": "Root=1-67642df8-64d00406369b3f1b3660c57c"
  9.   },
  10.   "origin": "36.163.154.16",
  11.   "url": "https://www.httpbin.org/get"
  12. }
复制代码
可以发现更换后的 User-Agent 生效了。
回到本节开头提到的示例网站,我们试着用httpx请求一下这个网站,看看效果如何,代码如下:
  1. import httpx
  2. response = httpx.get('https://spa16.scrape.center')
  3. print(response.text)
复制代码
运行结果如下:
  1. httpx.ReadError: [WinError 10054] 远程主机强迫关闭了一个现有的连接。
复制代码
可以看到,抛出了和使用 requests 请求时雷同的错误,不是说好支持 HTTP/2
.0吗?其实,httpx 默认是不会开启对 HTTP/2
.0的支持的,默认使用的是 HTTP/1.1,需要手动声明一下才气使用 HTTP/2
.9,代码改写如下:
  1. import httpx
  2. client = httpx.Client(http2=True)
  3. response = client.get('https://spa16.scrape.center/')
  4. print(response.text)
复制代码
运行结果如下:
  1. <!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><meta name=referrer content=no-referrer><link rel=icon href=/favicon.ico><title>Scrape | Book</title><link href=/css/chunk-50522e84.e4e1dae6.css rel=prefetch><link href=/css/chunk-f52d396c.4f574d24.css rel=prefetch><link href=/js/chunk-50522e84.6b3e24aa.js rel=prefetch><link href=/js/chunk-f52d396c.f8f41620.js rel=prefetch><link href=/css/app.ea9d802a.css rel=preload as=style><link href=/js/app.b93891e2.js rel=preload as=script><link href=/js/chunk-vendors.a02ff921.js rel=preload as=script><link href=/css/app.ea9d802a.css rel=stylesheet></head><body><noscript><strong>We're sorry but portal doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=/js/chunk-vendors.a02ff921.js></script><script src=/js/app.b93891e2.js></script></body></html>
复制代码
这里我们声明白一个 Client 对象,赋值为 client 变量,同时显式地将 http2 参数设置为 True,如许便开启了对 HTTP/2
.0的支持,之后就会发现可以成功获取 HTML代码了。这也就印证了这个示例网站只能使用 HTTP/2
.0 访问。
刚才我们也提到了,httpx和requests有很多相似的API,上面实现的是 GET请求,对于POST请求、PUT请求和DELETE请求来说,实现方式是雷同的:
  1. import httpx
  2. r = httpx.get('https://www.httpbin.org/get', params={'name': 'germey'})
  3. r = httpx.post('https://www.httpbin.org/post', data={'name': 'germey'})
  4. r = httpx.put('https://www.httpbin.org/put')
  5. r = httpx.delete('https://www.httpbin.org/delete')
  6. r = httpx.patch('https://www.httpbin.org/patch')
复制代码
基于得到的 Response 对象,可以使用如部属性和方法获取想要的内容。


  • status code:状态码:
  • text:相应体的文本内容。
  • content:相应体的二进制内容,当请求的目的是二进制数据(如图片)时,可以使用此属性
    获取。
  • headers:相应头,是Headers 对象,可以用像获取字典中的内容一样获取其中某个 Header
    的值。
  • json:方法,可以调用此方法将文本结果转化为JSON对象。
除了这些,htpx还有一些基本用法也和requests极其雷同,这里就不再赘述了,可以参考官方文档:https://www.python-httpx.org/quickstart/。
Client对象

httpx 中有一些基本的 API和 requests 中的非常相似,但也有一些 API是不相似的,例如 htpx 中有一个 Client 对象,就可以和 requests 中的 Session 对象类比学习。
下面我们介绍 client 对象的使用。官方比较推荐的使用方式是withas语句,示例如下:
  1. import httpx
  2. with httpx.Client() as client:
  3.     response = client.get('https://www.httpbin.org/get')
  4.     print(response)
复制代码
运行结果如下:
  1. <Response [200 OK]>
复制代码
这个用法等价于:
  1. import httpx
  2. client = httpx.Client()
  3. try:
  4.     response = client.get('https://www.httpbin.org/get')
  5. finally:
  6.     client.close()
复制代码
两种方式的运行结果是一样的,只不外这里需要我们在最后显式地调用 close 方法来关闭 client对象。
另外,在声明 Client 对象时可以指定一些参数,例如 headers,如许使用该对象发起的所有请求都会默认带上这些参数配置,示例如下:
  1. import httpx
  2. url = "http://www.httpbin.org/headers"
  3. headers = {'User-Agent': 'my-app/0.0.1
  4. '}
  5. with httpx.Client(headers=headers) as client:
  6.     r = client.get(url)
  7.     print(r.json()['headers']['User-Agent'])
复制代码
这里我们声明白一个 headers 变量,内容为 User-Agent 属性,然后将此变量通报给 headers 参数初始化了一个 client 对象,并赋值为 client 变量,最后用 client 变量请求了测试网站,并打印返回结果中的 User-Agent 的内容:
  1. my-app/0.0.1
复制代码
可以看到,headers 成功赋值了。
关于 Client 对象的更多高级用法可以参考官方文档:https://www.python-httpx.org/advanced/。
支持 HTTP/2
.0


现在是要在客户端上开启对 HTTP/2
.0的支持,就像“基本使用”小节所说的那样,同样是声明Client 对象,然后将 http2 参数设置为True,如果不设置,那么默认支持 HTTP/1.1,即不开启对HTTP/2
.0 的支持。
写法如下:
  1. import httpx
  2. client = httpx.Client(http2=True)
  3. response = client.get('https://www.httpbin.org/get')
  4. print(response.text)
  5. print(response.http_version)
复制代码
这里我们输出了 response 变量的 http_version 属性,这是 requests 中不存在的属性,其结果可能为:
  1. HTTP/2
复制代码
这里输出的 http_version 属性值是 HTTP/2
,代表使用了 HTTP/2
.0 协议传输。
   留意:在客户端的 httpx 上启用对 HTTP/2
.0的支持并不意味着请求和相应都将通过 HTTP/2
.0 传输这得客户端和服务端都支持 HTTP/2
.0 才行。如果客户端连接到仅支持 HTTP/1.1 的服务器那么它也需要改用 HTTP/1.1。
  支持异步请求

httpx 还支持异步客户端请求(即 AsyncClient ),支持 Python的 async 请求模式,写法如下:
  1. import httpx
  2. import asyncio
  3. async def fetch(url):
  4.     async with httpx.AsyncClient(http2=True) as client:
  5.         response = await client.get(url)
  6.         print(response.text)
  7. if __name__ == '__main__':
  8.     asyncio.get_event_loop().run_until_complete(fetch('https://www.httpbin.org/get'))
复制代码
关于异步请求,目前仅了解一下即可,后面章节也会专门对异步请求进行讲解。大家也可以参考官方文档:https://www.python-httpx.org/async/。
总结

本篇博客介绍了 httpx的基本用法,该库的 API与requests的非常相似,简单易用,同时支持 HTTP/2
.0.
推荐大家使用。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

涛声依旧在

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表