常见的java调用python脚本方式

  • 通过jython提供的类库实现
  • 通过Runtime.getRuntime()开启进程来执行脚本文件

通过jython提供的类库实现

  通过jython实现的话,我们需要引入jar包(jython官网:https://www.jython.org/),具体我写了一个demo,假设你的python代码为test.py:

public static void main(String[] args) {
PythonInterpreter interpreter = new PythonInterpreter();
interpreter.execfile("E:\\workspace\\pycharm_workspace\\weixincrawer\\test.py");
PyFunction function = (PyFunction)interpreter.get("my_test",PyFunction.class);
PyObject pyobject = function.__call__(new PyString("huzhiwei"),new PyString("25"));
System.out.println("anwser = " + pyobject.toString());
}

输出结果:

name: huzhiwei
age: 25
anwser = success

  到此是没有什么问题的,我们使用function.call方法传入参数调用python函数,使用pyobject.toString()方法拿到python中my_test函数的返回值,但是如果你把test.py稍微做下修改如下:

import requests

def my_test(name, age):
response = requests.get("http://www.baidu.com")
print("name: "+name)
print("age: "+age)
return "success"

  不修改java调用代码的情况下,你会得到下面异常信息:

  ImportError: No module named requests

  没错,这就是我要讨论的问题,因为jython不可能涵盖所有python第三方类库的东西,所以在我们得python文件中用到requests类库的时候,很显然会报找不到模块的错误,这个时候我们是可以通过Runtime.getRuntime()开启进程来执行python脚本文件的。

通过Runtime.getRuntime()开启进程来执行脚本文件

使用这种方式需要同时修改python文件以及java调用代码,在此我同样在上面test.py的基础上进行修改:

import requests
import sys def my_test(name, age):
response = requests.get("http://www.baidu.com")
print("url:"+response.url)
print("name: "+name)
print("age: "+age)
return "success" my_test(sys.argv[1], sys.argv[2])

和上面test.py代码最大的区别在于,我们此处开启进程的方式实际上是在隐形的调用dos界面进行操作,因此在python代码中我们需要通过sys.argv的方式来拿到java代码中传递过来的参数。

java调用代码部分:

public static void main(String[] args) {
String[] arguments = new String[] {"python", "E:\\workspace\\pycharm_workspace\\weixincrawer\\test.py", "huzhiwei", "25"};
try {
Process process = Runtime.getRuntime().exec(arguments);
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
in.close();
int re = process.waitFor();
System.out.println(re);
} catch (Exception e) {
e.printStackTrace();
}
}

结果输出:

url:http://www.baidu.com/
name: huzhiwei
age: 25
0

在此需要注意的一点,java代码中的process.waitFor()返回值为0表示我们调用python脚本成功,返回值为1表示调用python脚本失败,这和我们通常意义上见到的0与1定义正好相反。

java通过Process.waitFor()调用python模块返回错误代码1的一种解决办法

  在本人的实际项目需求开发时,基本上也是模仿上面的思路进行的,python脚本成功在PyCharm Community中也执行也成功,获得了所请求的网页数据,但是在java环境中通过Process.waitFor()调用python模块返回错误代码1。

  经过多次尝试和分析,发现

  问题原因:我的请求的URL设置为安全Http了,即https了,在PyCharm Community IDE可能存在HTTPS相关的处理模块所以执行成功。但是在java环境中通过Process.waitFor()调用python模块,实质上是通过dos/cmd命令行执行python.exe *.py命令的。而在这种情况下,由于环境中缺少HTTPS相关的处理模块所以执行不成功。

  解决办法:将请求的URL由安全Https修改为http即可。

下面附上我的示例代码:

被调用的python代码模块为:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2020/3/6 23:41
# @Author :
# @File : URLibTest.py import urllib.request
import sys def WebSpider(name, age):
response = urllib.request.urlopen('http://celestrak.com/satcat/tle.php?CATNR=25994')
print(response.read().decode('utf-8')) WebSpider(sys.argv[1], sys.argv[2])
# WebSpider("huzhiwei", "25")

主调的java代码模块为:

package cn.cetc;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader; public class JavaInvokePython {
private static final String pyInterpreterPath = "C:\\Anaconda3\\python.exe";//注意:当命令行参数分开写的时候,exe后面不用添加一个空格。当命令行参数一起写的时候,exe后面一定要添加一个空格
private static final String pyFilePath = "URLibTest.py";//如果未指定.py文件的完全路径,则默认从工程当前目录下搜索
private static Process proc = null;//java进程类 /**
* 执行*.py文件
*/
public static void execPy() {
try {
String[] arguments = new String[] {pyInterpreterPath, pyFilePath, "huzhiwei", "25"};//实际上后两个参数传进入也没使用。当真正需要有参数传入时可以是利用这种方式传参
proc = Runtime.getRuntime().exec(arguments);
BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
in.close(); int re = proc.waitFor();//返回0:成功。其余返回值均表示失败,如:返回错误代码1:操作不允许,表示调用python脚本失败
System.out.println(re);
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
} public static void main(String[] args) {
execPy();
} }

注意:上述java代码运行环境不需要额外安装Jython-x.x.x.jar,只需要一般的JDK环境和常规的需要的包导入。

参考链接:

1、java调用python脚本

2、在Java中调用Python代码

3、java调用python的几种用法(看这篇就够了)

4、Java调用Python程序方法总结

5、java调用python脚本无法正确获取返回值

6、在Java中调用Python

[转]java调用python脚本以及通过Process.waitFor()直接调用python模块返回错误代码1的一种解决办法的更多相关文章

  1. 解决:执行python脚本,提示错误:/usr/bin/python^M: 解释器错误: 没有那个文件或目录。

    执行python脚本,提示错误: /usr/bin/python^M: 解释器错误: 没有那个文件或目录. 产生错误原因: \r字符被显示为^M,这时候只需要删除这个字符就可以了. Linux环境下: ...

  2. Java链接Redis时出现 “ERR Client sent AUTH, but no password is set” 异常的原因及解决办法

    Java链接Redis时出现 "ERR Client sent AUTH, but no password is set" 异常的原因及解决办法 [错误提示] redis.clie ...

  3. java调用python脚本 并传参(根据配置文件获取python文件地址)

    方式一: Java代码 package com.mybatis.plus.utils; import cn.hutool.core.lang.Console; import java.io.Buffe ...

  4. 如何让python脚本支持命令行参数--getopt和click模块

    一.如何让python脚本支持命令行参数 1.使用click模块 如何使用这个模块,在我前面的博客已经写过了,可参考:https://www.cnblogs.com/Zzbj/p/11309130.h ...

  5. Python脚本开头两行的:#!/usr/bin/python和# -*- coding: utf-8 -*-的作用

    #!/usr/bin/Python指定用什么解释器运行脚本以及解释器所在的位置 # -*- coding: utf-8 -*-用来指定文件编码为utf-8的 估计有不少人注意过一些python脚本开头 ...

  6. 关于Python脚本开头两行的:#!/usr/bin/python和# -*- coding: utf-8 -*-的作用 – 指定文件编码类型

    #!/usr/bin/python指定用什么解释器运行脚本以及解释器所在的位置 # -*- coding: utf-8 -*-用来指定文件编码为utf-8的PEP 0263 -- Defining P ...

  7. 【转】关于Python脚本开头两行的:#!/usr/bin/python和# -*- coding: utf-8 -*-的作用 – 指定文件编码类型

    原文网址:http://www.crifan.com/python_head_meaning_for_usr_bin_python_coding_utf-8/ #!/usr/bin/python 是用 ...

  8. 【转载】关于Python脚本开头两行的:#!/usr/bin/python和# -*- coding: utf-8 -*-的作用 – 指定文件编码类型

    1.#!/usr/bin/python 是用来说明脚本语言是 python 的 是要用 /usr/bin下面的程序(工具)python,这个解释器,来解释 python 脚本,来运行 python 脚 ...

  9. 【亲测有效】Nodepad++/Sublime Text3中Python脚本运行出现语法错误:IndentationError: unindent does not match any outer indentation level解决策略

    我在开发游戏的时候,发现一个python脚本,本来都运行好好的,然后写了几行代码,而且也都确保每行都对齐了,但是运行的时候,却出现语法错误: IndentationError: unindent do ...

  10. (二)Python脚本开头两行的:#!/usr/bin/python和# -*- coding: utf-8 -*-的作用

    #!usr/bin/env python # -*- coding: utf-8 -*- def test(): print('hello, world') if __name__ == " ...

随机推荐

  1. 云原生周刊:Gateway API v1.1 发布 | 2024.6.3

    开源项目推荐 Grafana Tanka Tanka 是 Grafana 开发的一款用于 Kubernetes 的灵活.可重用和简洁的配置工具,是使用 YAML 进行 Kubernetes 配置的一种 ...

  2. Cloth Simulation with Root Finding and Optimization

    目录 0 前言 1 Implicit Method 1.1 Root-finding 1.2 Optimization 1.3 Insight 2 Newton-Raphson Method 3 Ma ...

  3. 关于STL容器的简单总结

    关于STL容器的简单总结 转载自 1.结构体中重载运算符的示例 //结构体小于符号的重载 struct buf { int a,b; bool operator < (const buf& ...

  4. linux基本指令总结

    拖了好久的linux学习,终于开始啦 环境终于没问题了 边学边总结 一.常用指令 1.1 关机与开机 poweroff 马上关机 reboot 马上重启 1.2 目录文件操作命令 cd / 切换到根目 ...

  5. 2024 xp_CAPTCHA(瞎跑-白嫖版) 4.3最新版安装使用教程

    前言 xp_CAPTCHA(瞎跑-白嫖版)是一个免费的burpsuite插件,具有自动化图形验证码识别的功能.在安装的过程中,我发现网上的教程基本都为其较早的版本,已经不具备参考价值.因而我写下本篇博 ...

  6. 基于Java+SpringBoot+Mysql实现的古诗词平台功能设计与实现九

    一.前言介绍: 1.1 项目摘要 随着信息技术的迅猛发展和数字化时代的到来,传统文化与现代科技的融合已成为一种趋势.古诗词作为中华民族的文化瑰宝,具有深厚的历史底蕴和独特的艺术魅力.然而,在现代社会中 ...

  7. 基于YOLO实现滑块验证码破解

    申明:本案例中的思路和技术仅用于学习交流.请勿用于非法行为. 一.训练模型 详细训练步骤和导出模型参考 滑块验证码识别模型训练 二.模型试用 通过YoloDotNet运行模型,计算出滑块缺口位置后用R ...

  8. 条理清晰,浅显易懂:Lua语法技术知识详解(第三部分)

    今天我们继续学习Lua语法基础教程,下篇. 9.4 函数返回值 在前面的代码中,我们实现了一个函数,输入变量a.b,函数会自动输出两个数值的和. 但是一般来说,我们的需求远远不止这些,我们可能需要一个 ...

  9. 关于linux 终端的小命令

    Ubuntu 为例 ctrl alt t   新开一个终端(默认工作目录) ctrl shift t 在当前终端开一个tab (工作目录和当前tab一致 当你进入一个很深的目录的时候需要新开一个命令行 ...

  10. 玩转AI工作流:一步步搭建灵活的自动化流程

    我们之前搭建了许多不同类型的智能体,其中最受欢迎的就是在智能体中搭建各种工作流--这也是我最喜欢探索和玩的领域.那么,究竟什么是工作流?如何在后端实现一个工作流呢?今天我们就先简单了解下. 什么是工作 ...