当前位置: 首页 > news >正文

专业Python爬虫实战教程:逆向加密接口与验证码突破完整案例

案例背景

假设我们需要爬取一家内部测试系统的动态数据API接口。该系统前端页面使用了复杂的JavaScript混淆技术来防止接口被直接调用,同时对请求参数进行了加密签名。另外,登录环节带有图形验证码用于防护。我们的目标是:

  • 分析JavaScript代码,逆向加密签名算法。
  • 模拟登录过程,自动识别图形验证码并提交。
  • 构造正确请求参数,获取动态数据。
  • 完整实现Python爬虫,稳定批量抓取数据。

环境准备

  • Python 3.8+
  • 主要依赖库:
    • requests (HTTP请求)
    • execjs (调用JavaScript引擎)
    • Pillow & pytesseract(验证码图像处理与OCR)
    • jsbeautifier(JS格式化辅助阅读)
    • lxml(HTML解析)
    • selenium & webdriver-manager(动态交互及验证码抓取,可选)

Step 1:分析网页结构和JavaScript代码

模拟环境下,打开前端页面,按F12打开开发者工具:

  • 页面HTML框架简单,核心数据通过POST提交参数调用 /api/v1/getData 接口,返回JSON。
  • POST请求中的参数均为加密后的签名串,且请求头带有特殊字段 X-Custom-Token
  • 登录页带有断码的图形验证码,图片URL是 /captcha/image,验证码刷新时参数带时间戳。

1.1 网络数据初探

使用Chrome Network面板,关注XHR请求:

POST https://internal.test/api/v1/getData
Request Payload:
{"param": "EncryptedStringHere","sign": "GeneratedSignature"
}
Response:
{"code": 0,"data": [ ... ]
}

1.2 找到加密签名函数

通过Sources面板,加载执行的JS文件(例如main.min.js,经过混淆压缩),使用jsbeautifier进行格式化,定位请求相关代码片段。

逆向发现关键函数generateSign(params)

function generateSign(params) {var a = btoa(encodeURIComponent(JSON.stringify(params)));var b = someObfuscatedFunction(a);return md5(b + secretKey);
}

大致逻辑是:

  • 将参数JSON字符串化,编码成URI,再做Base64编码。
  • 经过部分混淆函数处理(someObfuscatedFunction)。
  • 最后加上固定密钥用MD5加密。

Step 2:JavaScript逆向与关键代码还原

2.1 还原混淆函数

原始混淆函数结构类似:

function someObfuscatedFunction(str) {var res = '';for (var i = 0; i < str.length; i++) {res += String.fromCharCode(str.charCodeAt(i) ^ 123); // 按位异或123}return res;
}

这是典型的异或加密,解密时再次异或同样的数字即可还原。

2.2 Python实现等效签名函数

利用Python的base64hashlib和自定义异或函数实现:

import base64
import hashlib
import urllib.parsesecret_key = 'FixedSecretKey123'  # 从JS中提取的密钥def xor_str(s, key=123):return ''.join(chr(ord(c) ^ key) for c in s)def generate_sign(params):# JSON序列化import jsonparam_str = json.dumps(params, separators=(',', ':'), ensure_ascii=False)# URI编码encoded = urllib.parse.quote(param_str)# Base64编码b64 = base64.b64encode(encoded.encode('utf-8')).decode('utf-8')# 异或处理xor_result = xor_str(b64)# 计算MD5签名sign_str = xor_result + secret_keymd5_hash = hashlib.md5(sign_str.encode('utf-8')).hexdigest()return md5_hash

Step 3:验证码识别技术

3.1 获取验证码图片

验证码在登录过程中返回,URL例子:

https://internal.test/captcha/image?_t=时间戳

3.2 图片预处理与OCR识别

验证码为简单断码数字。使用Pillow处理,pytesseract识别。

示例预处理代码:

from PIL import Image, ImageFilter
import pytesseract
import io
import requestsdef get_captcha(session):url = f'https://internal.test/captcha/image?_t={int(time.time()*1000)}'response = session.get(url)img = Image.open(io.BytesIO(response.content))# 灰度化img = img.convert('L')# 二值化img = img.point(lambda x: 0 if x < 140 else 255, '1')# 去噪img = img.filter(ImageFilter.MedianFilter())return imgdef recognize_captcha(img):text = pytesseract.image_to_string(img, config='--psm 7 digits')text = text.strip().replace(' ', '')return text

Step 4:登录流程模拟

登录时需提交用户名、密码、验证码。

def login(session, username, password):# 获取验证码并识别captcha_img = get_captcha(session)captcha_text = recognize_captcha(captcha_img)login_data = {'username': username,'password': password,'captcha': captcha_text,}response = session.post('https://internal.test/api/login', data=login_data)result = response.json()if result['code'] == 0:print('登录成功')else:print('登录失败:', result['msg'])raise Exception('登录失败')

Step 5:核心数据接口调用

构造请求参数,调用数据接口:

def fetch_data(session, params):sign = generate_sign(params)post_data = {'param': params,    # 通常是原始参数JSON对象,部分实现会转换为字符串,请按实际情况调整'sign': sign,}headers = {'X-Custom-Token': 'token-from-cookie-or-js', # 需要通过登录等动态获取'Content-Type': 'application/json',}resp = session.post('https://internal.test/api/v1/getData', json=post_data, headers=headers)data = resp.json()if data['code'] == 0:return data['data']else:raise Exception(f"接口调用失败: {data['msg']}")

Step 6:整体爬虫流程整合

import requests
import timedef main():session = requests.Session()# 登录login(session, 'test_user', 'test_password')# 伪装UA头session.headers.update({'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 \(KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'})# 请求示例参数params = {'type': 'recent', 'limit': 20, 'timestamp': int(time.time())}# 调用接口data = fetch_data(session, params)print('获取数据:', data)if __name__ == '__main__':main()

总结

本案例通过模拟环境设计,综合讲述了下一些高级Python爬虫技术:

  • JavaScript逆向:理解并还原混淆及加密算法核心。
  • 签名构造:使用Python重现JS签名逻辑,成功通过接口认证。
  • 图形验证码识别:图像预处理加OCR,自动突破登录验证。
  • 会话管理:使用requests.Session维护登录态。
  • 爬虫实战:整合流程实现自动登录、数据抓取的完整爬虫。
http://www.dtcms.com/a/303839.html

相关文章:

  • C 语言指针深度解析:从数组指针到指针函数的实战指南
  • 【21】C# 窗体应用WinForm ——图片框PictureBox属性、方法、实例应用
  • 重生之我在暑假学习微服务第四天《Docker-下篇》
  • Intellij Idea--解决Cannot download “https://start.spring.io‘: Connect timedout
  • React面试题目和答案大全
  • 队列算法之【用队列实现栈】
  • 系统重启过程和启动目标
  • Note3: CNN(卷积神经网络)
  • java每日精进 7.29【框架数据权限详解】
  • 远程Qt Creator中文输入解决方案
  • day064-kodbox接入对象存储与配置负载均衡
  • linux命令tail的实际应用
  • 网络数据传输与NAT技术的工作原理
  • 社区老人健康信息管理系统|基于springboot社区老人健康信息管理系统设计与实现(源码+数据库+文档)
  • SSO CAS+Shiro+springmvc单点登录解决方案
  • 符号计算与算法实践|使用Maple教授​​群论​​和​​图论​​课程
  • 【 MySQL集群架构与实践1】使用Docker实现简单主从复制
  • uni-app x开发避坑指南:拯救被卡顿的UI线程!
  • 【CF】Day114——杂题 (贪心 + 图论 | LCM + 贪心 | 最大最小子序列 + 图论)
  • 图论:Bellman_ford算法
  • docker设置iptables=false后容器内部无法互相访问
  • vue3组件通信的几种方法,详解
  • 工业补贴携手华为云,重塑汽车零部件供应链管理新趋势
  • B 站搜一搜关键词优化:精准触达用户的流量密码
  • 51c大模型~合集161
  • SQL注入SQLi-LABS 靶场less26-30详细通关攻略
  • Elasticsearch 深度分页问题与 `search_after` 解决方案
  • 从centos更换至ubuntu的安装、配置、操作记录
  • cpolar 内网穿透 ubuntu 使用石
  • 知识点梳理