подпроцесс stdout в переменную для Ngrok

Я пытаюсь создать скрипт Python, который сообщает мне, что порт на 0.tcp.ngrok.io запускается, когда я запускаю код на терминале (после перемещения исполняемого файла ngrok в /usr/local/bin)

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 в переменную, но поскольку stdout является циклическим, 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**]

как я могу получить моментальный снимок stdout для переменной, не останавливая ngrok?

Есть ли другой способ сделать это (следующей попыткой будет веб-скрейпер на локальном хосте, но было бы неплохо иметь эти знания для других команд, таких как top)

заранее спасибо


person Luis Borbolla    schedule 27.06.2017    source источник


Ответы (3)


У меня была та же проблема, когда я работал с ngrok http, и все альтернативы не работали, что приводило к взаимоблокировкам, и я даже мог распечатать ответ дочернего процесса, созданный с помощью ngrok. Таким образом, читая документы ngrok, я заметил, что есть способ получить общедоступный URL-адрес ngrok с помощью Запросы. Добавляем код ниже:

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
person Rodolfo Schiavi    schedule 20.07.2017

недостаточно репутации, чтобы комментировать, не стесняйтесь обновить или прокомментировать отличный ответ @Rodolfo, а затем удалить это

Возможно, они немного изменили API, это то, что сработало для меня: (исполняемый файл ngrok рядом со сценарием, обслуживание http на порту 5000 и выбор URL-адреса туннелирования https)

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)
person Hemulin    schedule 26.08.2017

Это работает для меня:

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 .

person Gianla    schedule 29.07.2020