什么是AST?AST有什么用?

AST 全称 Abstract Syntax Tree(语法抽象树),简称语法树。
对于爬虫来说,AST 是一种工具,尽可能的处理被混淆的代码,增强其可读性。
本人接触的是 babel ,故往后 AST 相关将默认基于其展开。

准备工作

  1. 一定的 js 基础,本人也是跟着这个教程学的,也时常翻阅(前往教程)
  2. 安装 nodejs 、babel nodejs 官网 babel 官网
    安装 babel 相关工具包时可以全局安装,这样方便调用
    npm install -g --save @babel/traverse

相关文档

必看!反复看!!很重要!!!

实用工具

  • AST explorer ,一个在线解析 AST 的网站。必备!!
    此时我们根据实际情况选择,JavaScript@babel/parser
    AST explorer 配置
    随着鼠标在左侧的点击或者在右侧的移动,网站会给我们高亮(标黄)提示相关代码的对应

  • 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 中的每个函数接收两个: pathstate(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

AST Babel 实战

推荐阅读