Управление маршрутами

📌 Инструкция по использованию системы 📌 Cхема работы 📌 Справка по языку DocuScript

📘 Практические примеры по написанию универсальных парсеров на DocuScript

От простого случая к сложному: как писать скрипты, работающие на разных документах

... А так же немного про поисковые запросы poisktenderov.ru



❗ Важные принципы написания парсеров

При написании скриптов важно обращать внимание на следующие моменты:

  • Пишите код так, чтобы он срабатывал на разных документах — не привязывайтесь к жёстко заданным маршрутам, названиям или индексам.
  • Парсер обязательно должен возвращать как минимум:
    • $s_route_number — номер маршрута
    • $s_rasp_forward — расписание движения
  • Не полагайтесь на фиксированное количество строк в таблицах или количество выходов. Используйте циклы и перебор.
  • Циклы в качестве условия не принимают функции. Вам надо использовать конструкции if $b_res then или while $b_res или другую булеву переменную
  • Храните в $s_rasp_forward только расписания. Улицы и остановки могут менять форму написания («ул.» → «улица»), что вызывает ложные срабатывания.

Парсер должен уметь находить нужные параметры маршрута в документе, как правило, называющемся «Проект контракта».

📄 Простой случай: один маршрут

Перед вами контракт города Кузнецка. Нас интересуют:

  • даты начала и окончания работ
  • номер маршрута и его название (название — опционально)
  • расписание движения (обычно хранится в таблицах)

Как это выглядит в документе:

  • Маршрут №10А «ул. Каткова – ул. Минская»
  • Начало выполнения работ – с даты заключения контракта.
  • Окончание выполнения работ – 30.04.2026 года.
  • Таблицы с расписанием: «График №1», «График №2» и т.д.

📅 Извлечение дат начала и окончания

Для извлечения дат используем команду find_between, так как начало и конец фраз фиксированы.

Пример текста:
Начало выполнения работ – с даты заключения контракта.
Окончание выполнения работ – 30.04.2026 года.

Код:

$s_contract_start = find_between("Начало выполнения работ –  ", "")
$s_contract_finish = find_between("Окончание выполнения работ – ", " года.")

Функция find_between автоматически найдёт параграф и извлечёт текст между указанными строками.

Сайт умеет преобразовывать типовые фразы: "с даты заключения контракта.", "5 лет с даты заключения контракта" и некоторые другие в правильный формат дат

🔢 Извлечение номера и названия маршрута

Строка с маршрутом в документе выглядит так:

Маршрут №7 «ул. Пригородная (кольцевой)»

Нам нужно отсечь начало и конец строки. Используем find_between.

Код:

$n_route_marker = find("Маршрут № ")
$s_route_number = find_between("Маршрут № ", " «", $n_route_marker)
$s_route_name = find_between("«", "»", $n_route_marker)

⏰ Извлечение расписания

Наш маршрут кольцевой, и расписание есть только в одну сторону. Оно хранится в таблицах после заголовка:

7. Сводное расписание отправления транспортных средств из остановочных пунктов

И до следующего раздела:

8. Количество рейсов и пробег транспортных средств.

Находим таблицы:

$n_start = find("7.  Сводное расписание отправления транспортных средств из остановочных пунктов ")
$n_end = find("8. Количество рейсов и пробег транспортных средств.")
$t_tables = find_all_tables($n_start, $n_end)

Чтобы совершить обход по каждой таблице, используется конструкция

foreach_table $t_current in $t_tables do
	     enter_table $t_current
		... # действия
	 

Обрабатываем каждую таблицу:

$a_rasp = []
add_to_array $a_rasp, "Рабочие дни"

foreach_table $t_current in $t_tables do
    enter_table $t_current
    move_to_cell(3, 1)
    $s_val = read_cell
    add_to_array $a_rasp, $s_val
end

add_to_array $a_rasp, "\nВыходные дни"

foreach_table $t_current in $t_tables do
    enter_table $t_current
    move_to_cell(3, 2)
    $s_val = read_cell
    add_to_array $a_rasp, $s_val
end

$s_rasp_forward = join $a_rasp

✅ Итоговый скрипт для одного маршрута

$n_route_marker = find("Маршрут № ")
$s_route_number = find_between("Маршрут № ", " «", $n_route_marker)
$s_route_name = find_between("«", "»", $n_route_marker)

$s_contract_start = find_between("Начало выполнения работ –  ", "")
$s_contract_finish = find_between("Окончание выполнения работ – ", " года.")

$n_sched_start = find("7.  Сводное расписание отправления транспортных средств из остановочных пунктов ")
$n_sched_end = find("8. Количество рейсов и пробег транспортных средств.")
$t_tables = find_all_tables($n_sched_start, $n_sched_end)

$a_rasp = []
add_to_array $a_rasp, "Рабочие дни"

foreach_table $t_current in $t_tables do
    enter_table $t_current
    move_to_cell(3, 1)
    $s_val = read_cell
    add_to_array $a_rasp, $s_val
end

add_to_array $a_rasp, "\nВыходные дни"

foreach_table $t_current in $t_tables do
    enter_table $t_current
    move_to_cell(3, 2)
    $s_val = read_cell
    add_to_array $a_rasp, $s_val
end

$s_rasp_forward = join $a_rasp

return $s_route_number, $s_rasp_forward

Другой формат документа - DOC или ZIP

Иногда встречается другой формат данных на сайте госзакупок. Система поддерживает DOC и ZIP. Преобразование этих форматов происходит автоматически, но для архива требуется указать имя файла, которое нужно прочитать из архива.

unpack - Команда, которая распаковывает архив

convert - Помогает сконвертировать DOC в DOCX

read "file_name". Имя документа - строка, указывается в кавычках. Или перечисление нескольких документов через запятую.

read_r "file_name". Вариант команды с регулярным выражением. Если используется регулярное выражение, парсятся все документы, попадающие под регулярное выражение.

🔁 Несколько маршрутов в документе

Рассмотрим сложный случай: в документе несколько маршрутов. Например:

Маршрут №10А «ул. Каткова – ул. Минская»
...
Маршрут №15 «Центр – Завод»

Вам нужно обработать сначала первый маршрут, затем второй и т.д.

Шаблон кода:

find("Маршрут № ")
if $b_res then
    # Обработка первого маршрута
    $s_route_number = find_between("Маршрут № ", " «", $n_route_marker)
    # ... извлечение данных ...
    add_to_array $a_all_routes, $s_route_number + ": " + $s_rasp_forward
end

find("Маршрут № ")
if $b_res then
    # Обработка второго маршрута
    $s_route_number = find_between("Маршрут № ", " «", $n_route_marker)
    # ... извлечение данных ...
    add_to_array $a_all_routes, $s_route_number + ": " + $s_rasp_forward
end

Каждый find("Маршрут № ") ищет следующее вхождение после предыдущего.

🔄 Альтернатива: цикл по маршрутам

Если количество маршрутов заранее неизвестно, можно использовать цикл:

$a_all_routes = []
$n_last_found = 0

while $b_true do
    $n_pos = find("Маршрут № ", $n_last_found)
    if not $b_res then
        break
    end

    # Устанавливаем старт для поиска внутри этого маршрута
    set $n_last_found = $n_pos + 1

    # Обработка одного маршрута
    $s_route_number = find_between("Маршрут № ", " «", $n_pos)
    # ... извлечение расписания ...

    add_to_array $a_all_routes, $s_route_number + ": " + $s_rasp_forward
end

$s_result = join $a_all_routes with " | "
return $s_result

Такой подход универсален и работает при любом количестве маршрутов.