Как использовать grep и cut в скрипте для получения URL сайта из файла HTML

21

Я пытаюсь использовать grep и cut для извлечения URL-адресов из файла HTML. Ссылки выглядят так:

<a href="http://examplewebsite.com/">

Другие сайты имеют .net, .govно я предполагаю, что я мог бы сделать точку отсечки прямо перед >. Так что я знаю, что могу использовать grep и cut как-то, чтобы отключить все до http и после .com, но я застрял на нем некоторое время.

eltigre
источник
Я редактировал это. Некоторые игнорируют пробел между <и a, HTML не будет отображаться без него. Спасибо, что поймали это!
eltigre
Используйте форматирование кода (выделите текст и нажмите Ctrl-K). В противном случае <>вынуждает его отображаться как тег HTML.
Муру
почему бы не сопоставить начальную и конечную кавычки параметра href? кроме того, я считаю, что регулярные выражения не совсем подходят для HTML.
盐 友情 留 在 无 盐
Я хочу написать команду, используя специально grep и cut, чтобы сделать это. Я понимаю, что есть и другие способы, но я хотел знать о них.
eltigre
9
В общем случае разбирать HTML с помощью регулярных выражений не очень хорошая идея, поскольку HTML не является обычным языком. Если вы можете гарантировать, что HTML-код, который вы анализируете, довольно прост, а то, что вы пытаетесь извлечь, предсказуемо, вы можете сойти с рук. Но, пожалуйста, смотрите stackoverflow.com/a/1732454/4014959
PM 2Ring

Ответы:

25

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

Чтобы получить только те URL-адреса, которые находятся в hrefатрибуте <a>элементов, я считаю, что проще всего сделать это в несколько этапов. Судя по вашим комментариям, вам нужен только домен верхнего уровня, а не полный URL. В этом случае вы можете использовать что-то вроде этого:

grep -Eoi '<a [^>]+>' source.html |
grep -Eo 'href="[^\"]+"' | 
grep -Eo '(http|https)://[^/"]+'

где source.htmlфайл, содержащий HTML-код для разбора.

Этот код будет печатать все URL верхнего уровня, которые встречаются как hrefатрибуты любых <a>элементов в каждой строке. -iВариант первой grepкоманды является обеспечение того , она будет работать на обоих <a>и <A>элементов. Я полагаю, вы могли бы также дать -i2-й, grepчтобы захватить HREFатрибуты верхнего регистра , OTOH, я бы предпочел игнорировать такой сломанный HTML. :)

Для обработки содержимого http://google.com/

wget -qO- http://google.com/ |
grep -Eoi '<a [^>]+>' | 
grep -Eo 'href="[^\"]+"' | 
grep -Eo '(http|https)://[^/"]+'

выход

http://www.google.com.au
http://maps.google.com.au
https://play.google.com
http://www.youtube.com
http://news.google.com.au
https://mail.google.com
https://drive.google.com
http://www.google.com.au
http://www.google.com.au
https://accounts.google.com
http://www.google.com.au
https://www.google.com
https://plus.google.com
http://www.google.com.au

Мой вывод немного отличается от других примеров, так как я перенаправлен на австралийскую страницу Google.

PM 2Ring
источник
СПАСИБО. Теперь это именно то, что я искал. Это самый чистый способ сделать это.
eltigre
@eltigre: С удовольствием! Но, пожалуйста, примите во внимание предупреждение, с которым я связался в моем комментарии выше. :)
PM 2Ring
Я пришел к этому вопросу, ожидая легких моментов ... и вы уже полностью ударили ногтем по голове
Марк К Коуэн
Спасибо, @MarkKCowan. :) Впервые я начал писать ответ, используя awk, но потом решил, что решение на основе grep будет легче понять тем, кто не знаком с awk. И вообще, приведенный выше код короче моего кода на awk.
PM 2Ring
2
@mavavilj: Потому что OP хотел только домен верхнего уровня, поэтому после ://мы принимаем только символы перед первым /или ". Но если вы хотите увидеть полный URL, измените эту команду на grep -Eo '(http|https)://[^"]+. Другой вариант для этой строки - grep -Eo '(http|https)://[^?"]+'это отключение параметров запроса. Однако этот вариант будет по-прежнему печатать URL-адреса, содержащиеся в другом URL-адресе, в качестве параметра запроса, но они будут напечатаны в отдельной строке.
PM 2Ring
25

Не уверен, если вы ограничены в инструментах:

Но регулярное выражение, возможно, не лучший путь, как уже упоминалось, но вот пример, который я собрал:

cat urls.html | grep -Eo "(http|https)://[a-zA-Z0-9./?=_-]*" | sort -u
  • grep -E: аналогично egrep
  • grep -o: выводит только то, что было записано
  • (http | https): это либо / или
  • az: все строчные
  • А-Я: все дело выше
  • , : точка
  • \?: является ?
  • *: повторить группу [...]
  • Uniq: удалит все дубликаты

Выход:

bob@bob-NE722:~s$  wget -qO- https://stackoverflow.com/ | grep -Eo "(http|https)://[a-zA-Z0-9./?=_-]*" | sort -u
https://stackauth.com
https://meta.stackoverflow.com
https://cdn.sstatic.net/Img/svg-icons
https://stackoverflow.com
https://www.stackoverflowbusiness.com/talent
https://www.stackoverflowbusiness.com/advertising
https://stackoverflow.com/users/login?ssrc=head
https://stackoverflow.com/users/signup?ssrc=head
https://stackoverflow.com
https://stackoverflow.com/help
https://chat.stackoverflow.com
https://meta.stackoverflow.com
...

Вы также можете добавить, \dчтобы поймать другие типы чисел.

jmunsch
источник
2
IRI регулярно Используйте один из них и напугайте ОП! :)
Муру
2
@muru ... дрожи я ... Я не знаю , что сказать. Это даже реально !?
Jmunsch
4
@jmunsch, uniq просто удалите соседние дубликаты. sort -u?
JJoao
1
это прекрасно работает, лучший ответ!
Гери
@JJoao источник для сортировки -u быстрее, чем трубопровод? Просто мысленный эксперимент, я должен посмотреть. Но вы, вероятно, правы, по поводу промежуточного программного обеспечения оболочки.
jmunsch
9

Если ваш grep поддерживает регулярные выражения Perl:

grep -Po '(?<=href=")[^"]*(?=")'
  • (?<=href=")и (?=")являются обходными выражениями для hrefатрибута. Это требует -Pвыбора.
  • -o печатает соответствующий текст.

Например:

$ curl -sL https://www.google.com | grep -Po '(?<=href=")[^"]*(?=")'
/search?
https://www.google.co.in/imghp?hl=en&tab=wi
https://maps.google.co.in/maps?hl=en&tab=wl
https://play.google.com/?hl=en&tab=w8
https://www.youtube.com/?gl=IN&tab=w1
https://news.google.co.in/nwshp?hl=en&tab=wn
...

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

Мур
источник
8

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

pup 'a[href] attr{href}' < yourfile.html

Найдет все aэлементы, имеющие hrefатрибут, затем отобразит значение hrefатрибута.

Для установки pupвам нужен Go (язык программирования):

sudo apt-get install golang
sudo go get github.com/ericchiang/pup

Преимущество этого решения в том, что оно не зависит от правильного форматирования HTML .

Kroltan
источник
1
+1 за pup, время установить это ....
Марк К Коуэн
Вы также можете поместить их в файл. pup 'a.classname[href] attr{href}' < tut.html >links.md
Ахмад Авайс
1

Я нашел здесь решение , которое ИМХО намного проще и потенциально быстрее, чем было предложено здесь. Я немного настроил поддержку файлов https. Но версия TD; TR ...

PS: Вы можете заменить URL сайта на путь к файлу, и он будет работать так же.

lynx -dump -listonly -nonumbers "http://www.goggle.com" > links.txt

lynx -dump -listonly -nonumbers "some-file.html" > links.txt

Если вы просто хотите увидеть ссылки, а не помещать их в файл, попробуйте вместо этого ...

lynx -dump -listonly -nonumbers "http://www.google.com"

lynx -dump -listonly -nonumbers "some-file.html"

Результат будет выглядеть примерно так:

http://www.google.ca/imghp?hl=en&tab=wi
http://maps.google.ca/maps?hl=en&tab=wl
https://play.google.com/?hl=en&tab=w8
http://www.youtube.com/?gl=CA&tab=w1
http://news.google.ca/nwshp?hl=en&tab=wn
https://mail.google.com/mail/?tab=wm
https://drive.google.com/?tab=wo
https://www.google.ca/intl/en/options/
http://www.google.ca/history/optout?hl=en
...
etc.

Для моего случая использования это работало просто отлично. Но остерегайтесь того факта, что в настоящее время люди добавляют ссылки типа src = "// blah.tld" для CDN URI библиотек. Я не хотел видеть их в найденных ссылках.

Не нужно пытаться проверять ссылки или ссылки на другие источники, потому что "lynx -dump" по умолчанию извлекает все кликабельные ссылки с данной страницы. Поэтому единственное, что вам нужно сделать после этого, - это проанализировать результат «lynx -dump» с использованием grep, чтобы получить более чистую версию того же результата.

asiby
источник
Но вопрос гласит: «извлекать URL-адреса из файла HTML [который выглядит] как» (пример), а НЕ «извлекать URL-адреса из веб-страницы». Если ваш ответ может быть использован для файла, который находится на локальной машине, объясните, как. Пожалуйста, не отвечайте в комментариях; отредактируйте свой ответ, чтобы сделать его более понятным и полным.
G-Man говорит «Восстановить Монику»
1
Вы можете заменить URL на имя файла.
asiby
@ G-Man, почему -1? Вам нужно попробовать код самостоятельно и убедиться, что он работает и для локальных файлов. Я добавил это уточнение на случай, если оно не было очевидным.
asiby
Это очень удобно ... если вы используете xargs, стоит добавить | сортировать | Uniq, чтобы обрезать дубликаты ссылок.
Стюарт Аксон
0
wget -qO- google.com |
tr \" \\n | grep https\*://

... вероятно, будет очень хорошо. Как написано, он печатает:

http://schema.org/WebPage
http://www.google.com/imghp?hl=en&tab=wi
http://maps.google.com/maps?hl=en&tab=wl
https://play.google.com/?hl=en&tab=w8
http://www.youtube.com/?tab=w1
http://news.google.com/nwshp?hl=en&tab=wn
https://mail.google.com/mail/?tab=wm
https://drive.google.com/?tab=wo
http://www.google.com/intl/en/options/
http://www.google.com/history/optout?hl=en
https://accounts.google.com/ServiceLogin?hl=en&continue=http://www.google.com/
https://www.google.com/culturalinstitute/project/the-holocaust?utm_source=google&amp;utm_medium=hppromo&amp;utm_campaign=auschwitz_q1&amp;utm_content=desktop
https://plus.google.com/116899029375914044550

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

wget -qO- google.com |
sed '/\n/P;//!s|<a[^>]*\(https*://[^/"]*\)|\n\1\n|;D'

... или что-то в этом роде - хотя для некоторых sedвам может понадобиться заменить буквенный \nсимвол ewline для каждого из последних двух n.

Как написано, приведенная выше команда печатает:

http://www.google.com
http://maps.google.com
https://play.google.com
http://www.youtube.com
http://news.google.com
https://mail.google.com
https://drive.google.com
http://www.google.com
http://www.google.com
http://www.google.com
https://www.google.com
https://plus.google.com

... и в любом случае (но, вероятно, наиболее полезно с последним) вы можете прикрепить |sort -uфильтр до конца, чтобы получить список sortи удалить дубликаты.

mikeserv
источник
-1
echo "<a href="http://examplewebsite.com/">"|sed -r 's:<.*"::g'|sed 's:/">$::g'
Правин Кумар Б.С.
источник
Я не уверен, что эти «умные» цитаты - то, что вы намеревались там - возможно, регулярные «двойные» цитаты?
Джефф Шаллер