Подтвердить что ты не робот

Парсер JavaScript в Python

Существует JavaScript-парсер, по крайней мере, на C и Java (Mozilla), в JavaScript (Mozilla снова) и Ruby. Есть ли в настоящее время для Python?

Мне не нужен интерпретатор JavaScript, как таковой, только парсер, соответствующий стандартам ECMA-262.

Быстрый поиск по Google не выявил немедленных ответов, поэтому я прошу сообщество SO.

4b9b3361

Ответ 1

ANTLR, еще один инструмент для распознавания языков - это инструмент языка, который обеспечивает основу для создания распознавателей, интерпретаторов, компиляторов и переводчики из грамматических описаний, содержащие действия на разных целевых языках.

ANTLR содержит много грамматик, в том числе one для JavaScript.

Как это происходит, существует Python API, поэтому вы можете вызывать лексер (распознаватель), сгенерированный из грамматики, непосредственно из Python (удачи).

Ответ 2

В настоящее время существует хотя бы один лучший инструмент, называемый slimit:

SlimIt - это JavaScript minifier, написанный на Python. Он компилирует JavaScript в более компактный код, чтобы он загружал и запускал быстрее.

SlimIt также предоставляет библиотеку, содержащую парсер JavaScript, лексер, красивый принтер и посетитель дерева.

Демо:

Представьте, что у нас есть следующий код javascript:

$.ajax({
    type: "POST",
    url: 'http://www.example.com',
    data: {
        email: '[email protected]',
        phone: '9999999999',
        name: 'XYZ'
    }
});

И теперь нам нужно получить значения email, phone и name от объекта data.

Идея здесь заключалась бы в создании экземпляра парсера slimit, посещении всех узлов, фильтрации всех назначений и перевода их в словарь:

from slimit import ast
from slimit.parser import Parser
from slimit.visitors import nodevisitor


data = """
$.ajax({
    type: "POST",
    url: 'http://www.example.com',
    data: {
        email: '[email protected]',
        phone: '9999999999',
        name: 'XYZ'
    }
});
"""

parser = Parser()
tree = parser.parse(data)
fields = {getattr(node.left, 'value', ''): getattr(node.right, 'value', '')
          for node in nodevisitor.visit(tree)
          if isinstance(node, ast.Assign)}

print fields

Он печатает:

{'name': "'XYZ'", 
 'url': "'http://www.example.com'", 
 'type': '"POST"', 
 'phone': "'9999999999'", 
 'data': '', 
 'email': "'[email protected]'"}

Ответ 3

Как упоминалось в pib, pynarcissus является токенизатором Javascript, написанным на Python. Кажется, что у него есть некоторые грубые грани, но до сих пор хорошо работает для того, чего я хочу достичь.

Обновлено: Взял еще одну трещину на pynarcissus, а ниже - рабочее направление для использования PyNarcissus в шаблоне посетителя, таком как система. К сожалению, мой текущий клиент купил следующую итерацию моих экспериментов и решил не делать это публичным источником. Более чистая версия приведенного ниже кода находится на gist здесь

from pynarcissus import jsparser
from collections import defaultdict

class Visitor(object):

    CHILD_ATTRS = ['thenPart', 'elsePart', 'expression', 'body', 'initializer']

def __init__(self, filepath):
    self.filepath = filepath
    #List of functions by line # and set of names
    self.functions = defaultdict(set)
    with open(filepath) as myFile:
        self.source = myFile.read()

    self.root = jsparser.parse(self.source, self.filepath)
    self.visit(self.root)


def look4Childen(self, node):
    for attr in self.CHILD_ATTRS:
        child = getattr(node, attr, None)
        if child:
            self.visit(child)

def visit_NOOP(self, node):
    pass

def visit_FUNCTION(self, node):
    # Named functions
    if node.type == "FUNCTION" and getattr(node, "name", None):
        print str(node.lineno) + " | function " + node.name + " | " + self.source[node.start:node.end]


def visit_IDENTIFIER(self, node):
    # Anonymous functions declared with var name = function() {};
    try:
        if node.type == "IDENTIFIER" and hasattr(node, "initializer") and node.initializer.type == "FUNCTION":
            print str(node.lineno) + " | function " + node.name + " | " + self.source[node.start:node.initializer.end]
    except Exception as e:
        pass

def visit_PROPERTY_INIT(self, node):

    # Anonymous functions declared as a property of an object
    try:
        if node.type == "PROPERTY_INIT" and node[1].type == "FUNCTION":
            print str(node.lineno) + " | function " + node[0].value + " | " + self.source[node.start:node[1].end]
    except Exception as e:
        pass


def visit(self, root):

    call = lambda n: getattr(self, "visit_%s" % n.type, self.visit_NOOP)(n)
    call(root)
    self.look4Childen(root)
    for node in root:
        self.visit(node)

filepath = r"C:\Users\dward\Dropbox\juggernaut2\juggernaut\parser\test\data\jasmine.js"
outerspace = Visitor(filepath)

Ответ 4

Я перевел esprima.js на Python:

https://github.com/PiotrDabkowski/pyjsparser

Это ручной перевод, поэтому он очень быстрый, занимает около 1 секунды для анализа angular.js файла (так 100 тыс. символов в секунду). Он поддерживает весь ECMAScript 5.1 и части версии 6 - например, функции Arrow, const, let.

В качестве альтернативы вы можете использовать автоматический перевод более новой версии esprima на python, который отлично работает и поддерживает весь JavaScript 6!

Ответ 5

Вы можете попробовать python-spidermonkey Это оболочка над spidermonkey, которая является кодовым именем для реализации javascript для Mozilla C.