scrapelect 0.3.2

Interpreter for scrapelect, a CSS-inspired web scraping DSL
Documentation
import random

def scrapelect():
    return [[statement_list]]

def statement_list():
    return [[statement, statement_list]]

def statement():
    return [[randid(), ":", rvalue, filter_list, ";"]]

def rvalue():
    return [[element], [leaf]]

def element():
    return [[maybe_url, selector_list, selector_ops, "{", statement_list, "}"]]

def maybe_url():
    return [[variable], [randstr()]]

def selector_list():
    return [[selector, selector2]]

def selector():
    return [[".", randid()], ["#", randid()], [randid()], ["*"]]

def selector2():
    return [[selector_combinator, selector, selector2]]

def selector_combinator():
    # explicit whitespace here
    return [[x] for x in [" + ", " > ", " ~ ", ""]]

def selector_ops():
    return [["?"], ["[]"]]

def filter_list():
    return [["|", randid(), "(", arg_list, ")", filter_list]]

def arg_list():
    return [[randid(), ":", leaf, arg_list2]]

def arg_list2():
    return [[",", arg_list]]

def leaf():
    return [[variable], [randflt()], [randstr()], [randint()]]

def variable():
    return [["$", randid()]]

e = lambda: ""
def randid():
    return "".join(random.choice("abcdefghjiklmnopqrstuvwxyz") for _ in range(random.randint(1, 26)))

def randflt():
    return str((1 - random.random()) * 10000)

def randint():
    return str(random.randint(-10000, 10000))

def randstr():
    # doesn't test escaping or anything
    return f'"{randid()}"'

bases = {
    statement_list,
    maybe_url,
    selector2,
    selector_combinator,
    selector_ops,
    filter_list,
    arg_list,
    arg_list2
}

def fuzz(recurse_prob, f=scrapelect, a=None):
    if a is None: a = recurse_prob
    if f in bases:
        r = random.random()
        if r < 1 - recurse_prob:
            yield ""
            return

    rule = random.choice(f())
    for r in rule:
        if isinstance(r, str):
            yield r
        else:
            yield "".join(fuzz(recurse_prob * a, f=r))

if __name__ == '__main__':
    import sys
    r = float(sys.argv[1])
    for x in fuzz(r): print(x)