鸣蜩十四 发表于 2021-11-8 16:58

【原创源码】【Python】爬虫学习-Scrape Center闯关(spa4,spa5,spa6)

# 场景
这次记录的是spa系列的4-6个,分别对应的技巧是智能分析,有翻页批量抓取,js逆向分析

# 关卡

## spa4
新闻网站索引,无反爬,数据通过 Ajax 加载,无页码翻页,适合 Ajax 分析和动态页面渲染抓取以及智能页面提取分析。

智能解析的知识点详情:[智能解析详解](https://blog.csdn.net/qq_37275405/article/details/103225099?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link)
我在本次实验中使用的是newspaper库:(https://zhuanlan.zhihu.com/p/101679529)
使用智能解析方便快捷,结果的话抓取十个链接,可能出错的有2-3个,还可以接受的
![在这里插入图片描述](https://img-blog.csdnimg.cn/8943ba30a4b84b05bceccc726890a5de.png)

总代码:
```
import json
import pandas as pd
import requests
import urllib3
from newspaper import Article

urllib3.disable_warnings()#去除因为网页没有ssl证书出现的警告
title,url,authors,published = [],[],[],[]
headers ={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                         'Chrome/87.0.4280.141 Safari/537.36'}

the_url = 'https://spa4.scrape.center/api/news/?limit=10&offset=0'
response=requests.get(the_url,headers=headers,verify=False)
data = json.loads(response.text)
for i in range(0,10):
    url.append(data['results']['url'])
    news = Article(url,language='zh')
    news.download()#加载网页
    news.parse()   # 解析网页
    title.append(news.title)
    authors.append(news.authors)
    published.append(news.publish_date)

bt = {
    "链接":url,
    "标题":title,
    "作者":authors,
    "发布时间":published
}
work = pd.DataFrame(bt)
work.to_csv('work.csv')
```

## spa5
图书网站,无反爬,数据通过 Ajax 加载,有翻页,适合大批量动态页面渲染抓取。

最后结果抓取:
![在这里插入图片描述](https://img-blog.csdnimg.cn/e69d598ead464215a3080b023af7ef29.png)


```
import json
import pandas as pd
import requests
import urllib3

name,authors,url,content,theme,id=[],[],[],[],[],[]
headers ={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                         'Chrome/87.0.4280.141 Safari/537.36'}
urllib3.disable_warnings()#去除因为网页没有ssl证书出现的警告
the_url = 'https://spa5.scrape.center/api/book/?limit=10&offset=0'
response=requests.get(the_url,headers=headers,verify=False)
data = json.loads(response.text)
for i in range(0,10):
    id.append(data['results']['id'])
    name.append(data['results']['name'])
    authors.append(str(data['results']['authors']).replace('[','').replace("\\n","").replace("'","").replace(']','').strip())
for a in id:
    the_url = 'https://spa5.scrape.center/api/book/'+a+'/'
    response=requests.get(the_url,headers=headers,verify=False)
    data = json.loads(response.text)
    url.append(data['url'])
    theme.append(str(data['tags']).replace('[','').replace("'","").replace(']','').strip())

bt= {
    "链接":url,
    "书名":name,
    "作者":authors,
    "主题":theme,
}
work = pd.DataFrame(bt)
work.to_csv('work.csv')


```

## spa6
电影数据网站,数据通过 Ajax 加载,数据接口参数加密且有时间限制,源码经过混淆,适合 JavaScript 逆向分析。

### 分析网站主页token产生的js
先进行分析,在开始的地方和我前面的文章spa2一样,可以参考一下
(https://www.52pojie.cn/thread-1539359-1-1.html)
这就是token加密的代码块
![在这里插入图片描述](https://img-blog.csdnimg.cn/73868dfc46f0462296bd3e8aa053a578.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/d883383434d746b5b66be81275dbc66a.png)

我们可以看到先sha1加密这样的一组数据

![在这里插入图片描述](https://img-blog.csdnimg.cn/02d7006fcebb47e4a63d2cbf2cdb22fd.png)
然后将经过SHA1加密的字符串继续与时间戳结合进行encode加密,对encode加密进行分析
![在这里插入图片描述](https://img-blog.csdnimg.cn/899e32a8d36e4f1cbc74fabad76eb2ff.png)
追溯到这一步,整了大半天,原来
![在这里插入图片描述](https://img-blog.csdnimg.cn/53a425668e0d45fea4c0edee6e064cbc.png)
找了半天发现没直接使用base64的加密
这样,token的加密方式就已经解出来了,步骤为:

o=sha1(url,时间戳)=>c=Base64(o,时间戳)=> token=c

转换为代码为:
SHA1加密
```
t = int(time.time())   #获取10位整数的时间戳
    s1 = f'/api/movie,{t}'
    o = hashlib.sha1(s1.encode('utf-8')).hexdigest()   #进行SHA1加密
```
Base64加密:
```
str_str = str(f"{o},{t}")
    bytesStr = str_str.encode(encoding='utf-8')
    b64str = base64.b64encode(bytesStr)   #最后的base64加密
    b64str = b64str.decode('utf-8')   # 将字节转换为str
```
b64str就是最后的token的值了,在这个过程中需要注意的是两次加密,共用的是同一个时间戳,并不是一次加密获取一个

### 分析网站电影详情页的url中的加密
和前面的一样,先进行分析,在开始的地方和我前面的文章spa2一样,可以参考一下
(https://blog.csdn.net/Destiny_one/article/details/121136061)

找到代码块,然后单步进入
![在这里插入图片描述](https://img-blog.csdnimg.cn/ae55a4d6db034c6883fc754e2eb8ccf2.png)
找到熟悉的代码块,这就是刚才分析的token的产生方式,所以我们发现这两个是一样的
![在这里插入图片描述](https://img-blog.csdnimg.cn/c166f838f8064ae4b68a61c9ae80acf4.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/f95679704d2649eab7688add1819fbb7.png)
就这一步的url需要加上生成加密字符串再加密,下来的基本都和上面的一样了

然后分析前面的加密字符串
![在这里插入图片描述](https://img-blog.csdnimg.cn/cf2adf98b7d54a058c09738c9e03e181.png)
可以发现在token产生之前,这串字符串就已经产生,指向的是一个key的值,我们直接全局搜索key值
找到key产生的代码块
![在这里插入图片描述](https://img-blog.csdnimg.cn/6c0c731766f847e3ae0b1c10d7111e64.png)
单步调试,熟悉的代码块,和spa3中一样的写死的一串字符经过加密转换后产生
![在这里插入图片描述](https://img-blog.csdnimg.cn/0be0b0db3efa47ec91110fb8517835e7.png)
经过分析是将下图中这个字符串同样经过encode加密,也就是上面分析得base64加密
![在这里插入图片描述](https://img-blog.csdnimg.cn/10e69685e08047e5943a7dd4b078ce8e.png)
所以加密的方式为:
Base64(ef34#teuq0btua#(-57w1q5o5–j@98xygimlyfxs*-!i-0-mb+第几部电影的数值)

这部分代码的加密和上面的类似,就不再单独写
最后,所有的加密方式以及对应的代码都已经分析好了

```
import base64
import json
import time
import urllib3
import requests
import pandas as pd
import hashlib

urllib3.disable_warnings()#去除因为网页没有ssl证书出现的警告
url,title,theme,score,content = [],[],[],[],[]
headers ={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                         'Chrome/87.0.4280.141 Safari/537.36'}
global url_list,title_list,theme_list,score_list,content_list,t

def token1():
    t = int(time.time())# 获取10位整数的时间戳
    s1 = f'/api/movie,{t}'
    o = hashlib.sha1(s1.encode('utf-8')).hexdigest()   #进行SHA1加密
    str_str = str(f"{o},{t}")
    bytesStr = str_str.encode(encoding='utf-8')
    b64str = base64.b64encode(bytesStr)   #最后的base64加密
    b64str_all = b64str.decode('utf-8')   # 将字节转换为str
    return b64str_all

def token2():
    a = 'ef34#teuq0btua#(-57w1q5o5--j@98xygimlyfxs*-!i-0-mb' + str(y)
    bytesStr = a.encode(encoding='utf-8')
    b64str = base64.b64encode(bytesStr).decode('utf-8')
    return b64str
def decode2(b64str):
    t = int(time.time())# 获取10位整数的时间戳
    s1 = f'/api/movie/{b64str},{t}'
    o = hashlib.sha1(s1.encode('utf-8')).hexdigest()# 进行SHA1加密
    str_str =(f"{o},{t}")
    bytesStr = str_str.encode(encoding='utf-8')
    b64str = base64.b64encode(bytesStr)# 最后的base64加密
    b64str_all = b64str.decode('utf-8')# 将字节转换为str
    return b64str_all

for i in range(0,10):
    the_url = "https://spa6.scrape.center/api/movie/?limit=10&offset="+str(i*10)+"&token="+token1()
    index=requests.get(the_url,headers=headers,verify=False)
    dict_data = json.loads(index.text)    #将响应的内容转化为json
    for x in range(0,10):
      title.append(dict_data['results']['name']+dict_data['results']['alias'])
      theme.append(str(dict_data['results']['categories']).replace('[','').replace(']','').replace("'",''))
      score.append(dict_data['results']['score'])
    for y in range(i*10+1,i*10+11):
      the_url = "https://spa6.scrape.center/api/movie/" + token2() + '/?token=' + decode2(token2())
      response = requests.get(the_url, headers=headers, verify=False)
      dict_data_1 = json.loads(response.text)
      content.append(dict_data_1['drama'])


bt = {
    '标题':title,
    '主题':theme,
    '评分':score,
    '剧情介绍':content
}
work = pd.DataFrame(bt)
work.to_csv('work.csv')

```

狐白本白 发表于 2021-11-8 17:11

可以可以,我要学习一下,多谢分享

一位变态的自述 发表于 2021-11-8 17:12

我要是也会就好了

阳光肥肥 发表于 2021-11-8 19:42

虽然顶着混淆也可以搞
不过反混淆一下看起来能省力很多,不然跳来跳去一会儿就容易忘了

lei122756700 发表于 2021-11-9 12:00

借鉴学习,谢谢分享
页: [1]
查看完整版本: 【原创源码】【Python】爬虫学习-Scrape Center闯关(spa4,spa5,spa6)