Я использую BeautifulSoup для преобразования относительных URL-адресов в некоторых древних HTML-файлах с архивного сайта в абсолютные URL-адреса (в основном, чтобы их можно было лучше таргетировать по правилам .htaccess). У меня есть эта часть: поиск определенных тегов и их атрибутов, используйте urllib.parse.urljoin (это Python3) для исправления. Хорошо.
Тем не менее, есть и некоторые .php файлы в этой коллекции, начиная с более поздних лет существования этого сайта. В основном они используют 3-5 строк для включения других файлов .php, тогда как остальные — HTML, хотя есть некоторые исключения.
Проблема: Парсеры BeautifulSoup пытаются интерпретировать, что между <?php ?>
теги. На самом деле, бывают случаи, когда они просто выбрасывают только угловые скобки, но оставляют вопросительные знаки — поведение, на которое я хакерски обращался так:
for c in soup.contents:
c = str(c) # previously a BeautifulSoup Tag
# I don't need soup after this point, hence not reconstructing contents
c = ('<' if c.startswith('?') else '') + c
c = c + ('>' if c.endswith('?') else '')
Но в любом случае я заметил, что в целом <?php ?>
теги часто искажались, по-разному, в зависимости от парсера. Например, парсер html5lib принимает следующие строки:
<?
//echo "BEGIN PAGE: " . $_SESSION["i"]."<br>";
include ('util.php');
И интерпретирует тег как заканчивающийся на >
что закрывается <br>
,
Я бы предпочел, чтобы теги php оставались в покое. (Очевидно, что в идеальном мире парсер будет читать их и работать с любым внутренним HTML, но это похоже на слишком много!)
Возможные решения
<?php ?>
блокировать и повторно вставлять после завершения работы с BeautifulSoup, стараясь вспомнить, где они должны упасть (что может быть очень сложно, если любой из этих тысяч файлов имеет <?php echo 'foobar' ?>
в середине строки HTML, например)<?php ?>
теги от парсера, например вставляя вокруг них HTML-комментарии, а затем убирайте защиту после супаЧтобы ответить на мой собственный вопрос … 🙂
Я использовал решение № 4: программно защитить все <?php ?>
теги из парсера, вставляя вокруг них HTML-комментарии. Затем парсер пропускает интерпретацию того, что находится внутри комментария. Позже, при использовании soup.prettify()
или же soup.contents
, вывод можно просто дать прямую замену <!--<?
с <?
и аналогично для закрытия тегов.
Обратите внимание, что это не работает для тегов PHP, используемых для генерации динамического содержимого внутри определенных тегов HTML, например:
<a href= "<? echo foo_bar(); ?>" >
Текущие версии html.parser
, lxml
, а также html5lib
все интерпретируют это как серию бессмысленных атрибутов <a>
даже когда теги PHP заключены в комментарии HTML. В таких случаях я вручную извлекал теги с помощью регулярных выражений, чтобы решить мою проблему.
Других решений пока нет …