从JavaScript代码调用Python函数

121

我想从JavaScript代码中调用一个Python函数,因为在JavaScript中没有其他方法可以做到我想要的。这种情况可能吗?你能否修改下面的片段使其工作吗?

JavaScript代码:

var tag = document.getElementsByTagName("p")[0];
text = tag.innerHTML;
// Here I would like to call the Python interpreter with Python function
arrOfStrings = openSomehowPythonInterpreter("~/pythoncode.py", "processParagraph(text)");

~/pythoncode.py 包含使用高级库编写的函数,这些库在JavaScript中没有容易编写的等效物:

import nltk # is not in JavaScript
def processParagraph(text):
  ...
  nltk calls
  ...
  return lst # returns a list of strings (will be converted to JavaScript array)

15
不,浏览器(幸运的是)不会执行任意的Python代码。你需要在服务器上运行它。 - Fred Foo
2
Javascript 运行在客户端。我猜 Python 运行在服务器上。你可以向服务器发送 Ajax 请求。但速度可能不会很快。 - John Dvorak
2
使用ajax将文本发送到您服务器上的Python脚本。设置脚本以使用易于解析(对于js)的符号(如JSON)返回数据,并将结果分配给成功处理程序中的arrOfStrings。 - Asad Saeeduddin
10
你可以通过使用clang和Emscripten编译官方的Python解释器在浏览器中运行。之前已经有人成功实现过。 - user142019
2
@FredFoo,实际上幸运的是浏览器不运行ECMAScript(由于相当可疑的历史原因被称为JavaScript)。同样幸运的是,如果浏览器从90年代开始就运行Python的安全子集(这是任何人在浏览器中运行任何东西的意思,尽管你的草人论点并非如此),那么我们就不必处理当前的网络混乱了。 - SO_fix_the_vote_sorting_bug
显示剩余3条评论
7个回答

74

您只需要对您的Python代码进行Ajax请求。您可以使用jQuery http://api.jquery.com/jQuery.ajax/,或者仅使用JavaScript实现。

$.ajax({
  type: "POST",
  url: "~/pythoncode.py",
  data: { param: text}
}).done(function( o ) {
   // do something
});

2
我在Firebug中运行这个代码,但是它记录了[] - xralf
2
好的,那么这样就对了吗?我的Python文件包含了正确的函数。我应该在Python中调用这个函数,参数将是sys.argv[1]吗? - xralf
1
能否详细说明一下?通过ajax post调用python函数时,它是否会调用__ main __方法?因为main不能返回字符串。我们能否期望得到任何返回值?数据属性是否对应于python中的**kwargs字典,因此我们必须有一个接受它的方法?否则,我们如何指定python模块中的函数? - NuclearPeon
10
谢谢你的回答,但为了使Python脚本执行,必须通过支持CGI或WSGI的Web服务器进行部署。能否在您的回答中说明如何解决这个问题? - Matteo
6
如果我知道如何编辑您的答案,我很乐意为您编辑并改善其易懂性。但是,我不知道如何进行编辑,我希望您能提供一些建议,因为我遇到了这个错误XMLHttpRequest cannot load file:~/pythoncode.py. Cross origin requests are only supported for protocol schemes: http, data, chrome-extension, https, chrome-extension-resource,尽管我理解了问题所在,但不知道如何解决。有什么有用的提示吗?非常感谢。(顺便说一句...chessheaven看起来真的很棒!我肯定会试试,你的个人资料图片里的可爱女孩很讨人喜欢 ;)) - Matteo
显示剩余2条评论

32

根据document.getElementsByTagName,我猜测你在浏览器中运行JavaScript。

向浏览器中运行的JavaScript公开功能的传统方式是使用AJAX调用远程URL。 AJAX中的X代表XML,但现在每个人都使用JSON而不是XML。

例如,使用jQuery,您可以这样做:

$.getJSON('http://example.com/your/webservice?param1=x&param2=y', 
    function(data, textStatus, jqXHR) {
        alert(data);
    }
)

您需要在服务器端实现一个Python Web服务。对于简单的Web服务,我喜欢使用Flask

典型的实现如下:

@app.route("/your/webservice")
def my_webservice():
    return jsonify(result=some_function(**request.args)) 

你可以使用Silverlight在浏览器中运行IronPython(一种Python.Net),但我不知道NLTK是否可用于IronPython。


17

通过进程进行通信

示例:

Python: 这个 Python 代码块应该返回随机温度。

# sensor.py

import random, time
while True:
    time.sleep(random.random() * 5)  # wait 0 to 5 seconds
    temperature = (random.random() * 20) - 5  # -5 to 15
    print(temperature, flush=True, end='')

Javascript(Nodejs):在这里,我们将需要生成一个新的子进程来运行我们的Python代码,然后获取打印输出。

// temperature-listener.js

const { spawn } = require('child_process');
const temperatures = []; // Store readings

const sensor = spawn('python', ['sensor.py']);
sensor.stdout.on('data', function(data) {

    // convert Buffer object to Float
    temperatures.push(parseFloat(data));
    console.log(temperatures);
});

12

通常您可以使用类似以下的Ajax请求来完成此操作:

var xhr = new XMLHttpRequest();
xhr.open("GET", "pythoncode.py?text=" + text, true);
xhr.responseType = "JSON";
xhr.onload = function(e) {
  var arrOfStrings = JSON.parse(xhr.response);
}
xhr.send();

6
你无法在没有Python程序的情况下从JavaScript中运行.py文件,就像没有文本编辑器时无法打开.txt文件一样。但是,在Web API服务器(以下示例中为IIS)的帮助下,整个过程变得轻松。
  1. Install python and create a sample file test.py

    import sys
    # print sys.argv[0] prints test.py
    # print sys.argv[1] prints your_var_1
    
    def hello():
        print "Hi" + " " + sys.argv[1]
    
    if __name__ == "__main__":
        hello()
    
  2. Create a method in your Web API Server

    [HttpGet]
    public string SayHi(string id)
    {
        string fileName = HostingEnvironment.MapPath("~/Pyphon") + "\\" + "test.py";          
    
        Process p = new Process();
        p.StartInfo = new ProcessStartInfo(@"C:\Python27\python.exe", fileName + " " + id)
        {
            RedirectStandardOutput = true,
            UseShellExecute = false,
            CreateNoWindow = true
        };
        p.Start();
    
        return p.StandardOutput.ReadToEnd();                  
    }
    
  3. And now for your JavaScript:

    function processSayingHi() {          
       var your_param = 'abc';
       $.ajax({
           url: '/api/your_controller_name/SayHi/' + your_param,
           type: 'GET',
           success: function (response) {
               console.log(response);
           },
           error: function (error) {
               console.log(error);
           }
        });
    }
    

请记住,你的.py文件将不会在用户的计算机上运行,而是在服务器上运行。


4

尽管某些回复和评论认为不行,但有多种方式可以在前端使用Python。对于您的问题,请参见此回复


2

看一下JSPyBridge

似乎你可以使用这个工具在JS中使用Python函数。他们甚至有一个NLTK的例子,我已经在这里提供了。

// Do npm i pythonia first!
import { python } from 'pythonia'
import fs from 'fs'
const nltk = await python('nltk')

// ** You can comment this if you already have it.
await nltk.download('book')

const monologue = fs.readFileSync('./shakesphere.txt', 'utf-8')

// First we use NLTK to tokenize, tag and "chunk" the words into a tree
const sentences = await nltk.sent_tokenize(monologue).then(v => v.valueOf())
const tokenized = await Promise.all(sentences.map(sentence => nltk.word_tokenize(sentence)))
const tagged = await Promise.all(tokenized.map(tok => nltk.pos_tag(tok)))
const chunked = await nltk.ne_chunk_sents$(tagged, { binary: true })

// Some tree traversal logic to extract all the Named Entities (NE)
async function extractEntityNames (t) {
  const entityNames = []
  if (await t.label$) {
    const label = await t.label()
    if (label === 'NE') {
      for (const child of await t.valueOf()) {
        entityNames.push(child[0])
      }
    } else {
      for await (const child of t) {
        entityNames.push(...await extractEntityNames(child))
      }
    }
  }
  return entityNames
}

const entityNames = []

// Run the function above on each of the chunked trees
for await (const tree of chunked) {
  entityNames.push(...await extractEntityNames(tree))
}

// Compile the frequencies of each word
const frequencies = entityNames.reduce((acc, curr) => (acc[curr] ??= 0, acc[curr]++, acc), {})
// Turn it to an array and list by most common
const result = Object.entries(frequencies).map(([k, v]) => [k, v]).sort((a, b) => b[1] - a[1])
// Log it out, you should get [ [ 'Romeo', 5 ], [ 'Juliet', 2 ], [ 'Deny', 1 ], [ 'Montague', 1 ], ... ]
console.log(result)
// Exit python
python.exit()


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接