【问题标题】:Execute python script through Java通过Java执行python脚本
【发布时间】:2022-01-12 10:54:04
【问题描述】:

我正在尝试运行一个非常简单的 python 脚本,该脚本从 java 内部清除并写入 CSV 文件,但我在执行此操作时遇到了很多麻烦。

脚本不需要任何输入,输出全部写入 CSV 文件,所以我需要做的就是让 python 脚本在我的 java 代码中运行。

以下是我在互联网上看到的一些代码,但似乎对我不起作用。似乎对于这两个脚本,使用此命令对 csv 没有任何作用。不会抛出任何错误,并且 java 程序可能会在不执行 python 脚本的情况下直接退出。

public static void main(String[] args) throws IOException
    {
        Process p = Runtime.getRuntime().exec("python Refresh.py");
    }

这是我正在尝试运行的脚本。

脚本1:

file = open("products.csv","r+")
file.truncate(0)
file.close()

脚本2:

from bs4 import BeautifulSoup as soup
from urllib.request import Request, urlopen
import time

filename = "products.csv"
f = open(filename, "a")


#connects to the page and reads and saves raw HTML
for i in (0,25,50,75):
    my_url = 'https://www.adorama.com/l/Computers/Computer-Components/Video-and-Graphics-Cards?startAt='+ str(i) +'&sel=Expansion-Ports_HDMI'
    hdr = {'User-Agent': 'Mozilla/5.0'}
    client = Request(my_url,headers=hdr)
    page = urlopen(client).read()

    #parsing the HTML
    page_soup = soup(page, "html.parser")
    #print (page_soup.h1)

    containers = page_soup.findAll("div",{"class":"item"})
    #print (len(containers))
    containers.pop()
    for container in containers:
        
        title_container = container.findAll("div",{"class":"item-details"})
        title = title_container[0].h2.a.text.strip()

        status_container = container.findAll("div",{"class":"item-actions"})
        status = status_container[0].form.button.text.strip()

        if (status == "Temporarily not available"):
            status = "Out of stock"
        else:
            status = "In stock"
        
        price = container.find("div","prices").input["value"]

        link = container.a["href"]

        f.write(title.replace(",", "|") + "," + price.replace(",", "") + "," + status + "," + link + "\n")

        time.sleep(0.01)
f.close()

java 文件、Python 脚本和 csv 文件都在同一个文件夹中。

【问题讨论】:

  • 你想用Java重写这些python脚本吗?
  • 您是否遇到任何错误?例外?您是否尝试过为 python 可执行文件和脚本提供完整路径以查看是否存在问题?
  • 无错误无异常。该程序只是运行并退出。我也试过给出 python 可执行文件的完整路径,但不幸的是仍然不起作用。
  • A) 你真的想在该命令中获得 python 二进制文件的完整路径 B) 从一个简单的 python 脚本开始,它只是将一些东西打印到标准输出 C) 然后使用 Java 进程接口来 阅读该脚本所写的内容,依此类推。从小处着手。是的,为什么要为此混合两种语言?
  • 谢谢,试试这个。至于语言的混合,我在 Java 中进行网页抓取的经历很糟糕,发现在 python 中更简单,而且更成功。所以我想把我的java项目的webscraping部分改成python。

标签: python java csv


【解决方案1】:

使用较新的 ProcessBuilder 类:

ProcessBuilder pb = new ProcessBuilder("python","Refresh.py");
Process p = pb.start();

希望对你有用!

【讨论】:

  • 不幸的是它仍然不起作用。 java 程序只需运行并退出,无需对 CSV 文件进行任何编辑。也没有抛出错误。
【解决方案2】:

您没有检查 python 脚本中的错误。您只需将 STDERR 合并到 STDOUT 并将 STDOUT 的内容报告给控制台即可实现此目的:

Process p = new ProcessBuilder("python", "Refresh.py")
            .redirectErrorStream(true)
            .start();
p.getInputStream().transferTo(System.out);
int rc = p.waitFor();

这应该会从 python 打印出错误消息并返回错误代码。您可能对文件的路径有疑问,因此您可能需要将参数调整为“python”和/或“Refresh.py”的显式路径名。

【讨论】:

  • 出于同样的想法,我创建了输入缓冲区并继续读取 python 输出,现在似乎实际上是在等待 python 脚本完成运行后再继续。谢谢!
【解决方案3】:

我设法通过不断读取 Python 文件的“打印”和错误输出来解决此问题。虽然我仍然不完全理解这是如何解决问题的,但我最好的猜测是,有了这个,Java 代码会保持 python 脚本“运行”,直到脚本本身完成它的工作,而不是仅仅打开脚本并立即继续前进。

代码如下:

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Test {

    public static void main(String... args) throws Exception {

        String[] callAndArgs = {"python3", "YourScript.py"};
        Process p = Runtime.getRuntime().exec(callAndArgs);
        
        BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
        BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
        
        String s;
        while ((s = stdInput.readLine()) != null) {
            //System.out.println(s);
        }

        while ((s = stdError.readLine()) != null) {
            //System.out.println(s);
        }

    }

}

另一个值得注意的细节是,此代码似乎仅在编译并通过终端/Geany 运行时才有效。如果我用 IntelliJ 运行同样的东西 它不起作用。再一次,我不确定这是为什么,但我怀疑 IntelliJ 可以在某种 VM 中编译和运行。

【讨论】:

  • 它可能不起作用,因为必须同时使用两个流,而不是一个接一个。请参阅下面的答案 - .redirectErrorStream(true) 部分表示没有流死锁。
  • 这会是它在 Geany 但不能在 Intellij 中工作的原因吗?这对我来说没有意义。我仍然会实施您建议的更改。谢谢:)
  • JVM不同,结果可能不同,但也要检查错误信息和结果代码
猜你喜欢
  • 2012-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-06
  • 1970-01-01
  • 2020-08-18
  • 2019-02-04
  • 2013-04-17
相关资源
最近更新 更多