Babel AST 入门
什么是AST?AST有什么用?
AST 全称 Abstract Syntax Tree(语法抽象树),简称语法树。
对于爬虫来说,AST 是一种工具,尽可能的处理被混淆的代码,增强其可读性。
本人接触的是 babel ,故往后 AST 相关将默认基于其展开。
准备工作
- 一定的 js 基础,本人也是跟着这个教程学的,也时常翻阅(前往教程)
- 安装 nodejs 、babel nodejs 官网 babel 官网
安装 babel 相关工具包时可以全局安装,这样方便调用
如npm install -g --save @babel/traverse
相关文档
必看!反复看!!很重要!!!
- babel github地址
- babel 手册(可以优先看快速入门)
实用工具
-
AST explorer ,一个在线解析 AST 的网站。必备!!
此时我们根据实际情况选择,JavaScript
和@babel/parser
随着鼠标在左侧的点击或者在右侧的移动,网站会给我们高亮(标黄)提示相关代码的对应 - AST explorer 国内镜像
- ob 混淆工具官网,可以用它的 demo 检测下自己的 AST 水准,顺带了解下 ob 混淆后的代码特征
- 猿人学爬虫工具合集
babel 的处理步骤、思路
babel 的三个主要处理步骤分别是: 解析(parse),转换(transform),生成(generate)。点击查看详情
个人认为,使用 babel 的处理思路其实就是增删改查节点。
譬如
- 删除多余空行、空语句、未被使用的函数和变量等
- 对于编码的变量替换为转换后结果,对于纯函数及其传入的固定参数直接替换为值等
- …
操作节点的核心思想其实就是把你需要处理的代码和你希望处理成的样子放到在线解析网站 AST explorer ,对比差异即可
处理代码时建议一步步将代码拆分,逐个操作,简单易懂
关于处理前后 js 代码节点的不同,参照 @babel/types 即可
AST babel 处理模板
执行命令为:node decrypt.js encode.js decode.js
decrypt.js:babel 处理、解密的 js
encode.js:待处理 js (可以使用绝对路径)
encode.js:处理后 js (可以使用绝对路径)
visitor 中的每个函数接收两个: path 和 state(state少用)
// decrypt.js
const fs = require('fs');
var util = require('util');
const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const types = require('@babel/types');
const generator = require('@babel/generator').default;
// 程序启动时间
var time_start = new Date().getTime()
// 读取文件
process.argv.length > 2 ? encode_file = process.argv[2] : encode_file = 'encode.js';
process.argv.length > 3 ? decode_file = process.argv[3] : decode_file = 'decode.js';
let jscode = fs.readFileSync(encode_file, {encoding: 'utf-8'});
// 转换为 ast 树
let ast = parser.parse(jscode);
const visitor =
{
// 此处编写 babel 处理代码、插件代码
ASTNodeTypeHere(path, state) {
}
// 如
// Identifier(path, state) {}
// Identifier(path) {}
}
//调用插件,处理待处理 js ast 树
traverse(ast, visitor);
console.log('AST traverse completed.')
// 生成处理后的 js
let {code} = generator(ast);
console.log('AST generator completed.')
fs.writeFile(decode_file, code, (err) => {
});
console.log(util.format('The javascript code in [%s] has been processed.', encode_file))
console.log(util.format('The processing result has been saved to [%s].', decode_file))
// 程序结束时间
var time_end = new Date().getTime()
console.log(util.format('The program runs to completion, time-consuming: %s s', (time_end - time_start) / 1000))
AST Babel demo
- 第一个 babel 插件, babel 初体验
- Babel 删除未被使用的 function 和由 var,let,const 定义的未使用变量
- Babel 还原不直观的编码字符串或数值
- Babel 将逗号表达式还原为多个语句
- Babel 还原由 var,let,const 定义的未变更的字面量
- Babel 去控制流平坦化之while-switch
- Babel 去控制流平坦化之for-switch
- Babel 将 a[‘bb’] 转换为 a.bb
- Babel 处理没有参数的自执行函数
- Babel 替换条件确定的if判断或条件表达式代码
- Babel 在参数全为字面量的纯函数调用处替换为其返回值
- …