這篇博客旨在吐血分享今天遇到的java調用python腳本遇到的坑,折騰了3個多小時終於可以跑通了,代碼超級短,但網上的好多資料都是抄來抄去的,很少有能夠直接跑通的,尤其是針對你的python文件中用到第三方類庫的情況。
先來說說我為什么要用java調用python代碼,原因就在於python在爬蟲方面提供了豐富的類庫,但我本來已經有一套java操作數據庫以及消息中間件的代碼,這些代碼用python實現的話可能需要至少一周時間,為了減少時間成本,因此我決定用java調用python腳本的方式使用requests等等庫,下面把我解決的過程分享出來,希望能給遇到類似問題的朋友一點幫助。
常見的java調用python腳本方式
- 通過jython.jar提供的類庫實現
- 通過Runtime.getRuntime()開啟進程來執行腳本文件
通過jython.jar提供的類庫實現
通過jython.jar實現的話,我們需要引入jar包,具體我寫了一個demo,假設你的python代碼為test.py:
def my_test(name, age): print("name: "+name) print("age: "+age) return "success"
java調用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定義正好相反。
我的代碼:
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2018-02-27 # @Author : zhangmingcheng from PIL import Image import imagehash import sys def get_hash(path): image = Image.open(path) h = str(imagehash.dhash(image)) print h return h get_hash(sys.argv[1])
java
/** * 獲取影像dhash,獲取完后將影像刪除 */ @Override public String getDhash(String absolutePathName) { String dhash = ""; String[] arguments = new String[] { "python", "/root/imagedhash/rest.py", absolutePathName }; try { Process process = Runtime.getRuntime().exec(arguments); BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream())); String line = null; while ((line = in.readLine()) != null) { dhash = line; } in.close(); process.waitFor(); } catch (Exception e) { e.printStackTrace(); } File file = new File(absolutePathName); if (file.exists() && file.isFile()) { file.delete(); System.out.println(absolutePathName + "影像的dhash值=" + dhash + ",刪除影像成功"); } return dhash; }
轉自:http://blog.csdn.net/hzw19920329/article/details/77509497