humanemulator.net — справка. Продукт, демо и покупка — на хуманэмулятор.рф | Демо | Купить | API | лог изменений

Сверено 21 октября 2026 по выпускам 7.0.78 и 8.1.6. · Руководство humanemulator.net

Запуск внешних скриптов из робота

Пять методов объекта app — run_as_python, run_as_js, run_as_php, run_as_console и run_as_bat — записывают файл и запускают его outside робота, а вывод возвращают строкой. Ниже: чем они различаются, откуда берётся интерпретатор, что происходит с выводом и ошибками, что на самом деле означает $timeout и как дочернему скрипту дозвониться до приложения, которое его запустило.

Пять методов

Первые три записывают содержимое в файл и запускают его своим интерпретатором; run_as_console ничего не пишет — он запускает готовый исполняемый файл; run_as_bat пишет и запускает пакетный файл Windows.

МетодЧто делаетВозвращает
run_as_python($content, $path, $show, $params, $timeout)Пишет $path (.py) и запускает через PythonВывод скрипта в консоль; пусто при ошибке
run_as_js($content, $path, $show, $params, $timeout)Пишет $path (.js) и запускает через Node.jsВывод скрипта; пусто при ошибке
run_as_php($content, $path, $show, $params, $timeout)Пишет $path (.php) и запускает через PHP приложенияВывод скрипта; пусто при ошибке
run_as_console($path, $show, $params, $encoding, $timeout)Запускает готовый .exe и читает его консольВывод; N/A при ошибке
run_as_bat($content, $path, $show, $timeout)Пишет $path (.bat) и выполняет в терминалеtrue/false — вывод не возвращается

$content можно оставить пустым: тогда выполняется уже существующий файл по пути $path. Путь указывается относительно папки скрипта — "test/1.py" попадёт в подпапку test рядом с роботом; каталог обязан существовать, иначе вызов вернёт ошибку, а не создаст папку.

Для вызова произвольной программы с её параметрами есть shell_execute — он не ждёт окончания и не читает вывод; run_as_console выбирайте, когда нужен текст ответа программы.

Откуда берётся интерпретатор

  • Python и Node.js — из настроек программы, а не из переменной окружения и не из угаданного пути. До 7.0.78 run_as_js собирал путь к node.exe неверно и скрипт не запускался; теперь Node.js берётся из настроек и вывод возвращается целиком.
  • PHP — встроенный в приложение: run_as_php выполняет файл тем же PHP, что обслуживает робота, поэтому расширения и настройки общие.
  • В 8.x у каждого языка есть режим запуска — на хосте или в контейнере среды выполнения; он переключается в настройках и влияет на то, какой именно интерпретатор увидит run_as_python и run_as_js (подробнее — в разделе про платформы).
Если run_as_js или run_as_python возвращает пусто, а в логе ошибки пусто — первым делом сверьте путь к интерпретатору в настройках: метод не ищет Node.js или Python в PATH «на удачу».

Вывод и ошибки

Внешний скрипт пишет в два потока: обычный вывод и поток ошибок. Робот получает текст стандартного вывода как возвращаемое значение, а поток ошибок приложение добавляет в свой журнал — в строку возврата он не попадает. Поэтому «пустой результат» ещё не значит «скрипт молчал»: смотрите панель отладки.

Главная ловушка этих вызовов — большой вывод. Пока программа читала вывод после завершения процесса, скрипт с логом больше буфера pipe зависал навсегда: процесс ждал, кто заберёт текст, а робот ждал, пока процесс закончится. Сейчас оба потока вычитываются параллельно с исполнением, и вызов возвращает полный текст.

  • 7.x: выпуск 7.0.78 — run_as_python, run_as_console и run_as_js больше не виснут на большом выводе, run_as_php с перехватом вывода перестал бросать исключение.
  • 8.x: те же правки — в 8.1.5.

Симптом старой сборки: Studio висит, в диспетчере задач живёт python.exe (или node.exe), которого никто не снимает. Если скрипт печатает много — обновитесь или разбейте вывод на части.

Что такое $timeout

Последний параметр всех пяти методов — $timeout, по умолчанию 3000. Это не лимит на работу скрипта и не «убить через N секунд».

Робот общается с приложением по HTTP, и $timeout — сколько секунд клиент скрипта жит ответа от этого вызова. Пока внешний процесс жив, вызов не завершён, и параметр определяет, когда клиент устанет ждать. Практические следствия:

  • скрипт, который работает дольше $timeout, не отменяется — робот просто потеряет связь с вызовом, а процесс доиграет на своё усмотрение;
  • для долгой внешней работы уменьшать таймаут бессмысленно — увеличивайте его или разбивайте задачу;
  • значение 0 и меньше не означают «ждать вечно»: клиент подставляет таймаут команды по умолчанию (в шаблонах PHP это 600 секунд). Если нужен действительно долгий вызов — напишите число.

Сколько именно жил процесс и не потерялся ли вывод — видно в журнале приложения; там же дублируются сообщения об ошибках из stderr.

Обратная связь: RPABOT_HOST_URL

Дочерний скрипт часто должен обратиться обратно в приложение: позвонить get_port, выполнить команду через API или доложить о прогрессе. Адрес родителя передаётся ребёнку в переменной окружения RPABOT_HOST_URL — в ней хост и тот порт, который реально слушает приложение.

# child.py — обращаемся к тому же экземпляру, что нас запустил
import os, requests
host = os.environ["RPABOT_HOST_URL"]      # например 127.0.0.1:5006
r = requests.get(f"http://{host}/api/window/app/get_port")
print(r.text)

В скриптах на PHP, Python и C# глобальная переменная $xhe_host получает это значение автоматически из окружения процесса (с 7.0.76) — поэтому init-шаблон не обязан зашивать порт вручную, и робот переживает смену порта без правок.

Что чинилось в этой части и почему раньше не работало:

  • 7.0.78: родитель, ожидая ребёнка, держал единственный командный канал — команды ребёнка некому было обслуживать, и Studio зависала до ручного снятия процесса. Теперь на время ожидания канал пропускает вложенные команды.
  • 8.1.6: адрес хоста ребёнка всегда собирался с портом по умолчанию (7010), поэтому на установке, где приложение слушает другой порт, ребёнок получал connection refused. Теперь ребёнок получает реальный порт.

Отсюда правило: в дочернем скрипте не печатайте порт числом — читайте RPABOT_HOST_URL. Иначе первый же переезд на второй экземпляр программы сломает робота.

7.x и 8.x: где что исполняется

7.x (классическая Studio) ставится только на Windows, и run_as_* запускают процессы на этой же машине: Python и Node.js берутся из настроек, PHP — встроенный, run_as_bat — терминал Windows.

8.x (бета) — Windows и Linux; все пять методов присутствуют на обеих ОС, но среда выполнения выбирается по языку:

  • PHP по умолчанию исполняется на хосте — абсолютные пути этой ОС и переменные окружения работают как ожидается;
  • Python по умолчанию идёт через контейнер среды выполнения (режим «на хосте» включается в настройках);
  • JavaScript — только контейнер: собственного Node.js в поставке 8.x нет, и это норма, а не дефект установки;
  • из-за этого внутри контейнера путь вида D:\… не существует: файл, который скрипт пишет, пишите по пути относительно папки скрипта, и он будет виден хосту в той же папке;
  • контейнер поднимается Docker-ом: если Docker ещё не готов, запуск не состоится — проверьте docker version и дайте системе догрузиться.

Про установки 8.x на Linux: требования и установка. Общая картина восьмой линейки: Studio 8 (бета): что нового.

Примеры

Запуск Python с параметрами и разбором вывода:

<?php
require("../../../Templates/init.php");

$py  = "import sys\n";
$py .= "print('argv=' + str(sys.argv[1:]))\n";
$py .= "print('done')\n";

$out = WINDOW::$app->run_as_python($py, "test/1.py", false, "1 2");
if ($out !== "") {
    echo $out;                  // argv=['1', '2']  done
} else {
    echo "скрипт не выполнился — смотрите журнал\n";
}

WINDOW::$app->quit();
?>

Консольная утилита с кодовой страницей вывода (например чтобы дописать результат в файл):

$res = WINDOW::$app->run_as_console("tools/list.exe", false, "--json", "utf-8");
echo $res;   // N/A — запуск не удался

PHP-скрипт, который сам становится роботом: файл получает RPABOT_HOST_URL, подключает те же шаблоны API и работает с браузером наравне с основным скриптом — так из одного робота делают два, не плодя процессы вручную.

Готовые сценарии по задачам — в каталоге сниппетов; исходники этих методов — в описании объекта app.

Как проверить у себя

  1. Минимальный ребёнок: print('ok') через run_as_python. Если пусто — смотрите путь к интерпретатору в настройках и журнал (там stderr).
  2. Большой вывод: цикл на 200 000 строк. В 7.0.78 / 8.1.5 и новее вызов возвращается с текстом; в более старой сборке — зависание, выводите процесс вручную.
  3. Обратный звонок: в ребёнке напечатайте os.environ["RPABOT_HOST_URL"] и сверьте порт с настройками приложения. Разойдётся — у вас сборка до 8.1.6.
  4. Второй экземпляр программы: запустите робота из копии с другим портом и повторите пункт 3. Адрес обязан смениться сам.

← Миграция скриптов · Конструктор рабочих процессов →