Проверка мертвых ссылок локально на статическом сайте (с помощью wget?)

Очень хороший инструмент для проверки мертвых ссылок (например, ссылок, указывающих на ошибки 404) - wget --spider. Тем не менее, у меня есть несколько другой пример использования, когда я создаю статический веб-сайт и хочу проверить наличие неработающих ссылок перед загрузкой. Точнее, я хочу проверить оба:

  • Относительные ссылки, такие как <a href="some/file.pdf">file.pdf</a>

  • Абсолютные ссылки, скорее всего, на внешние сайты, например <a href="#" onclick="location.href='http://example.com'; return false;">example</a>.

Я попробовал wget --spyder --force-html -i file-to-check.html, который читает локальный файл, рассматривает его как HTML и следует за каждой ссылкой. К сожалению, он не может относиться к относительным ссылкам в локальном HTML файле (ошибки с помощью Cannot resolve incomplete link some/file.pdf). Я попытался использовать file:// но wget не поддерживает его.

В настоящее время у меня есть хак, основанный на запуске локального веб-сервера через python3 http.serve и проверке локальных файлов через HTTP:

python3 -m http.server &
pid=$! 
sleep .5
error=0
wget --spider -nd -nv -H -r -l 1 http://localhost:8000/index.html || error=$? 
kill $pid
wait $pid
exit $error

Я не очень доволен этим по нескольким причинам:

  • Мне нужен этот sleep.5 чтобы ждать, пока веб-сервер будет готов. Без него сценарий терпит неудачу, но я не могу гарантировать, что будет достаточно 0,5 секунд. Я предпочел бы иметь способ запустить команду wget когда сервер будет готов.

  • И наоборот, это kill $pid кажется уродливым.

В идеале, у python3 -m http.server будет возможность запускать команду, когда сервер будет готов, и выключится после завершения команды. Это звучит выполнимо, написав немного Python, но мне было интересно, существует ли более чистое решение.

Я что-то пропустил? Есть ли лучшее решение? Я упоминаю wget в своем вопросе, потому что он делает почти то, что я хочу, но использование wget не является обязательным требованием для меня (и не является python -m http.server). Мне просто нужно что-то легко запускать и автоматизировать в Linux.

Ответ 1

Поэтому я думаю, что вы работаете в правильном направлении. Я бы использовал wget и python поскольку они являются двумя доступными параметрами для многих систем. И хорошая часть состоит в том, что он выполняет работу для вас. Теперь вы хотите прослушивать Serving HTTP on 0.0.0.0 из stdout этого процесса.

Поэтому я бы начал процесс, используя что-то вроде ниже

python3 -u -m http.server > ./myserver.log &

Обратите внимание на -u я использовал здесь для небуферизованного вывода, это действительно важно

Теперь следующий ждет, пока этот текст появится в myserver.log

timeout 10 awk '/Serving HTTP on 0.0.0.0/{print; exit}' <(tail -f ./myserver.log)

Таким образом, 10 секунд - это ваше максимальное время ожидания здесь. И отдых не требует объяснений. Далее о вашем kill $pid. Я не думаю, что это проблема, но если вы хотите, чтобы это было больше похоже на то, как пользователь это делает, я бы изменил ее на

kill -s SIGINT $pid

Это будет эквивалентно обработке CTRL+C после запуска программы. Также я бы обработал скрипт SIGINT my bash, используя что-то вроде ниже

https://unix.stackexchange.com/questions/313644/execute-command-or-function-when-sigint-or-sigterm-is-send-to-the-parent-script/313648

Вышеприведенное в основном добавляет ниже вершины сценария bash, чтобы обработать вас, убивая скрипт, используя CTRL+C или внешний сигнал об удалении

#!/bin/bash
exit_script() {
    echo "Printing something special!"
    echo "Maybe executing other commands!"
    trap - SIGINT SIGTERM # clear the trap
    kill -- -$$ # Sends SIGTERM to child/sub processes
}

trap exit_script SIGINT SIGTERM

Ответ 2

Ответ Таруна Лалвани правильный, и, следуя приведенным советам, можно написать чистый и короткий сценарий оболочки (полагаясь на Python и awk). Другое решение - полностью написать сценарий в Python, предоставляя несколько более подробный, но, возможно, более чистый скрипт. Сервер можно запустить в потоке, затем выполняется команда проверки веб-сайта, и, наконец, сервер отключается. Нам не нужно разбирать текстовый вывод и больше не отправлять сигнал на внешний процесс. Таким образом, ключевые части сценария:

def start_server(port,
                 server_class=HTTPServer,
                 handler_class=SimpleHTTPRequestHandler):
    server_address = ('', port)
    httpd = server_class(server_address, handler_class)
    thread = threading.Thread(target=httpd.serve_forever)
    thread.start()
    return httpd

def main(cmd, port):
    httpd = start_server(port)
    status = subprocess.call(cmd)
    httpd.shutdown()
    sys.exit(status)

Я написал несколько более продвинутый скрипт (с небольшим количеством синтаксического анализа командной строки поверх этого) и опубликовал его как: https://gitlab.com/moy/check-links