跟着崔庆才学爬虫:httpx的使用

前面我们学习了urllib库和requests库的使用,已经可以爬取大多数网站的数据了,但是对于一些网站还是无能为力,究其原因是因为这些网站前置使用HTTP/2.0协议访问,这时urllib和requests是无法访问数据的,因为它们支支持HTTP/1.1,不支持HTTP2.0。那么这时该怎么办呢?

还是有办法的只需要使用一些支持HTTP/2.0请求库就可以了,requests已有的功能他都支持。

所以本节就开始httpx的使用。

引入

下面我们来看一个实例,https://spa16.scrape.center/就是一个强制HTTP/2.0访问的一个网站,用浏览器打开此网站,f12点击网络,右键点击表头选择协议,可以看到协议一列都是h2,证明请求所用的协议是HTTP/2.0。

 这个网站是无法使用requests爬取的,我们可以试一下

import requests
url ='https://spa16.scrape.center/'
resp = requests.get(url)
print(resp.text)

 运行结果报错:

  File "d:\跟着崔庆才学爬虫\.venv\Lib\site-packages\urllib3\connectionpool.py", line 791, in urlopen
    response = self._make_request(
..........
                
  File "C:\Users\30255\AppData\Local\Programs\Python\Python311\Lib\http\client.py", line 287, in _read_status
    raise RemoteDisconnected("Remote end closed connection without"
http.client.RemoteDisconnected: Remote end closed connection without response

During handling of the above exception, another exception occurred:

Traceback (most recent call last):

.......
                         
  File "C:\Users\30255\AppData\Local\Programs\Python\Python311\Lib\http\client.py", line 287, in _read_status
    raise RemoteDisconnected("Remote end closed connection without"
urllib3.exceptions.ProtocolError: ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):

可以看到首先抛出的错误就是RemoteDisconnected错误,请求失败。

可能有人会认为这是没有设置请求头导致的,其实不是,真实原因是requests这个库是使用HTTP/1,1访问的目标网站,而目标网站会检测请求使用的是不是HTTP/2.0如果不是就拒绝返回任何结果。

安装

安装命令 : pip install httpx

 但是这样安装完的httpx是不支持HTTP/2.0的,如果想支持可以这样安装

pip install 'httpx[http2]'

这样就既安装了httpx,又安装了httpx对http/2.0的支持模块

基本使用

用之前的测试网站看一下httpx的基本使用

import httpx
resp = httpx.get('https://www.httpbin.org/get')
print(resp.status_code)
print(resp.headers)
print(resp.text)

运行结果如下

200
Headers({'date': 'Thu, 16 Nov 2023 07:23:51 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'})
{
  "args": {},
  "headers": {
    "Accept": "*/*",
    "Accept-Encoding": "gzip, deflate",
    "Host": "www.httpbin.org",
    "User-Agent": "python-httpx/0.25.1",
    "X-Amzn-Trace-Id": "Root=1-6555c387-1a52f7803da99c9f5716c911"
  },
  "origin": "112.32.67.234",
  "url": "https://www.httpbin.org/get"
}

这里可以看出httpx和requests的用法基本一致,将返回结果赋值为resp变量,然后打印状态码,请求头,以及文本等属性,通过返回结果我们可以看到其中的User-Agent是一个 "User-Agent": "python-httpx/0.25.1",代表我们用的是httpx请求的

我们更换一下User-Agent在请求一次,代码如下

import httpx
from fake_useragent import UserAgent
headers = {"User-Agent":UserAgent().chrome}
resp = httpx.get('https://www.httpbin.org/get',headers=headers)

print(resp.text)

请求结果如下:

{
  "args": {},
  "headers": {
    "Accept": "*/*",
    "Accept-Encoding": "gzip, deflate",
    "Host": "www.httpbin.org",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36",      
    "X-Amzn-Trace-Id": "Root=1-6555c5a4-416117406c4a2c030ef6bab3"
  },
  "origin": "112.32.67.234",
  "url": "https://www.httpbin.org/get"
}

 可以发现,我们更换的User-Agent生效了。

现在我们再用开头的实例网站,测试一下httpx是否能够爬取网站内容

import httpx
url ='https://spa16.scrape.center/'
resp = httpx.get(url)
print(resp.text)

运行发现抛出了和requests请求时类似的错误,不是支持HTTP/2.0吗?httpx默认是不会开启对HTTP/2.0的支持的,默认使用的时HTTP/1.1,需要手动开启才能使用HTTP/2.0

改写代码如下

import httpx
client = httpx.Client(http2=True)
url ='https://spa16.scrape.center/'
resp = client.get(url)
print(resp.text)

运行结果如下:

<!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请求来说,实现方式是类似的

import httpx
r = httpx.get('https://www.httpbin.org/get')
r = httpx.post('https://www.httpbin.org/post')
r = httpx.put('https://www.httpbin.org/put')
r = httpx.delete('https://www.httpbin.org/delete')

 基于得到的resp对象,可以使用如下属性和方法获得想要的内容。

status_code:状态码

text:响应体的文本内容

content:响应体的二进制内容如图片等。

header:响应头,是Headers对象,可以用像获取字典中的内容一样获取其中某个header的值

json:方法,可以调用此方法将文本转化为json对象。

 此外还有一些基本用法基本都与requests类似,具体可以参考官方文档

https://www.python-httpx.org/quickstart

 Client对象

上面说到httpx和requests对象有很多相似的部分,那么现在就来聊聊不同的部分,首先说到的就是Client对象,这个对象可以和requests中session对象类比学习。

下面我们就来介绍Client对象的使用,官方比较推荐的使用方式是with as语句,实例如下

import httpx
with httpx.Client() as client:
    resp=client.get('https://www.httpbin.org/get')
    print(resp)

运行结果:<Response [200 OK]>

 这个方法等价于

import httpx
client= httpx.Client()
try:
    resp=client.get('https://www.httpbin.org/get')
finally:
    
    print(resp)
    client.close()

 两种方法运行结果是一样的。只不过这里需要我们在最后显式地调用了close方法来关闭client对象。

另外,在声明Client对象时可以指定一些参数,例如headers,这样使用该对象发起的所有请求都会默认带上这些参数配置。

示例如下

import httpx
url = 'https://www.httpbin.org/headers'
headers={"User-Agent":"my-request/0.0.1"}
with httpx.Client(headers=headers)as client:
    r=client.get(url)
    print(r.json()['headers']['User-Agent'])

 这里我们声明了一个headers对象,内容为User-Agent属性,然后将此变量传递给headers参数初始化了一个Client对象,并赋值为client变量,最后用client变量请求了测试网站。并打印了返回结果中的User-Agent的内容:

my-request/0.0.1

可以看到成功赋值了

关于更多client对象的高级用法可以参考官网文档:https://www.python-httpx.org/advanced

 支持HTTP/2.0

现在是要在客户端开启对HTTP/2.0的支持,就像基本使用小节所说的那样,同样是声明Client对象,然后将http2的参数设置为True。如果不设置,那么请求就会默认支持HTTP/1.0,即不开启对HTTP/2.0的支持。写法如下

import httpx
client = httpx.Client(http2=True)
resp = client.get('https://www.httpbin.org/get')
print(resp.text)
print(resp.http_version)

这里我们在输出代码上加了一个http_version属性,这是requests库中不存在的属性,其结果可能为:HTTP/1.0,HTTP/1.1,HTTP/2.0

代码运行的返回结果为 HTTP/2.0,代表使用了HTTP/2.0协议传输。

注意。在客户端的httpx启用了对HTTP/2.0的支持并不意味着请求和响应都将通过HTTP/2.0传输,这里得客户端和服务端都支持HTTP/2.0才行。如果客户端连接到仅支持HTTP/1.1的服务器,那么它也需要改用HTTP/1.1

支持异步请求

httpx还支持异步客户端请求(即AsyncClient),支持Python的async的请求模式,写法如下:

import httpx
import asyncio
async def fetch(url):
    async with httpx.Client(http2=True) as client:
        resp=await client.get(url)
        print(resp.text)
if __name__ == "__main__":
    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,如果后面有需要requests爬取网页时,推荐大家使用httpx

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值