直接get(url)会返回521, 该网站采用了js加密反爬. 其实就是一个js逆向问题, 我们看到的是521, 实际上是进行了三次访问. 每次访问需要带上上一次的cookie.
- 先导入库和设置一个头部
import re
import execjs
import requests
import json
from requests.utils import add_dict_to_cookiejar
from requests.packages.urllib3.exceptions import InsecureRequestWarning
# 关闭ssl验证提示
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
header =
{
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0',
'Host' : 'www.mafengwo.cn'
}
- 进行第一次访问
session = requests.session() #使用session会一直携带上一次的cookies
url = 'https://www.mafengwo.cn/i/23463414.html'
response = session.get(url, headers=header, verify=False) #直接访问得到JS代码
js_clearance = re.findall('cookie=(.*?);location', response.text)[0] #用正则表达式匹配出需要的部分
#
result = execjs.eval(js_clearance).split(';')[0].split('=')[1] #反混淆、分割出cookie的部分
print(result)
结果为:
这就是第一次访问后得到的解析过的cookie.
- 进行第二次访问
add_dict_to_cookiejar(session.cookies, {'__jsl_clearance_s': result}) #将第一次访问的cookie添加进入session会话中
response = session.get(url, headers=header, verify=False) #带上更新后的cookie进行第二次访问
会得到以下内容:
内容很乱, 但是没关系, 用我们之前提到的JS美化小工具在线JS格式化. 将上述本文粘贴进这个工具进行格式化, 再拉到最后
可以看到这次访问有个go函数, 其中一个attrs为**“ha”**, 这是hash(哈希)加密算法的简称, 此次哈希算法函数为sha256, 实际上这类反爬虫只有三种算法函数 sha256、sha1、md5. 那么只需要根据此次访问的加密类型来反解cookie即可.
我们将go函数部分提取出来
go = json.loads(re.findall(r'};go\((.*?)\)</script>', response.text)[0])
结果:
根据算法规则反解cookie
for i in range(len(go['chars'])):
for j in range(len(go['chars'])):
values = go['bts'][0] + go['chars'][i] + go['chars'][j] + go['bts'][1]
if go['ha'] == 'md5':
ha = hashlib.md5(values.encode()).hexdigest()
elif go['ha'] == 'sha1':
ha = hashlib.sha1(values.encode()).hexdigest()
elif go['ha'] == 'sha256':
ha = hashlib.sha256(values.encode()).hexdigest()
if ha == go['ct']:
__jsl_clearance_s = values
原理是就是正确的cookie由go函数中的"bts", "chars"里的字符所组成, 但网页返回的是哈希值, 所以当我们确定好加密方式后, 只需要将所有组合的哈希值计算然后与正确的配对, 就能找到正确的cookie.
- 第三次访问
将第二次访问中哈希算法得到的cookie再一次添加到session会话中, 进行第三次访问
add_dict_to_cookiejar(session.cookies, {'__jsl_clearance_s' :__jsl_clearance_s})
response = session.get(url, headers=header, verify=False)
response.text
结果
就能够得到正确的页面信息了.
另一个思路: 将三种算法函数保存到本地, 判断出是哪种加密算法后, 将哈希值带入, 反解出cookie
import re
import execjs
import requests
import json
from requests.utils import add_dict_to_cookiejar
from requests.packages.urllib3.exceptions import InsecureRequestWarning
# 关闭ssl验证提示
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0',
}
url = 'https://www.mafengwo.cn/i/23463414.html'
# 使用session保持会话
session = requests.session()
def get_parameter(response):
# 提取js代码
js_clearance = re.findall('cookie=(.*?);location', response.text)[0]
# 执行后获得cookie参数js_clearance
result = execjs.eval(js_clearance).split(';')[0].split('=')[1]
# 添加cookie
add_dict_to_cookiejar(session.cookies, {'__jsl_clearance_s': result})
# 第二次请求
response = session.get(url, headers=header, verify=False)
# 提取参数并转字典
parameter = json.loads(re.findall(r';go\((.*?)\)', response.text)[0])
js_file = ''
# 判断加密方式
if parameter['ha'] == 'sha1':
js_file = 'sha1.js'
elif parameter['ha'] == 'sha256':
js_file = 'sha256.js'
elif parameter['ha'] == 'md5':
js_file = 'md5.js'
return parameter, js_file
def get_cookie(param, file):
with open(file, 'r') as f:
js = f.read()
cmp = execjs.compile(js)
# 执行js代码传入参数
clearance = cmp.call('go', param)
return clearance
def run():
# 第一次请求
response = session.get(url, headers=header, verify=False)
# 获取参数及加密方式
parameter, js_file = get_parameter(response)
# 获取cookie
clearance = get_cookie(parameter, js_file)
print(clearance)
# 修改cookie
add_dict_to_cookiejar(session.cookies, {'__jsl_clearance_s': clearance})
# 第三次请求
html = session.get(url, headers=header, verify=False)
#print(html.cookies)
#print(html.content.decode())
return html
page = run()
soup = BeautifulSoup(page.text, "html.parser")
soup
结果
也同样能获得正确的页面