Javascript uitvoeren vanuit Python

Ik heb HTML-webpagina’s die ik crawl met xpath. De etree.tostringvan een bepaald knooppunt geeft me deze string:

<script>
<!--
function escramble_758(){
  var a,b,c
  a='+1 '
  b='84-'
  a+='425-'
  b+='7450'
  c='9'
  document.write(a+c+b)
}
escramble_758()
//-->
</script>

Ik heb alleen de uitvoer van escramble_758()nodig. Ik kan een regex schrijven om het hele ding te achterhalen, maar ik wil dat mijn code netjes blijft. Wat is het beste alternatief?

Ik blader door de volgende bibliotheken, maar ik heb geen exacte oplossing gezien. De meesten van hen proberen de browser na te bootsen, waardoor de boel traag wordt.

Bewerken: Een voorbeeld is geweldig.. (barebones zijn voldoende)


Antwoord 1, autoriteit 100%

Je kunt ook Js2Py gebruiken, dat is geschreven in pure python en in staat is om zowel javascript uit te voeren als te vertalen naar python. Ondersteunt vrijwel hele JavaScript, zelfs labels, getters, setters en andere zelden gebruikte functies.

import js2py
js = """
function escramble_758(){
var a,b,c
a='+1 '
b='84-'
a+='425-'
b+='7450'
c='9'
document.write(a+c+b)
}
escramble_758()
""".replace("document.write", "return ")
result = js2py.eval_js(js)  # executing JavaScript and converting the result to python string 

Voordelen van Js2Py zijn onder meer draagbaarheid en extreem gemakkelijke integratie met python (aangezien JavaScript in feite wordt vertaald naar python).

Installeren:

pip install js2py

Antwoord 2, autoriteit 86%

Met PyV8kan ik dit doen. Ik moet echter document.writevervangen door returnomdat er geen DOM is en dus ook geen document.

import PyV8
ctx = PyV8.JSContext()
ctx.enter()
js = """
function escramble_758(){
var a,b,c
a='+1 '
b='84-'
a+='425-'
b+='7450'
c='9'
document.write(a+c+b)
}
escramble_758()
"""
print ctx.eval(js.replace("document.write", "return "))

Of u kunt een nepdocumentobject maken

class MockDocument(object):
    def __init__(self):
        self.value = ''
    def write(self, *args):
        self.value += ''.join(str(i) for i in args)
class Global(PyV8.JSClass):
    def __init__(self):
        self.document = MockDocument()
scope = Global()
ctx = PyV8.JSContext(scope)
ctx.enter()
ctx.eval(js)
print scope.document.value

Antwoord 3, autoriteit 40%

Nog een oplossing aangezien PyV8 niet onderhouden lijkt te zijn en afhankelijk is van de oude versie van libv8.

PyMiniRacerHet is een wrapper rond de v8-engine en het werkt met de nieuwe versie en wordt actief onderhouden.

pip install py-mini-racer

from py_mini_racer import py_mini_racer
ctx = py_mini_racer.MiniRacer()
ctx.eval("""
function escramble_758(){
    var a,b,c
    a='+1 '
    b='84-'
    a+='425-'
    b+='7450'
    c='9'
    return a+c+b;
}
""")
ctx.call("escramble_758")

En ja, je moet document.writevervangen door returnzoals anderen suggereerden


Antwoord 4, autoriteit 7%

Je kunt js2py-context gebruiken om je js-code uit te voeren en uitvoer te krijgen van document.write met een nepdocumentobject:

import js2py
js = """
var output;
document = {
    write: function(value){
        output = value;
    }
}
""" + your_script
context = js2py.EvalJs()
context.execute(js)
print(context.output)

Antwoord 5, autoriteit 7%

Je kunt requests-htmlgebruiken die chroom eronder zal downloaden en gebruiken.

from requests_html import HTML
html = HTML(html="<a href='http://www.example.com/'>")
script = """
function escramble_758(){
    var a,b,c
    a='+1 '
    b='84-'
    a+='425-'
    b+='7450'
    c='9'
    return a+c+b;
}
"""
val = html.render(script=script, reload=False)
print(val)
# +1 425-984-7450

Meer hierover lees hier


Antwoord 6, autoriteit 3%

quickjs zou de beste optie moeten zijn nadat quickjs uit is gekomen. Gewoon pip install quickjsen je bent klaar om te gaan.

wijzig op basis van het voorbeeld op README.

from quickjs import Function
js = """
function escramble_758(){
var a,b,c
a='+1 '
b='84-'
a+='425-'
b+='7450'
c='9'
document.write(a+c+b)
escramble_758()
}
"""
escramble_758 = Function('escramble_758', js.replace("document.write", "return "))
print(escramble_758())

https://github.com/PetterS/quickjs

Other episodes