Самый простой способ извлечь URL-адреса из html-страницы, используя только sed или awk

Я хочу извлечь URL-адрес из тегов привязки html-файла. Это нужно сделать в BASH, используя SED/AWK. Пожалуйста, без перла.

Как это сделать проще всего?


person codaddict    schedule 10.12.2009    source источник
comment
Прочитайте это и будьте просвещены: stackoverflow.com/questions/1732348/   -  person Dennis Williamson    schedule 10.12.2009
comment
Если вы не возражаете, что: Нет гарантии, что вы найдете все URL-адреса. или Нет гарантии, что все найденные вами URL-адреса действительны. используйте один из приведенных ниже примеров. Если вы не возражаете, используйте соответствующий инструмент для работы (perl, python, ruby)   -  person Nifle    schedule 10.12.2009
comment
Мой предыдущий комментарий, конечно же, относится к любому простому решению, которое вы можете попробовать. awk достаточно мощен, чтобы выполнять эту работу, черт возьми, теоретически вы могли бы реализовать perl в awk...   -  person Nifle    schedule 10.12.2009
comment
Это похоже на одно из тех испытаний на выживание, где вам нужно прожить три дня, питаясь только термитами? Если нет, то серьезно, почему ограничение? Каждая современная система может установить по крайней мере Perl, а оттуда у вас есть вся сеть.   -  person Randal Schwartz    schedule 21.12.2009


Ответы (15)


Вы также можете сделать что-то подобное (при условии, что у вас установлен lynx)...

Версии Lynx ‹ 2.8.8

lynx -dump -listonly my.html

Версии Lynx >= 2.8.8 (любезно предоставлено @condit)

lynx -dump -hiddenlinks=listonly my.html
person Hardy    schedule 04.01.2010
comment
В Lynx 2.8.8 это стало lynx -dump -hiddenlinks=listonly my.html - person condit; 08.05.2014

Ты просил об этом:

$ wget -O - http://stackoverflow.com | \
  grep -io '<a href=['"'"'"][^"'"'"']*['"'"'"]' | \
  sed -e 's/^<a href=["'"'"']//i' -e 's/["'"'"']$//i'

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

person Greg Bacon    schedule 17.12.2009
comment
Почти идеально, но как насчет этих двух случаев: 1. Вы сопоставляете только те, которые начинаются с ‹a href ‹a title=Title href=sample›Match me‹/a› 2. Что, если в одной строке есть два якоря Я внес следующие изменения в исходное решение: code cat index.html | grep -o '‹a .*href=.*›' | sed -e 's/‹a/\n‹a/g' | sed -e 's/‹a .*href=[''']//' -e 's/['''].*$//' -e '/^$/ d' code - person Crisboot; 06.08.2012
comment
спасибо, работает на Mac по сравнению со многими другими решениями, упомянутыми выше - person Roman Chernyatchik; 20.08.2018

С помощью Xidel — инструмента для извлечения данных HTML/XML это можно сделать с помощью:

$ xidel --extract "//a/@href" http://example.com/

С преобразованием в абсолютные URL:

$ xidel --extract "//a/resolve-uri(@href, base-uri())" http://example.com/
person Ingo Karkat    schedule 13.03.2013
comment
concat ожидает 2 аргумента, но здесь только один (дан базовый URL). err:XPST0017: неизвестная функция: concat #1 Возможно, вы имели в виду: В модуле w3.org/2005/ xpath-функции: concat #2-65535 - person smihael; 24.08.2017
comment
@smihael: Ты прав, здесь это лишнее. Удалил. Спасибо, что заметили! - person Ingo Karkat; 24.08.2017

grep "<a href=" sourcepage.html
  |sed "s/<a href/\\n<a href/g" 
  |sed 's/\"/\"><\/a>\n/2'
  |grep href
  |sort |uniq
  1. Первый grep ищет строки, содержащие URL-адреса. Вы можете добавить больше элементов после, если хотите просматривать только локальные страницы, поэтому не http, а относительный путь.
  2. Первый sed добавит новую строку перед каждым тегом URL a href с \n
  3. Второй sed будет сокращать каждый URL-адрес после 2-го " в строке, заменяя его тегом /a с новой строкой. Оба sed будут давать вам каждый URL-адрес в одной строке, но есть мусор, поэтому
  4. 2-й grep href убирает беспорядок
  5. Сортировка и уникальный код дадут вам по одному экземпляру каждого существующего URL-адреса, присутствующего в sourcepage.html.
person kerkael    schedule 19.09.2012
comment
Хорошая разбивка того, что должен делать каждый шаг. - person Jeremy J Starcher; 20.09.2012

Я внес несколько изменений в решение Грега Бэкона.

cat index.html | grep -o '<a .*href=.*>' | sed -e 's/<a /\n<a /g' | sed -e 's/<a .*href=['"'"'"]//' -e 's/["'"'"'].*$//' -e '/^$/ d'

Это устраняет две проблемы:

  1. Мы сопоставляем случаи, когда якорь не начинается с href в качестве первого атрибута.
  2. Мы учитываем возможность наличия нескольких якорей в одной строке.
person Crisboot    schedule 06.08.2012
comment
Но, по крайней мере, это решает проблему, ни одно из других решений не делает - person Crisboot; 06.08.2012
comment
Лучший вариант здесь, если вы не хотите использовать Lynx и ваши анкоры не начинаются с ‹a href... - person simon; 23.02.2018

Пример, поскольку вы не предоставили образец

awk 'BEGIN{
RS="</a>"
IGNORECASE=1
}
{
  for(o=1;o<=NF;o++){
    if ( $o ~ /href/){
      gsub(/.*href=\042/,"",$o)
      gsub(/\042.*/,"",$o)
      print $(o)
    }
  }
}' index.html
person ghostdog74    schedule 10.12.2009
comment
Работает ли это для '‹a href=aktuell.de.selfhtml.org target=_blank›SELFHTML Актуэль‹/a›' - person Ralph M. Rickenbach; 10.12.2009
comment
если я скажу, что это работает (может быть, не 100%, но 99,99%) времени, вы поверите?? :). Лучше всего попробовать себя на разных страницах и посмотреть. - person ghostdog74; 10.12.2009
comment
это действительно сработало, большое спасибо за этот отличный пакет awk! - person SomniusX; 01.07.2014

Я предполагаю, что вы хотите извлечь URL-адрес из некоторого текста HTML, а не анализировать HTML (как предлагает один из комментариев). Хотите верьте, хотите нет, но кто-то уже сделал это.

OT: веб-сайт sed содержит много полезной информации и множество интересных/сумасшедших sed. скрипты. Вы даже можете играть Sokoban в sed!

person Alok Singhal    schedule 15.12.2009
comment
Это самый простой и простой ответ. Просто сделайте, например. wget http://sed.sourceforge.net/grabbag/scripts/list_urls.sed -O ~/bin/list_urls.sed && chmod +x ~/bin/list_urls.sed чтобы получить скрипт, а затем wget http://www.example.com -O - | ~/bin/list_urls.sed > example.com.urls.txt чтобы получить URL-адреса в текстовом файле! - person arjan; 19.02.2016

Вы можете сделать это довольно легко с помощью следующего регулярного выражения, которое неплохо находит URL-адреса:

\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))

Я взял его из статьи Джона Грубера о том, как найти URL-адреса в тексте.

Это позволяет вам найти все URL-адреса в файле f.html следующим образом:

cat f.html | grep -o \
    -E '\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))'
person nes1983    schedule 10.12.2009
comment
сложно и терпит неудачу, когда href выглядит так: ... HREF=somewhere.com ADD_DATE=1197958879 LAST_MODIFIED= 1249591429› ... - person ghostdog74; 10.12.2009
comment
Я попробовал это на самой странице daringfireball, и он нашел все ссылки. другие решения могут не сработать, потому что href= может быть где-то внутри обычного текста. трудно сделать это абсолютно правильно, не проанализировав HTML в соответствии с его грамматикой. - person nes1983; 10.12.2009
comment
Вам не нужно иметь кошку перед grep. Просто поместите f.html в конец grep - person monksy; 13.04.2012
comment
И grep -o может завершиться ошибкой из-за ошибки в некоторых версиях grep. - person kisp; 24.08.2013

Расширение ответа kerkael:

grep "<a href=" sourcepage.html
  |sed "s/<a href/\\n<a href/g" 
  |sed 's/\"/\"><\/a>\n/2'
  |grep href
  |sort |uniq
# now adding some more
  |grep -v "<a href=\"#"
  |grep -v "<a href=\"../"
  |grep -v "<a href=\"http"

Первый добавленный мной grep удаляет ссылки на локальные закладки.

Второй удаляет относительные ссылки на верхние уровни.

Третий удаляет ссылки, которые не начинаются с http.

Выберите и выберите, какой из них вы используете в соответствии с вашими конкретными требованиями.

person Nikhil VJ    schedule 22.09.2016

В bash должно работать следующее. Обратите внимание, что он не использует sed или awk, но использует tr и grep, оба очень стандартные, а не perl ;-)

$ cat source_file.html | tr '"' '\n' | tr "'" '\n' | grep -e '^https://' -e '^http://' -e'^//' | sort | uniq

Например:

$ curl "https://www.cnn.com" | tr '"' '\n' | tr "'" '\n' | grep -e '^https://' -e '^http://' -e'^//' | sort | uniq

генерирует

//s3.amazonaws.com/cnn-sponsored-content
//twitter.com/cnn
https://us.cnn.com
https://www.cnn.com
https://www.cnn.com/2018/10/27/us/new-york-hudson-river-bodies-identified/index.html\
https://www.cnn.com/2018/11/01/tech/google-employee-walkout-andy-rubin/index.html\
https://www.cnn.com/election/2016/results/exit-polls\
https://www.cnn.com/profiles/frederik-pleitgen\
https://www.facebook.com/cnn
etc...
person Brad Parks    schedule 01.11.2018

Перейдите к первому проходу, заменив начало URL-адресов (http) новой строкой (\nhttp). Тогда вы гарантировали себе, что ваша ссылка начинается в начале строки и является единственным URL в строке.

Остальное должно быть легко, вот пример:

sed "s/http/\nhttp/g" <(curl "http://www.cnn.com") | sed -n "s/\(^http[s]*:[a-Z0-9/.=?_-]*\)\(.*\)/\1/p"

alias lsurls='_(){ sed "s/http/\nhttp/g" "${1}" | sed -n "s/\(^http[s]*:[a-Z0-9/.=?_-]*\)\(.*\)/\1/p"; }; _'

person Community    schedule 07.12.2015

Можешь попробовать:

curl --silent -u "<username>:<password>" http://<NAGIOS_HOST/nagios/cgi-bin/status.cgi|grep 'extinfo.cgi?type=1&host='|grep "status"|awk -F'</A>' '{print $1}'|awk -F"'>" '{print $3"\t"$1}'|sed 's/<\/a>&nbsp;<\/td>//g'| column -c2 -t|awk '{print $1}'
person dpathak    schedule 11.03.2013

Вот как я попробовал это для лучшего просмотра, создайте файл оболочки и укажите ссылку в качестве параметра, он создаст файл temp2.txt.

a=$1

lynx -listonly -dump "$a" > temp

awk 'FNR > 2 {print$2}' temp > temp2.txt

rm temp

>sh test.sh http://link.com
person Abhishek Gurjar    schedule 15.04.2017
comment
Я настоятельно рекомендую использовать конвейер вместо временных файлов: lynx -listonly -dump $url | awk 'FNR › 2 {print$2}' - person Raúl Salinas-Monteagudo; 06.06.2017

Это мой первый пост, поэтому я стараюсь изо всех сил объяснять, почему я публикую этот ответ...

  1. Поскольку первые 7 ответов с наибольшим количеством голосов, 4 включают GREP, даже если в сообщении прямо говорится об использовании только sed или awk.
  2. Даже если сообщение не требует perl, пожалуйста, из-за предыдущего пункта и из-за того, что внутри grep используется регулярное выражение PERL.
  3. и потому что это самый простой способ (насколько я знаю, и требовался) сделать это в BASH.

Итак, простейший скрипт из GNU grep 2.28:

grep -Po 'href="\K.*?(?=")'

О переключателе \K на страницах MAN и INFO не было информации, поэтому я пришел здесь для ответа.... переключатель \K избавляет от предыдущих символов (и самого ключа). Имейте в виду, следуя советам из справочных страниц: это очень экспериментально, и grep -P может предупредить о нереализованных функциях.

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

Надеюсь, ребята, вы найдете это очень полезным.

Спасибо!!!

person X00D45    schedule 16.11.2017

Отказ от требования awk/sed:

  1. urlextract создан именно для такой задачи (документация).
  2. urlview — это интерактивное решение CLI (репозиторий github).
person Marek Kowalczyk    schedule 13.02.2021