接上文 JavaScript逆向爬取实战——使用Python实现列表页内容爬取(一)
3. 寻找列表页面的加密逻辑
根据上面的回溯查找,已经找到了token的位置了,可以观察这个token对应的变量,它叫做_0x263439,所以关键就是看看这个变量哪里来的。怎么找呢?添加断点就好了。
取消上面设置的断点,看一下这个变量是哪里生成的,如下图所示:
设置了新断点,刷新网页,发现网页停在新的断点上面,如下图所示:
这时我们就可以观察正在运行的一些变量了,比如把鼠标放在各个变量上,可以看到变量的值和类型;把鼠标放在变量_0x2fa7bd上,会有一个浮窗显示,如下图所示:
另外,还可以在右侧的Watch面板中添加想要查看的变量,如这行代码的内容为:
, _0x263439 =Object(_0x2fa7bd['a'])(this['$store']['state']['url']['index']);
我们比较感兴趣的可能就是_0x51c425,还有this里的$store属性。展开Watch面板,然后点击+号,把想看的变量添加到Watch面板里面,如下图所示:
可以发现,_0x2fa7bd是一个对象,它具有属性a,其值是一个方法。this[‘$store’][‘state’][‘url’][‘index’]的值其实就是/api/movie,即Ajax请求URL的Path。_0x263439就是调用前者的方法传入/api/movie得到的。如下图所示:
下一步就是去寻找这个方法。我们可以把Watch面板的_0x2fa7bd展开,这里会显示的FunctionLocation就是这个函数的代码位置,如下图所示:
点击进入,这时我们就进入一个新的名字为_0x456254的方法里,在这个方法中,应该就有token的生成逻辑了。添加断点,然后点击面板右上角蓝色箭头状的Resume script execution按钮,如下图所示:
接下来,不断进行单步调试,观察这里的执行逻辑和每一步调试的结果都有啥变化,如下图所示:
根据上面的单步调试,在Watch面板下看到每步具体结果,总结出这个token的构造逻辑,如下:
- 传入的/api/movie会构造一个初始化列表,将变量命名_0x31a891
- 获取当前的时间戳,命名为_0x5da681,调用push方法将其添加到_0x31a891变量代表的列表中
- 将_0x31a891变量用,拼接,然后进行SHA1编码,命名为_0xf7c3c7
- 将_0xf7c3c7(SHA1编码的结果)和_0x5da681(时间戳)用逗号拼接,命名为_0x3c8435
- 将_0x3c8435进行Base64编码,命名为_0x104b5b,得到最后的token
4. 使用Python实现列表页的爬取
实现这个逻辑,需要借助两个库:一个是hashlib,它提供了sha1方法;另外一个是base64库,它提供了b64encode方法对结果进行Base64编码。实现代码如下:
import hashlib
import time
import base64
from typing import List, Any
import requests
INDEX_URL = 'https://spa6.scrape.center/api/movie?limit={limit}&offset={offset}&token={token}'
LIMIT = 10
OFFSET = 0
def get_token(args: List[Any]):
timestamp = str(int(time.time()))
args.append(timestamp)
sign = hashlib.sha1(','.join(args).encode('utf-8')).hexdigest()
return base64.b64encode(','.join([sign, timestamp]).encode('utf-8')).decode('utf-8')
args = ['/api/movie']
token = get_token(args=args)
index_url = INDEX_URL.format(limit=LIMIT, offset=OFFSET, token=token)
response = requests.get(index_url)
print('response', response.json())
根据上面的逻辑加密流程实现出来了,这里先模拟爬取了第一页的内容,最后运行一下,可以得到最终的输出结果了。如下所示:
/usr/bin/python3 /Users/bruce_liu/PycharmProjects/崔庆才--爬虫/第11章JavaScript逆向爬虫/python爬取列表页.py
response {
'count': 102, 'results': [{
'id': 1, 'name': '霸王别姬', 'alias': 'Farewell My Concubine', 'cover': 'https://p0.meituan.net/movie/ce4da3e03e655b5b88ed31b5cd7896cf62472.jpg@464w_644h_1e_1c', 'categories': ['剧情', '爱情'], 'published_at': '1993-07-26', 'minute': 171, 'score': 9.5, 'regions': ['中国内地', '中国香港']}, {
'id': 2, 'name': '这个杀手不太冷', 'alias': 'Léon', 'cover': 'https://p1.meituan.net/movie/6bea9af4524dfbd0b668eaa7e187c3df767253.jpg@464w_644h_1e_1c', 'categories': ['剧情', '动作', '犯罪'], 'published_at': '1994-09-14', 'minute': 110, 'score': 9.5, 'regions': ['法国']}, {
'id': 3, 'name': '肖申克的救赎', 'alias': 'The Shawshank Redemption', 'cover': 'https://p0.meituan.net/movie/283292171619cdfd5b240c8fd093f1eb255670.jpg@464w_644h_1e_1c', 'categories': ['剧情', '犯罪'], 'published_at': '1994-09-10', 'minute': 142, 'score': 9.5, 'regions': ['美国']}, {
'id': 4, 'name': '泰坦尼克号', 'alias': 'Titanic',
.....
.....