将标准输出子进程转换为 Ngrok 的变量

Posted

技术标签:

【中文标题】将标准输出子进程转换为 Ngrok 的变量【英文标题】:subprocess stdout into a variable for Ngrok 【发布时间】:2017-11-30 16:57:33 【问题描述】:

我正在尝试制作一个 python 脚本,当我在终端上运行代码时(在将 ngrok 可执行文件移动到 /usr/local/bin 之后)启动 0.tcp.ngrok.io 上的端口

p>

ngrok tcp 22

我得到了这种输出

ngrok by @inconshreveable                                       (Ctrl+C to quit)
                                                                                
Session Status                connecting                                        
Version                       2.2.4                                             
Region                        United States (us)                                
Web Interface                 http://127.0.0.1:4041                             
Forwarding                    tcp://0.tcp.ngrok.io:13014 -> localhost:22                                                                                 
Connections                   ttl     opn     rt1     rt5     p50     p90       
                              0       0       0.00    0.00    0.00    0.00  

我的第一次尝试是将子进程标准输出记录到变量中,但由于标准输出是循环的,stdout.read() 永远不会结束,这是代码

import subprocess

ngrok = subprocess.Popen(['ngrok','tcp','22'],stdout = subprocess.PIPE)

output_text = ngrok.stdout.read() # script stops here forever

[**code for getting domain:port from output_text**]

如何在不停止 ngrok 的情况下获取 stdout 到变量的“快照”?

还有其他方法吗(下一次尝试是在 localhost 上使用网络爬虫,但如果有其他命令的相关知识会很好,例如“top”)

提前致谢

【问题讨论】:

【参考方案1】:

我在使用 ngrok http 时遇到了同样的问题,并且所有替代方案都不起作用,导致死锁,我什至可以打印使用 ngrok 创建的子进程响应。因此,阅读ngrok docs 我注意到有一种方法可以通过请求获取 ngrok 公共 url。 添加以下代码:

localhost_url = "http://localhost:4041/api/tunnels" #Url with tunnel details
tunnel_url = requests.get(localhost_url).text #Get the tunnel information
j = json.loads(tunnel_url)
tunnel_url = j['Tunnels'][0]['PublicUrl'] #Do the parsing of the get

所以,tunnel_url 将返回您需要的内容。添加导入的完整代码如下:

import subprocess
import requests
import json

ngrok = subprocess.Popen(['ngrok','tcp','22'],stdout = subprocess.PIPE)

localhost_url = "http://localhost:4041/api/tunnels" #Url with tunnel details
tunnel_url = requests.get(localhost_url).text #Get the tunnel information
j = json.loads(tunnel_url)

tunnel_url = j['Tunnels'][0]['PublicUrl'] #Do the parsing of the get

【讨论】:

【参考方案2】:

没有足够的声誉来发表评论,请随时更新或评论 @Rodolfo 的好答案,然后删除此

也许他们稍微改变了 api,这对我有用: (脚本旁边的 ngrok 可执行文件,在端口 5000 上提供 http 并选择 https 隧道 url)

import subprocess
import requests
import json
import time

if __name__ == '__main__':
    ngrok = subprocess.Popen(['./ngrok','http','5000'], 
                             stdout=subprocess.PIPE)
    time.sleep(3) # to allow the ngrok to fetch the url from the server
    localhost_url = "http://localhost:4040/api/tunnels" #Url with tunnel details
    tunnel_url = requests.get(localhost_url).text #Get the tunnel information
    j = json.loads(tunnel_url)

    tunnel_url = j['tunnels'][1]['public_url'] #Do the parsing of the get
    print(tunnel_url)

【讨论】:

【参考方案3】:

这对我有用:

def open_tunnel():
        process = subprocess.Popen(f'/snap/bin/ngrok tcp PORT --log "stdout"', shell=True, stdout=PIPE, stderr=PIPE)  # You can also use a list and put shell = False
        while True:
            output = process.stdout.readline()
            if not output and process.poll() is not None:
                break
            elif b'url=' in output:
                output = output.decode()
                output = output[output.index('url=tcp://') + 10 : -1]
                return output.split(':')

我使用/snap/bin/ngrok,因为我的 pycharm 无法识别路径,对此感到抱歉。您可以只说ngrok 来替换它 .

【讨论】:

以上是关于将标准输出子进程转换为 Ngrok 的变量的主要内容,如果未能解决你的问题,请参考以下文章

为远程进程的子进程捕获标准输出

无法使用子进程从标准输出获取结果

Jupyter notebook 中 Python 子进程的实时标准输出输出

阻止写入标准输出

持久的子进程管道 - 没有读取标准输出

Linux - 从管道读取的孩子接收发送到标准输出的调试消息