Как я могу извлечь и распечатать определенные части файла HTML?

У меня есть документ, который похож на это:

<html>
<head>
<title>Hello</title>
</head>
<body>
This is a page
</body>
</html>

Я должен перечислить содержание между <html> и </html> и затем весь файл без <....> и </....> части. Как я делаю это?

0
задан 11 January 2017 в 16:17

1 ответ

Этот ответ основан на литеральном чтении вопроса. Кто-либо, кто сталкивается с этим при поиске, как просмотреть файл HTML удобным, человекочитаемым способом в терминале, должен вместо этого видеть, Как я могу предварительно просмотреть документы HTML из командной строки? Это не то, что делают методы, подробно изложенные в этом ответе.


Иногда a < или > символ появляется в файле HTML, даже когда он не предназначен для обозначения начала или конца тега. Если необходимо иметь дело с такой вещью - или, в более общем плане при необходимости в решении быть устойчивыми и работать с произвольными документами HTML - затем необходимо использовать утилиту, которая на самом деле анализирует HTML.

Однако, если Вы просто генерируете вывод для своего собственного удобства и заметите, идет ли что-то не так, как надо (и ничего ужасного не произошло бы, если Вы не заметили), затем можно сделать то, что Вы спрашиваете с любым из нескольких методов обработки текста.

Наиболее распространенные способы к тексту процесса с помощью системного входа обработки утилит Unix в качестве последовательности строк. Так как разрывы строки не имеют специального значения в HTML, я избежал этого подхода, и методы, данные в этом ответе, будут работать даже на теги, которые разделяются через строки. Однако я подчеркиваю, что это все еще приближенные решения.

Извлечение текста между <html> Теги

Эта острота Python 3 (выполняет его от Вашей оболочки) печатает весь текст в index.html это появляется после первого вхождения <html> но перед первым вхождением </html>:

python3 -c 'import pathlib; s=pathlib.Path("index.html").read_text(); e="<html>"; print(s[s.find(e)+len(e):s.find("</html>")])'

Если Вам нравится, можно не играть в гольф и улучшить это в допускающий повторное использование сценарий:

#!/usr/bin/env python3

from sys import argv
from pathlib import Path

start = '<html>'
end = '</html>'

for path in argv[1:]:
    text = Path(path).read_text()
    print(text[text.find(start) + len(start) : text.find(end)])

Если Вы сохранили сценарий как print-inside-html, Вы отметили бы его исполняемый файл как это:

chmod +x print-inside-html

И Вы работали на нем index.html как это:

./print-inside-html index.html

Можно выполнить его на нескольких файлах сразу, если Вам нравится:

./print-inside-html index.html foo.html coolstuff/index.html

Однако можно заметить что, если там ведет и запаздывает пробел между запуском и конечными тэгами, который печатается. Если Вы не хотите это, то можно использовать strip функция для удаления его. Вот измененная острота:

python3 -c 'import pathlib; s=pathlib.Path("index.html").read_text(); e="<html>"; print(s[s.find(e)+len(e):s.find("</html>")].strip())'

И, не игравший в гольф:

#!/usr/bin/env python3

from sys import argv
from pathlib import Path

start = '<html>'
end = '</html>'

for path in argv[1:]:
    text = Path(path).read_text()
    print(text[text.find(start) + len(start) : text.find(end)].strip())

Однако ни один из вышеупомянутых путей не размещает различные случаем имена тега (например, HTML вместо html) или пробел в тегах после имени. Эта далее измененная острота использует регулярные выражения для размещения обоих:

python3 -c 'import re,pathlib; s=pathlib.Path("index.html").read_text(); print(s[re.search(r"(?i)<html\s*>",s).end():re.search(r"(?i)</html\s*>",s).start()].strip())'

Не игравший в гольф:

#!/usr/bin/env python3

import re
from sys import argv
from pathlib import Path

start = re.compile(r'(?i)<html\s*>')
end = re.compile(r'(?i)</html\s*>')

for path in argv[1:]:
    text = Path(path).read_text()
    print(text[start.search(text).end() : end.search(text).start()].strip())

(?i) делает регулярные выражения нечувствительными к регистру и \s* использует любой пробел между именем тега и закрытием >. См. это руководство и этот вопрос для получения информации о функциях, использованных в том коде.

Удаление пишет сообщение, который похож на теги

Если Вы готовы рассматривать что-нибудь, что запускается с a < или </, сопровождаемый непробельным символом (который является также нет /, <, или >), сопровождаемый любым количеством символов, кроме того, >, сопровождаемый >, как тег, затем это печатает index.html с удаленными тегами:

python3 -c 'import re,pathlib; print(re.sub(r"</?[^\s/<>][^>]*>", "", pathlib.Path("index.html").read_text()))'

Это не анализирует HTML-код как таковой, и фактические правила для того, что составляет тег, являются более тонкими. Очевидно, это не будет работать ни в каком приложении, которое требует, чтобы HTML всегда был проанализирован правильно. Например, не используйте это в веб-браузере или кодируйте дезинфицирующее средство! (Действительно, не используйте его ни в какой прикладной программе или утилите общего назначения.)

Это - несколько более управляемая острота (чем те выше для извлечения текста между <html> и </html> теги). Но в случае, если Вы хотите это как хорошо отформатированный сценарий:

#!/usr/bin/env python3

import re
from sys import argv
from pathlib import Path

pattern = re.compile(r'</?[^\s/<>][^>]*>')

for path in argv[1:]:
    text = Path(path).read_text()
    print(pattern.sub('', text))

Если Вы помещаете это в названный файл remove-tagish-stuff затем эти команды отмечают его исполняемый файл и выполняют его на одном файле, затем на паре большего количества файлов сразу:

chmod +x remove-tagish-stuff
./remove-tagish-stuff index.html
./remove-tagish-stuff foo.html bar/baz.html

Это не изменяет файлы; как другой код выше, это просто производит их содержание с некоторыми удаленными частями.

При выполнении этого на большей части HTML, включая демонстрационный HTML, показанный в вопросе, Вы будете видеть много пустых строк. Вы, вероятно, захотите это, так как большинство документов было бы довольно нечитабельно со всем уплотненным вместе. Однако, если Вы хотите превратить повторенные пустые строки во всего один и удалить пробел в самом начале и конце, затем Вы могли использовать это вместо этого:

python3 -c 'import re,pathlib; s=re.sub(r"</?[^\s/<>][^>]*>","",pathlib.Path("index.html").read_text()); print(re.sub("\n{3,}","\n\n",s).strip())'

И вот то, что один, не игравший в гольф в сценарий, куда Вы передаете имена файлов как параметры командной строки (как с предыдущими сценариями):

#!/usr/bin/env python3

import re
from sys import argv
from pathlib import Path

tag = re.compile(r'</?[^\s/<>][^>]*>')
excess = re.compile('\n{3,}')

for path in argv[1:]:
    text = Path(path).read_text()
    detagged = tag.sub('', text)
    print(excess.sub('\n\n', detagged).strip())

Если Вы собираетесь использовать какой-либо из них, я рекомендую использовать самые простые, которые делают что Вы что. К тому же возможно далее "улучшить" и усложнить код для покрытия большего количества случаев- < и > при появлении в атрибутах тега например - но я избежал этого здесь. Если необходимо сделать что-нибудь как точный парсинг структуры произвольного документа HTML, то Вы не должны использовать регулярные выражения.

Почему я - я показывающий это вообще, учитывая, что команды и сценарии как показанные выше должны только когда-либо использоваться в ситуациях, которые не вообще серьезны? Это для той же основной причины, что я мог бы попытаться использовать grep найти слово в папке веб-страниц. Это является хрупким и совсем не надежным (grep -FR tallest . не соответствовал бы She's the tall<em>est</em>!), но это может иногда быть удобно, пока каждый помнит, что это ограничено.

1
ответ дан 7 November 2019 в 04:19

Другие вопросы по тегам:

Похожие вопросы: