Текст між двома тегами


23

Я хочу отримати те, що знаходиться між цими двома тегами <tr> </tr>- від html doc. Тепер у мене немає жодних специфічних вимог html, які б відповідали на html-аналізатор. Мені просто потрібно щось, що відповідає, <tr>і </tr>отримує все між ними, і може бути декілька trs. Я спробував awk, який працює, але чомусь це в кінцевому підсумку дає мені дублікати кожного видобутого рядка.

awk '
/<TR/{p=1; s=$0}
p && /<\/TR>/{print $0 FS s; s=""; p=0}
p' htmlfile> newfile

Як про це піти?


IIUC ваш AWK сценарій повинен бути: '/<tr/{p=1}; p; /<\/tr>/{p=0}'. Опублікуйте приклад прикладу та очікуваний вихід, якщо він не працює.
Тор

оскільки ваша awkробота працює, але даючи дублікати, спробуйте передати вихідні дані, sort -uщоб їх розрізнити
igiannak

Відповіді:


14

Якщо ви хочете ...все <tr>...</tr>зробити:

grep -o '<tr>.*</tr>' HTMLFILE | sed 's/\(<tr>\|<\/tr>\)//g' > NEWFILE

Для багаторядкових:

tr "\n" "|" < HTMLFILE | grep -o '<tr>.*</tr>' | sed 's/\(<tr>\|<\/tr>\)//g;s/|/\n/g' > NEWFILE

Спершу перевірте HTMLFILE із заголовка "|" (не звичайна, але можлива), і якщо вона існує, перейдіть на ту, яка не існує.


1
Це працюватиме лише в тому випадку, якщо початковий і кінцевий теги знаходяться в одному рядку.
l0b0

echo "bla<tr>foo</tr>bla<tr>bar</tr>bla" | grep -o '<tr>.*</tr>' | sed 's/\(<tr>\|<\/tr>\)//g'дає fooblabar. Не blaповинно бути там?
NN

@ l0b0 правильно. піде на сумісність для рядків ...
xx4h

grep -Po '<tr>.*?</tr>'повертав би один результат на рядок у випадку @ NN, але він не є портативним.
l0b0

Я не впевнений, що ви маєте на увазі під "specs" чи "spec-style", але зауважте, що ваш веб-браузер використовує html-аналізатор, а html-аналізатор розбере html незалежно від того, як це написано. Він не буде розбирати речі, які не є html, але тоді і ваш браузер не буде працювати, тому ніхто не заважає писати "html", що аналізатор не може розібрати. Іншими словами: Гідний аналізатор - це, безумовно, найкраща ставка для цього.
goldilocks

11

У вас є вимога, яка гарантує аналіз HTML: вам потрібно розібратися в HTML. HTML Perl :: TreeBuilder , Python's BeautifulSoup та інші прості у використанні, простіші, ніж написання складних і крихких регулярних виразів.

perl -MHTML::TreeBuilder -le '
    $html = HTML::TreeBuilder->new_from_file($ARGV[0]) or die $!;
    foreach ($html->look_down(_tag => "tr")) {
        print map {$_->as_HTML()} $_->content_list();
    }
' input.html

або

python -c 'if True:
    import sys, BeautifulSoup
    html = BeautifulSoup.BeautifulSoup(open(sys.argv[1]).read())
    for tr in html.findAll("tr"):
        print "".join(tr.contents)
' input.html

9

sedі awkвони не дуже підходять для цього завдання, вам слід скористатися належним html-аналізатором. Наприклад hxselectз w3.org:

<htmlfile hxselect -s '\n' -c 'tr'

Я не знаю, якщо hxselect - найкращий вибір; Я не використовував його, але на сторінці man пишеться, що він «читає добре сформований XML-документ», якого немає у багатьох HTML-документах. Напевно, варто спробувати тхо. Значення html-парсера для perl, python тощо. ін. буде набагато краще, якщо це варіант.
goldilocks

2
@goldilocks: найкращий вибір залежить від ситуації. З мого досвіду, hxselectце дуже добре справляється з добре сформованими документами html / xml. Також швидше використовувати, ніж perl, python та інші. Я думаю hxselect, що це хороший середина між sed/ awkі парсером libs.
Тор

1
Якщо це працює, це чудово! Я просто додавав застереження для TechJack у випадку, якщо цього не сталося - оскільки я також рекомендував використовувати якийсь аналіз;
goldilocks

Тор, hxselectдобре виглядає, обов'язково вивчить його більше. Спасибі.
TechJack

@goldilocks: hxnormalizeпіклується про не добре сформовані файли html / xml.
tokland

5

Якщо rubyє, ви можете зробити наступне

ruby -e 'puts readlines.join[/(?<=<tr>).+(?=<\/tr>)/m].gsub(/<\/?tr>/, "")' file

де fileваш вхідний html-файл. Команда виконує однолінійку Ruby. По- перше, він читає все рядки з fileі з'єднує їх в рядок readlines.join. Потім з рядка вона вибирає що - небудь між (але не включаючи) <tr>та <\/tr>що один символ або більш незалежно від символів нового рядка [/(?<=<tr>).+(?=<\/tr>)/m]. Потім він видаляє будь-який рядок <tr>або </tr>з рядка gsub(/<\/?tr>/, "")(це необхідно для обробки вкладених trтегів). Нарешті, він виводить рядок, puts.

Ви сказали , що HTML - парсер не є виправданим для вас , але це дуже простий у використанні Nokogiri з , rubyі це робить команду простіше.

ruby -rnokogiri -e 'puts Nokogiri::HTML(readlines.join).xpath("//tr").map { |e| e.content }' file

-rnokogiriвантажі Нокогірі. Nokogiri::HTML(readlines.join)читає всі рядки з file. xpath("//tr")вибирає кожен trелемент і map { |e| e.content }підбирає вміст для кожного елемента, тобто те, що знаходиться між <tr>і </tr>.


1

grep

Щоб отримати вміст trтегу в декількох рядках, перейдіть його xargs, наприклад:

curl -sL https://www.iana.org/ | xargs | egrep -o "<tr>.*?</tr>"

Щоб повернути лише внутрішній HTML, використовуйте:

curl -sL https://www.iana.org/ | xargs | grep -Po "<tr>\K(.*?)</tr>" | sed "s/..tr.//g"

Перевірте синтаксис на perlreрозширені шаблони .

Примітка. Для швидшого виконання роботи ви можете розглянути, ripgrepякий має подібний синтаксис.


вона надрукована приємніше, не дивлячись на xargs, корисно було знайти вбудований JavaScript за допомогою egrep -o "<script. *? </script>"
Андрій

0

pup

Приклад використання pup(для якого використовуються селектори CSS ):

pup -f myfile.html tr

Щоб надрукувати тільки текст без тегів, використання: pup -f myfile.html tr text{}.

Ось кілька прикладів із curl:

curl -sL https://www.iana.org/ | pup tr text{}
pup -f <(curl -sL https://www.iana.org/) tr text{}

xpup

Приклад використання xpupдля розбору HTML / XML (який підтримує XPath):

xpup -f myfile.html "//tr"

0

якщо це лише швидкий перелік <tr>s, це може допомогти:

perl -ne 'print if /<tr>/../</tr>/' your.html > TRs.log

ура

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.