Самый простой способ - просто использовать response.iter_content , чтобы постепенно прочитать тело ответа и записать его в стандартный поток процесса в виде кусков:
import requests
import subprocess
r = requests.get('http://www.stackoverflow.com', stream=True)
r.raise_for_status()
p = subprocess.Popen(['wc'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
for chunk in r.iter_content(2048):
p.stdin.write(chunk)
stdout, stderr = p.communicate()
print("wc output:", stdout)
Таким образом, вы не используете файлоподобный объект из requests
, но он вам не нужен. Обратите внимание, что Popen
уже создает файловый объект (а именно канал), доступный как process.stdin
, который вы можете использовать для передачи данных процессу в реальном времени по мере его поступления.
Не сразу очевидно, что p.communicate()
здесь делает две вещи:
- закрывает стандартный входной канал, не записывая в него больше данных, сообщая
wc
, что мы закончили с записью, и он может вывести значения;
- затем читает все данные из канала stdout в переменную.
Примечание: wc
хорошо подходит здесь, поскольку потребляет все stdin
до печати до stdout
, но этот подход может зайти в тупик, если ваш процесс попытается записать в stdout
до stdin
полностью потребляется. В этом случае программа может зависнуть на p.stdin.write
, в то время как процесс ожидает чтения Python из p.stdout
.
Для того, чтобы справиться с этим правильно, вам нужно написать отдельные темы для чтения и записи. communicate()
делает это за вас, но принимает входные данные только в виде строки, а не потока или генератора. Другой альтернативой может быть запись процесса в временный файл, а не в канал.