Очень хороший инструмент для проверки мертвых ссылок (например, ссылок, указывающих на ошибку 404) - это wget --spider
. Однако у меня есть несколько другой вариант использования, когда я создаю статический веб-сайт и хочу проверить неработающие ссылки перед загрузкой. Точнее, хочу проверить оба:
Относительные ссылки, например
<a href="some/file.pdf">file.pdf</a>
Абсолютные ссылки, скорее всего, на внешние сайты, такие как
<a href="http://example.com">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.
2 ответа
Так что я думаю, вы идете в правильном направлении. Я бы использовал 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
мой сценарий bash, используя что-то вроде ниже
Вышеупомянутое в основном добавляет ниже в начало сценария 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
Ответ Таруна Лалвани правильный, и, следуя приведенным там советам, можно написать чистый и короткий сценарий оболочки (опираясь на 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
Похожие вопросы
Новые вопросы
python
Python - это многопарадигмальный, динамически типизированный, многоцелевой язык программирования. Он разработан для быстрого изучения, понимания и использования, а также для обеспечения чистого и единообразного синтаксиса. Обратите внимание, что Python 2 официально не поддерживается с 01.01.2020. Тем не менее, для вопросов о Python, связанных с версией, добавьте тег [python-2.7] или [python-3.x]. При использовании варианта Python (например, Jython, PyPy) или библиотеки (например, Pandas и NumPy) включите его в теги.