基于JWT的模拟登录爬取实战
本节中我们通过实例讲解基于 JWT 模拟登录并爬取数据的流程。
案例介绍
这里用到的案例网站是 https://login3.scrape.center/ ,访问这个网站,同样会打开一个登录页面,如图 10-4 所示。
图10-4 案例网站的登录页面
用户名和密码依然都是 admin,输入后点击登录按钮会跳转到首页,证明登录成功。
模拟登录
基于 JWT 的网站通常采用的是前后端分离式,前后端的数据传输依赖于 Ajax,登录验证依赖于 JWT 这个本身就是 token 的值,如果 JWT 经验证是有效的,服务器就会返回相应的数据。
和上一节一样,下面先打开开发者工具,重新执行登录操作,查看一下登录过程中产生的请求,如图 10-5 所示。
图10-5 登录过程中产生的请求
从图 10-5 可以看出,登录时的请求 URL 为 https://login3.scrape.center/api/login ,是通过 Ajax 请求的。请求体是 JSON 格式的数据,而不是表单数据,返回状态码为 200。然后看一下返回结果是怎样的,如图 10-6 所示。
图 10-6 返回结果
从图 10-6 可以看出,返回结果也是 JSON 格式的数据,包含一个 token 字段,其内容为:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwaXJlIjoxNjgxOTgtMDAzLCJlbWFpbCI6ImFkbWluQGZkbWlulumNvbSIsIm9yawdwYWxlIjoxNjI3OTQxODQ3fQ.YzOFwWhy_GwcmOnFXUTJAaqnBbJoj6hen751b82ds0j8
这和我们在 10.1 节讲过的一样,由 “.” 把整个字符串分为三段。那么有了这个 JWT 之后,怎么获取后续的数据呢?我们翻一下页,观察下后续的请求内容,如图 10-7 所示。
图10-7 翻页后的请求内容
从图 10-7 可以看出,在后续发出的用于获取数据的 Ajax 请求中,请求头里多了个 Authorization 字段,其内容为 jwt 加上刚才图 10-6 中 token 字段的内容,返回结果也是 JSON 格式的数据,如图 10-8 所示。
图10-8 返回结果
可以看出,返回结果正是网站首页显示的内容,这也是我们应该模拟爬取的内容。那么现在,模 拟登录的整个思路就变简单了,其实就是如下两个步骤:
-
模拟登录请求,带上必要的登录信息,获取返回的 JWT;
-
之后发送请求时,在请求头里面加上 Authorization 字段,值就是 JWT 对应的内容。
接下来我们用代码实现:
import requests
from urllib.parse import urljoin
BASE_URL = 'https://login3.scrape.center/'
LOGIN_URL = urljoin(BASE_URL, '/api/login')
INDEX_URL = urljoin(BASE_URL, '/api/book')
USERNAME = 'admin'
PASSWORD = 'admin'
response_login = requests.post(LOGIN_URL, json={
'username': USERNAME,
'password': PASSWORD
})
data = response_login.json()
print('Response JSON', data)
jwt = data.get('token')
print('JWT', jwt)
headers = {
'Authorization': f'jwt {jwt}'
}
response_index = requests.get(INDEX_URL, params={
'limit': 18,
'offset': 0
}, headers=headers)
print('Response Status', response_index.status_code)
print('Response URL', response_index.url)
print('Response Data', response_index.json())
这里我们同样先定义了登录接口和获取数据的接口,分别是 LOGIN_URL 和 INDEX_URL,接着调用 requests 的 post 方法进行模拟登录。由于这里提交的数据是 JSON 格式,所以使用 json 参数来传递。接着获取并打印出返回结果中包含的 JWT。之后构造请求头,设置 Authorization 字段并传入刚获取的 JWT,这样就能成功获取数据了。
运行结果如下:
Response JSON `{'token': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwaXJlIjoxNjgxOTQtMzAwLCJlbWFpbCI6ImFkbWluQGZkbWlulmNvbSIsIm9yawdwYWxlIjoxNjI3OTQxODQ3fQ.iUnuYhdi_A-Bupb2BLgCTUdxyHL6jgPhkBpozCPvm4'}`
JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwaXJlIjoxNjgxOTQtMzAwLCJlbWFpbCI6ImFkbWluQGZkbWlulmNvbSIsIm9yawdwYWxlIjoxNjI3OTQxODQ3fQ.iUnuYhdi\_A-Bupb2BLgCTUdxyHL6jgPhkBpozCPvm4
Response Status 200
Response URL [https://login3.scrape.center/api/book?limit=18\&offset=0](https://www.google.com/search?q=https://login3.scrape.center/api/book%3Flimit%3D18%26offset%3D0)
Response Data `{'count': 9200, 'results': [{'id': '27135877', 'name': '校园市场:布局未来消费群', 'authors': ['薛兆华', '李泽厚'], 'cover': 'https://img9.doubanio.com/view/subject/l/public/s29539805.jpg', 'score': '5.5'},`
`{'id': '30289316', 'name': '就算这样,还是喜欢你,草原先生', 'authors': ['おるおる'], 'cover': 'https://img3.doubanio.com/view/subject/l/public/s29875002.jpg', 'score': '7.5'}]}`
可以看到,这里成功输出了 JWT 的内容,同时获取了想要的数据,模拟登录成功!