[转]java调用python脚本以及通过Process.waitFor()直接调用python模块返回错误代码1的一种解决办法
常见的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环境和常规的需要的包导入。
参考链接:
[转]java调用python脚本以及通过Process.waitFor()直接调用python模块返回错误代码1的一种解决办法的更多相关文章
- 解决:执行python脚本,提示错误:/usr/bin/python^M: 解释器错误: 没有那个文件或目录。
执行python脚本,提示错误: /usr/bin/python^M: 解释器错误: 没有那个文件或目录. 产生错误原因: \r字符被显示为^M,这时候只需要删除这个字符就可以了. Linux环境下: ...
- Java链接Redis时出现 “ERR Client sent AUTH, but no password is set” 异常的原因及解决办法
Java链接Redis时出现 "ERR Client sent AUTH, but no password is set" 异常的原因及解决办法 [错误提示] redis.clie ...
- java调用python脚本 并传参(根据配置文件获取python文件地址)
方式一: Java代码 package com.mybatis.plus.utils; import cn.hutool.core.lang.Console; import java.io.Buffe ...
- 如何让python脚本支持命令行参数--getopt和click模块
一.如何让python脚本支持命令行参数 1.使用click模块 如何使用这个模块,在我前面的博客已经写过了,可参考:https://www.cnblogs.com/Zzbj/p/11309130.h ...
- Python脚本开头两行的:#!/usr/bin/python和# -*- coding: utf-8 -*-的作用
#!/usr/bin/Python指定用什么解释器运行脚本以及解释器所在的位置 # -*- coding: utf-8 -*-用来指定文件编码为utf-8的 估计有不少人注意过一些python脚本开头 ...
- 关于Python脚本开头两行的:#!/usr/bin/python和# -*- coding: utf-8 -*-的作用 – 指定文件编码类型
#!/usr/bin/python指定用什么解释器运行脚本以及解释器所在的位置 # -*- coding: utf-8 -*-用来指定文件编码为utf-8的PEP 0263 -- Defining P ...
- 【转】关于Python脚本开头两行的:#!/usr/bin/python和# -*- coding: utf-8 -*-的作用 – 指定文件编码类型
原文网址:http://www.crifan.com/python_head_meaning_for_usr_bin_python_coding_utf-8/ #!/usr/bin/python 是用 ...
- 【转载】关于Python脚本开头两行的:#!/usr/bin/python和# -*- coding: utf-8 -*-的作用 – 指定文件编码类型
1.#!/usr/bin/python 是用来说明脚本语言是 python 的 是要用 /usr/bin下面的程序(工具)python,这个解释器,来解释 python 脚本,来运行 python 脚 ...
- 【亲测有效】Nodepad++/Sublime Text3中Python脚本运行出现语法错误:IndentationError: unindent does not match any outer indentation level解决策略
我在开发游戏的时候,发现一个python脚本,本来都运行好好的,然后写了几行代码,而且也都确保每行都对齐了,但是运行的时候,却出现语法错误: IndentationError: unindent do ...
- (二)Python脚本开头两行的:#!/usr/bin/python和# -*- coding: utf-8 -*-的作用
#!usr/bin/env python # -*- coding: utf-8 -*- def test(): print('hello, world') if __name__ == " ...
随机推荐
- AI五子棋_10 更多的算法探索
AI五子棋 第十步 恭喜你到达第十步! 你已经完成了一个AI的设计,下面就需要发动你的智慧让你的机器大脑变得更聪明了! 我们的征途是星辰大海! 更多资料可以参考这个列表 https://gomocup ...
- att&ck学习笔记1
一.环境搭建 1.1环境搭建测试 最近想要开始学习内网渗透,搜集了一些教程,准备先实验一个vulnstack靶机,熟悉一下内网渗透操作再学习基础知识. 靶场下载地址:http://vulnstack. ...
- Vue2.x 常用功能和方法
Vue 生命周期 beforeCreate (组件实例刚被创建,组件属性计算之前,如 data 属性等) created (组件实例创建完成, 属性已绑定,但 DOM 还未生成, $el 属性不存在) ...
- C240817D. 模拟赛:树上dp(以i为起点)+set操作
C240817D. 模拟赛 比较显然的树上dp, 但是维护set比较烦 考场上其实自己是定义 \(f[i]\) 是以 \(i\) 结尾, 然后这样的话单次更新根本做不到 \(O(logN)\). 反应 ...
- 『玩转Streamlit』--数据展示组件
数据展示组件在Streamlit各类组件中占据了至关重要的地位, 它的核心功能是以直观.易于理解的方式展示数据. 本次介绍的数据展示组件st.dataframe和st.table,能够将复杂的数据集以 ...
- apache2和nginx卸载总是不干净不完全导致无法重装,重装成功也无法启动
大着胆子把nginx卸载了用的命令是 sudo apt remove nginx 结果最后不知道怎么折腾的就算重新装也装不上了,然后就转头折腾apache2,也卸载了 sudo apt remov ...
- RL 基础 | 如何复现 PPO,以及一些踩坑经历
最近在复现 PPO 跑 MiniGrid,记录一下- 这里跑的环境是 Empty-5x5 和 8x8,都是简单环境,主要验证 PPO 实现是否正确. 01 Proximal policy Optimi ...
- require/import路径中的叹号是什么?
问题: 之前在一些开源项目的源码里,以及一些文章里,见到如下这样的require/import路径,其中包含形如!.的片段,不知道是什么意思: // https://juejin.im/post/68 ...
- mongo之常见问题
最近发现服务器上的MongoDB由于oom导致服务被杀死 1.查看oom时间 grep "Out of memory" /var/log/message 或者 dmesg -T|g ...
- Tornado框架之应用安全(四)
知识点 Cookie操作 安全Cookie 跨站请求伪造原理 XSRF保护 模板 请求体 HTTP报文头 用户验证 authenticated装饰器 get_current_user()方法 logi ...