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

Python 爬虫反爬突破:动态脚本加载拦截与解析

前言

现代主流网站全面采用 Vue、React、Angular 等前端框架实现前后端分离,核心数据不再直埋页面源码,而是依托动态 JS 脚本异步渲染、路由懒加载、脚本分片加载、Webpack 代码打包、异步接口动态挂载等机制完成数据展示。传统爬虫直接请求页面源码只能获取空壳 HTML,无法抓取真实业务数据;加之网站对动态脚本实施混淆、加载拦截、接口隐藏、脚本按需下发等反爬策略,常规静态爬取、简单 AJAX 抓包的方式彻底失效。

本文聚焦动态脚本加载的底层机制、脚本拦截原理、分片脚本抓取、混淆 JS 解析、异步接口溯源、渲染式数据解析全流程技术,拆解静态源码解析、接口逆向抓包、无头浏览器渲染、脚本拦截劫持四大主流解析方案,配套标准化工程代码、原理深度剖析与落地优化方案。配套开发工具及依赖库官方超链接:Python 官方运行环境Requests 网络请求库Playwright 自动化渲染框架PyMiniRacer JS 解析引擎BeautifulSoup 网页解析库

本文所有技术内容仅限爬虫技术学习与合规授权数据采集,严格遵守目标站点 robots 协议及网络安全法规,禁止用于恶意爬取、商业盗用、接口批量爆破等违规行为。

一、动态脚本加载核心机制与反爬逻辑

1.1 动态脚本加载主流形式

表格

加载类型技术特征数据渲染方式爬虫爬取难点
异步 AJAX 加载页面加载后异步请求接口 JSON 数据JS 拼接 DOM 渲染页面接口加密、参数动态生成、接口地址隐藏
脚本分片懒加载页面拆分多个 chunk 分片 JS,滚动或触发事件后加载按需加载脚本再渲染数据脚本地址动态生成、无固定 JS 链接
Webpack 打包加载全站代码打包为单个或多个 bundle 脚本打包脚本内部请求数据并渲染脚本混淆、变量加密、接口地址隐藏在打包代码中
路由异步加载切换页面路由才加载对应业务脚本路由触发后下发脚本与数据无路由触发则无法加载核心数据脚本
Shadow DOM 隔离加载数据挂载在影子 DOM 内部,脱离常规 DOM 树影子内部渲染,外部无法直接获取常规解析器无法穿透 Shadow DOM 抓取内容

1.2 动态脚本对爬虫的核心拦截原理

  1. 源码空壳化:初始 HTML 仅包含根节点、框架入口脚本,无任何业务数据,静态爬取拿到空白源码;
  2. 脚本加载受控:通过前端逻辑控制脚本加载时机,未触发指定行为则不下发核心业务 JS;
  3. 脚本代码混淆:变量名混淆、函数扁平化、字符串加密、代码乱序,增加逆向解析难度;
  4. 接口动态隐藏:真实数据接口地址、请求参数、签名算法全部封装在动态脚本内部,不直接暴露在网络请求列表;
  5. 加载环境校验:检测浏览器环境、设备指纹、渲染特征,非真实浏览器环境直接终止脚本加载与数据请求。

二、开发环境与必备依赖库配置

解析动态脚本需要网络请求、页面解析、浏览器渲染、原生 JS 引擎解析等多类库支撑,适配 Python3.8 及以上版本。

2.1 依赖库批量安装命令

bash

运行

# 基础网络请求 pip install requests==2.31.0 # 网页HTML源码解析 pip install beautifulsoup4==4.12.3 # 无头浏览器动态渲染,解析JS加载内容 pip install playwright==1.40.0 # 原生JS引擎,脱离浏览器解析混淆脚本 pip install py-mini-racer==0.14.0 # 正则匹配、脚本内容提取 pip install re

2.2 Playwright 内核初始化

bash

运行

playwright install chromium

2.3 环境验证代码

python

运行

import requests from bs4 import BeautifulSoup from playwright.sync_api import sync_playwright import py_mini_racer def env_check(): print("动态脚本解析依赖库全部加载完成") test_req = requests.get("https://www.baidu.com",timeout=5) print("网络请求连通正常,状态码:",test_req.status_code) # 验证JS引擎 ctx = py_mini_racer.MiniRacer() res = ctx.eval("1+1") print("原生JS引擎运行测试结果:",res) if __name__ == "__main__": env_check()

运行无报错、输出正常数值,代表环境配置就绪。

三、传统静态爬虫失效原因深度剖析

3.1 仅能获取初始空 HTML

前后端分离架构下,服务器仅返回极简 HTML 框架,所有列表数据、详情内容、分类信息均由 JS 脚本异步请求后端接口后动态生成,requests 直接请求源码只能拿到结构标签,无真实文本与数据。

3.2 无法触发脚本懒加载逻辑

分片 JS、路由懒加载脚本需要页面滚动、点击切换、路由跳转等行为触发,静态请求不会执行前端交互逻辑,无法加载后续业务脚本,自然无法获取渲染后的数据。

3.3 无法执行 JS 渲染逻辑

Python 原生无浏览器 V8 引擎,不能解析、运行混淆打包后的 JS 代码,无法还原脚本内部的接口地址、加密参数、数据处理逻辑,只能被动看到空白页面。

四、方案一:源码脚本抓取 + 正则解析提取

适用于中小型站点、未做高强度混淆的动态脚本,通过抓取页面内嵌 JS、外部 JS 脚本,正则匹配提取接口地址、固定参数、明文数据。

4.1 实现流程

  1. 请求首页 HTML 源码;
  2. 正则提取页面内嵌 JS 与外部 JS 链接;
  3. 批量下载所有业务脚本文件;
  4. 通过正则表达式匹配接口 URL、密钥、固定参数;
  5. 构造请求直接调用接口获取 JSON 数据。

4.2 代码实战实现

python

运行

import requests import re from bs4 import BeautifulSoup class ScriptParseSpider: def __init__(self, url): self.url = url self.headers = { "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36" } def get_html(self): return requests.get(self.url,headers=self.headers,timeout=5).text def extract_script_url(self,html): # 提取所有外部JS脚本链接 soup = BeautifulSoup(html,"html.parser") script_list = soup.find_all("script",src=True) js_urls = [] for script in script_list: js_src = script.get("src") if js_src.startswith("http"): js_urls.append(js_src) return js_urls def match_api_from_script(self,js_content): # 正则匹配接口地址 pattern = re.compile(r'https?://.*?/api/.*?["\']',re.S) api_list = pattern.findall(js_content) # 去重清洗 api_list = list(set([item.strip('"\'') for item in api_list])) return api_list def run(self): html = self.get_html() js_urls = self.extract_script_url(html) print("提取到JS脚本数量:",len(js_urls)) # 遍历下载脚本并匹配接口 for js_url in js_urls: try: js_text = requests.get(js_url,headers=self.headers,timeout=5).text api_list = self.match_api_from_script(js_text) if api_list: print("从脚本提取接口地址:",api_list) except: continue if __name__ == "__main__": spider = ScriptParseSpider("目标网站首页地址") spider.run()

4.3 代码原理解析

  1. 借助 BeautifulSoup 解析 HTML,批量提取外部 JS 脚本链接;
  2. 循环下载每一个 JS 源码,利用正则匹配包含 /api 特征的业务接口;
  3. 自动去重清洗接口字符串,快速隐藏在脚本中的异步接口地址;
  4. 无需浏览器渲染,纯请求 + 正则即可完成轻量动态脚本解析,效率极高。

五、方案二:网络抓包拦截异步接口解析

适用于 JS 已混淆、接口隐藏较深的场景,通过拦截页面所有 XHR/Fetch 异步请求,直接抓取数据接口、请求方式与参数,绕过复杂 JS 逆向。

5.1 抓包拦截核心思路

  1. 启动浏览器并开启网络抓包监听;
  2. 访问目标页面,触发动态脚本加载与异步数据请求;
  3. 拦截所有 XHR、Fetch 类型请求,筛选业务数据接口;
  4. 记录接口请求方式、请求头、入参、加密规则;
  5. 复刻接口请求,直接获取 JSON 结构化数据。

5.2 Playwright 抓包拦截实战代码

python

运行

from playwright.sync_api import sync_playwright def intercept_xhr_api(url): api_data_list = [] with sync_playwright() as p: browser = p.chromium.launch(headless=False) context = browser.new_context() page = context.new_page() # 拦截网络请求 def handle_route(route): request = route.request # 筛选XHR和Fetch请求 if request.resource_type in ["xhr","fetch"]: if "/api/" in request.url: api_data_list.append({ "url":request.url, "method":request.method, "headers":request.headers, "post_data":request.post_data }) route.continue_() page.route("**/*",handle_route) page.goto(url,wait_until="networkidle") # 等待所有动态脚本加载完成 page.wait_for_timeout(3000) browser.close() return api_data_list if __name__ == "__main__": api_result = intercept_xhr_api("目标网站地址") for item in api_result: print("接口地址:",item["url"]) print("请求方式:",item["method"]) print("请求参数:",item["post_data"])

5.3 原理深度剖析

  1. 利用 Playwright 路由劫持能力,全局拦截所有网络请求;
  2. 过滤仅保留 XHR/Fetch 异步请求,筛选含 /api 业务特征的接口;
  3. 自动记录接口 URL、请求方法、请求头、POST 参数,完整复刻请求要素;
  4. 等待网络空闲状态,确保所有懒加载动态脚本与异步接口全部请求完毕,不漏抓接口。

六、方案三:无头浏览器全页面渲染解析

适用于 Shadow DOM 隔离、强 JS 渲染、无明确异步接口的场景,直接模拟真实浏览器执行所有动态脚本,渲染完整页面 DOM 后解析数据。

6.1 渲染解析适用场景

  • 数据完全由 JS 拼接生成,无独立异步接口;
  • Shadow DOM 影子 DOM 隔离,常规解析无法获取内容;
  • 脚本依赖页面滚动、点击等交互行为才能加载数据;
  • 前端路由跳转、懒加载分片脚本必须浏览器环境才能执行。

6.2 全页面渲染爬取代码

python

运行

from playwright.sync_api import sync_playwright from bs4 import BeautifulSoup import time def render_page_get_data(url): with sync_playwright() as p: browser = p.chromium.launch( headless=True, args=["--disable-blink-features=AutomationControlled"] ) context = browser.new_context( user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0 Safari/537.36" ) page = context.new_page() page.goto(url) # 模拟页面滚动触发懒加载脚本 page.evaluate("window.scrollTo(0,document.body.scrollHeight)") time.sleep(2) page.evaluate("window.scrollTo(0,0)") time.sleep(1) # 等待页面完全渲染 page.wait_for_load_state("networkidle") # 获取渲染完成后的完整HTML full_html = page.content() browser.close() # 解析渲染后页面数据 soup = BeautifulSoup(full_html,"html.parser") # 示例:提取列表标题,可自行修改选择器 title_list = soup.select("div.list-item h3") data = [title.get_text(strip=True) for title in title_list] return data if __name__ == "__main__": data = render_page_get_data("目标网站地址") for item in data: print("抓取数据:",item)

6.3 渲染解析原理

  1. 无头浏览器内置 V8 引擎,完整执行页面所有 JS、分片脚本、渲染逻辑;
  2. 模拟页面滚动行为,触发懒加载脚本与异步数据请求;
  3. 等待网络空闲确保所有动态资源加载完毕,获取最终完整渲染 HTML;
  4. 采用常规 BeautifulSoup 即可解析 DOM 内容,兼容 Shadow DOM 渲染后数据提取。

七、方案四:原生 JS 引擎解析混淆动态脚本

针对高强度混淆、Webpack 打包、禁止浏览器环境检测的脚本,脱离浏览器环境,使用 PyMiniRacer 独立 V8 引擎解析并执行 JS 代码,提取加密逻辑与数据。

7.1 核心实现代码

python

运行

import py_mini_racer import requests def parse_obfuscate_js(js_url): # 下载混淆JS脚本 headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0 Safari/537.36"} js_code = requests.get(js_url,headers=headers).text # 初始化独立V8引擎 ctx = py_mini_racer.MiniRacer() # 加载并执行混淆脚本 ctx.eval(js_code) # 调用脚本内部自定义函数,提取接口或加密参数 # res = ctx.eval("自定义函数()") # print("脚本执行结果:",res) print("混淆脚本加载执行完成") if __name__ == "__main__": parse_obfuscate_js("混淆JS脚本地址")

7.2 解析原理

  1. PyMiniRacer 内置独立 V8 引擎,与 Chrome 浏览器内核一致;
  2. 不依赖浏览器环境,规避前端对 webdriver、浏览器特征的检测拦截;
  3. 可独立执行混淆、打包、加密后的 JS 代码,手动调用内部函数还原加密参数与接口逻辑;
  4. 适合高防护动态脚本的离线逆向解析,不受页面环境限制。

八、动态脚本加载拦截综合规避优化技巧

8.1 脚本加载环境伪装

屏蔽自动化特征、轮换 UA、随机分辨率、禁用检测标识,避免前端识别爬虫环境而终止脚本加载。

8.2 懒加载触发策略

通过页面滚动、模拟点击、路由跳转、延时等待等方式,主动触发分片 JS、路由脚本、异步数据加载。

8.3 脚本缓存复用优化

对已下载的业务 JS、打包脚本进行本地缓存,重复爬取无需重新请求,提升解析效率。

8.4 异步并发脚本解析

结合 aiohttp 异步批量下载多个 JS 脚本,多线程正则匹配接口地址,大规模站点解析效率成倍提升。

九、常见问题排查

9.1 渲染后仍无数据

原因:未等待网络空闲、未触发滚动懒加载、脚本加载延时不足。解决:增加等待时间、模拟上下滚动、设置 networkidle 等待状态。

9.2 混淆脚本执行报错

原因:脚本依赖浏览器 window、document 对象。解决:手动模拟基础浏览器全局变量,补齐缺失依赖。

9.3 抓包拦截不到接口

原因:接口为 Fetch 异步延时请求、页面未完全加载。解决:延长等待时间、触发页面交互行为、全局路由拦截所有请求。

http://www.jsqmd.com/news/804695/

相关文章:

  • PTFE和PVDF过滤膜哪个性价比高?
  • 5分钟掌握Windows任务栏全能监控:TrafficMonitor插件终极指南
  • Zotero GPT插件:5步构建你的AI文献分析工作流
  • 揭示外周血单个核细胞中IFN-α信号通路
  • 继承虚函数
  • 日本电子产业转型启示:从技术过剩到商业模式创新
  • 宿主机切分“小鸡”全攻略:KVM、LXC、Docker到底怎么选?
  • Windows 10 PL2303驱动修复终极指南:3种方案解决串口设备兼容性问题
  • OpenClaw从入门到应用——工具(Tools):diff
  • FCC新规下电子产品入美测试合规指南:供应链安全与应对策略
  • 【力扣100题】22. 矩阵置零
  • 3分钟掌握Krita AI抠图:点一下就能完成的智能选区革命
  • 深入解析干扰素-γ(IFN-γ):宿主防御机制与治疗潜力新洞察
  • 拾亩绿光纯亚麻籽微粉效果怎么样
  • OpenClaw从入门到应用——工具(Tools):
  • 智飞生物:一家代理巨擘的百亿亏损与“只剩渣”的投资者残局
  • 【Google搜索增强黄金窗口期】:错过这波Gemini API权限开放,你将落后至少6个月开发节奏
  • FastGithub终极指南:5分钟让你的GitHub访问速度提升300%
  • 基于NestJS的智能代码评审代理:从AST解析到规则引擎实践
  • 【DeepSeek开发者垂直搜索实战指南】:3大行业落地案例+5个避坑要点,限时公开内部调优参数
  • 别再手动算脉冲了!STM32CubeMX配置定时器编码器模式,轻松读取直流电机转速(附防溢出处理代码)
  • 免费开源AI软件.桌面单机版,可移动的AI知识库,察元 AI桌面版:全模型支持的第一个例子 给察元AI挂上Ollama的下午
  • 如何在Windows电脑上安装安卓应用?APK Installer完整指南
  • 计算机毕业设计 | SpringBoot+vue高校教师电子名片系统(附源码+论文)
  • 厚街婚纱摄影哪家值得推荐:秒杀婚纱摄影全城优选 - 17322238651
  • ImageToSTL:让每一张照片都拥有立体的生命
  • 别再傻傻分不清了!一文搞懂L2范数、欧氏距离和正则化的前世今生
  • 厚街婚礼策划哪家值得推荐:秒杀婚礼策划梦幻缔造 - 13425704091
  • IGFBP-3:出生后血液中关键IGF结合蛋白的生物学功能与临床应用价值
  • 百度文库文档免费下载终极指南:3步快速获取纯净PDF