У меня есть исходный файл html, в котором мне нужно извлечь ссылки внутри них, число количество ссылок варьируется от файла к файлу, и ссылки отформатированы как таковые и заключены в одинарные кавычки:
../xxx/yyy/ccc/bbbb/nameoffile.extension
Мне нужно получить текст между одинарными кавычками, заменить ..
на http: / /
и вывести результат в файл.
Я новичок и ищу решение для автоматизации этого процесса в терминале.
его исходные файлы html и ссылки находятся повсюду в файле, мне нужно получить их по одной ссылке на каждую строку, выводимую в файле, чтобы передать их существующему xargs curl для загрузки.
образец файла выглядит примерно так:
<head>
<body>
<html>
blabla
</>
blibli afg fgfdg sdfg <b> blo blo href= '../xxx/yyy/ccc/bbbb/nameoffile1.extension' target blibli bloblo href= '../xxx/yyy/ccc/bbbb/nameoffile2.extension' blibli
bloblo href= '../xxx/yyy/ccc/bbbb/nameoffile3.extension'
…
результат поиска - это файл, содержащий следующее:
http://z.z.com/xxx/yyy/ccc/bbbb/nameoffile1.extension
http://z.z.com/xxx/yyy/ccc/bbbb/nameoffile2.extension
http://z.z.com/xxx/yyy/ccc/bbbb/nameoffile3.extension
может быть кто-нибудь достаточно любезен, чтобы помочь мне найти решение, пожалуйста.
исходный файл как можно ближе:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><HTML>
<HEAD>
<TITLE>Inter num num - nil</TITLE>
<link rel="stylesheet" type="text/css" href="style.css" />
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
</HEAD>
<BODY><table width=1200 align=center class=tabForm><tr><td align=left width=largeur_2 valign=top><img src=Img/logo.gif><br /></td><td align=center valign=center width=largeur_6><h1><font color='#CB150A'>Test d'épreuve</font></h1></td><td align=right valign=top width=largeur_2 class=dataLabel>Reçu le 11/03/2018 à 17:49<br /></td></tr>
<tr><td width=1200 colspan=3 align=center><b><font color='#CB150A' size=+1>Client : zzz - Référence : 232323 - Désignation : Fiche d'accueil </font></b></color></td></tr>
</table><BR/><table width=1200 align=center class=tabForm><tr><td class=dataLabelBig width=1200>M numnum ,<BR/><BR/>
Job citée ci-dessus.<BR/>
ci-joints toutes les informations nécessaires.
<BR/><BR/>
Sandy Jan<BR/>
test@test.com</font></td></tr></table><br /><table width=1200 align=center class=tabForm><tr><td colspan=2 width=1200 class=dataLabel>Documents nécessaires à votre réponse</td></tr><tr><td colspan=2 width=1200 class=dataLabel><u><b>Job :</b></u> Suivi Travaux - <u><b>Article :</b></u> 232323 - Fiche d'accueil</td></tr><tr><td colspan=2 width=1200 class=dataLabel><a href='../path/path/path/path/path.html' target=_blank><img src=Img/pdf.png border=0> Fiche.html</a></td></tr><tr><td colspan=2 width=1200 class=dataLabel><a href='../path/path/path/path/pathd%27accueil%20traitant-20160621163240.pdf' target=_blank><img src=Img/pdf.png border=0> text.pdf</a></td></tr><tr><td colspan=2 width=1200 class=dataLabel><a href='../path/path/path/path/pathla%20S%E9curit%E9%20%281%29.doc' target=_blank><img src=Img/pdf.png border=0> Fiched'accueil.doc</a></td></tr></table><br /><table width=1200 align=center class=tabForm><tr><td colspan=2 class=dataLabelRed width=1200 >Notre commentaire</td></tr></tr><td colspan=2 class=dataLabel>mise a jour - Attention<br />
Impression <br /><br /></td></tr></table><br /><table width=1200 align=center class=tabForm><form method=post name=formvolume action=?&dossier=111734&coo=135&auth=b182f10b82ba&key=2e7c69213b28d7de6655&action=submit&type=volume enctype=multipart/form-data ><tr><td width=1200 align=left colspan=2 class=dataLabel><h3><img src=Img/h3Arrow.gif border=0> Remise de job :</h3><br /></td></tr><tr><td align=left valign=top width=120 class=dataLabelRed>Votre commentaire</td><td width=1080 align=left class=dataLabel><textarea cols=200 rows=5 name=comment ></textarea></td></tr><tr><td align=left width=120 class=dataLabelRed>Votre fichier</td><td width=1080 align=left><input type=file name=fichier size=82></td></tr><tr><td align=center colspan=2 width=1200><br /><input type=button class=button value=" Remettre votre réponse " onClick="javascript: var ok=confirm('Etes vous certain de vouloir effectuer cette action ?');if(ok==true){ document.formvolume.submit();}else {return false}" ></form></td></tr><table></table></br><table width=1200 align=center class=tabForm><form method=post name=formvolume_complement action=?&dossier=111734&coo=135&auth=b182f10b82ba&key=2e7c69213b28d7de6655&action=submit_complement&type=volume enctype=multipart/form-data ><tr><td width=1200 align=left colspan=2 class=dataLabel><h3><img src=Img/h3Arrow.gif border=0> Demande de complément, votre réponse :</h3><br /></td></tr><tr><tr><td align=left valign=top width=120 class=dataLabelRed>Votre commentaire</td><td width=1080 align=left class=dataLabel><textarea cols=200 rows=5 name=comment ></textarea></td></tr><td align=left width=120 class=dataLabelRed>Votre fichier</td><td width=1080 align=left><input type=file name=fichier size=82></td></tr><tr><td align=center colspan=2 width=1200><br /><input type=button class=button value=" Remettre votre réponse " onClick="javascript: var ok =confirm('Etes v ?');if(ok==true){ document.formvolume_complement.submit();}else {return false}" ></form></td></tr><table></table></BODY></HTML></BODY>
</HTML>
Утилиты как sed
, awk
и т.д. не сделаны для парсинга структурированных данных, таких как HTML. Следовательно намного более эффективное решение состояло бы в том, чтобы использовать Python, чтобы сделать то же.
Во-первых, удостоверьтесь, что BeautifulSoup установлен:
sudo apt-get install python3 python3-bs4
Теперь создайте новый файл (например, test.py
) и вставьте короткий сценарий, который я записал с этой целью:
#!/usr/bin/env python3
import sys
from bs4 import BeautifulSoup
DOMAIN = 'z.z.com/'
if len(sys.argv)<2 or not sys.argv[1].endswith('.html'):
print("Argument not provided or not .html file", file=sys.stderr)
exit()
with open(sys.argv[1], 'r', encoding='latin-1') as f:
webpage = f.read()
soup = BeautifulSoup(webpage, "lxml")
for a in soup.findAll('a', href=True):
print(a['href'].replace("../","http://"+DOMAIN))
Версия Python 2 по запросу:
#!/usr/bin/env python2
import sys
from bs4 import BeautifulSoup
DOMAIN = 'z.z.com/'
if len(sys.argv)<2 or not sys.argv[1].endswith('.html'):
print >> sys.stderr, "Argument not provided or not .html file"
exit()
with open(sys.argv[1], 'rb') as f:
webpage = f.read().decode("latin-1")
soup = BeautifulSoup(webpage, "html.parser")
for a in soup.findAll('a', href=True):
print(a['href'].replace("../","http://"+DOMAIN))
Измените DOMAIN
переменная для соответствия фактическому домену сохраните этот сценарий в текущем каталоге и выполните его следующим образом:
./test.py yourfile.html > outputfile
Для ссылки это - вывод, произведенный сценарием при выполнении его с обеспеченным примером в вопросе:
http://z.z.com/path/path/path/path/path.html
http://z.z.com/path/path/path/path/pathd%27accueil%20traitant-20160621163240.pdf
http://z.z.com/path/path/path/path/pathla%20S%E9curit%E9%20%281%29.doc
Другое решение для Perl, которое использует надлежащий синтаксический анализатор HTML, следующее (сказать get-links.pl
):
#!/usr/bin/env perl
use strict;
use warnings;
use File::Spec;
use WWW::Mechanize;
my $filename = shift or die "Must supply a *.html file\n";
my $absolute_filename = File::Spec->rel2abs($filename);
my $mech = WWW::Mechanize->new();
$mech->get( "file://$absolute_filename" );
my @links = $mech->links();
foreach my $link ( @links ) {
my $new_link = $link->url;
if ( $new_link =~ s(^\.\./)(http://z.z.com/) ) {
print "$new_link\n";
}
}
Вы, возможно, должны установить WWW::Mechanize
модуль сначала, потому что это не базовый модуль (значение его не установлено по умолчанию вместе с Perl). Для этого выполненный
sudo apt install libwww-mechanize-perl
Сценарий читает данный файл, преобразовывает имя файла в полный путь (потому что мы хотим создать надлежащий URI как file:///path/to/source.html
).
После извлечения ссылок (my @links = $mech->links();
) это исследует URL каждой ссылки и если это запускается с ../
затем та часть заменяется http://z.z.com/
и распечатанный.
Использование:
./get-links.pl source.html
Вывод:
http://z.z.com/path/path/path/path/path.html
http://z.z.com/path/path/path/path/pathd%27accueil%20traitant-20160621163240.pdf
http://z.z.com/path/path/path/path/pathla%20S%E9curit%E9%20%281%29.doc
Как @Amith KK уже сказал в его ответе: Парсинг HTML (или XML) лучше всего сделан с надлежащим синтаксическим анализатором потому что инструменты как sed
и их вид может перестать работать, когда существуют другие элементы в источнике, которые похожи на ссылку, но не являются.
Извлечь данные между одинарными кавычками из файла test.html
с заменой двух точек ..
в URL с http://
и сохранять извлеченные данные в файл newfile.txt
сделайте:
cat test.html | sed -ne 's/^.*'\''\([^'\'']*\)'\''.*$/\1/p' | sed -e 's/\.\./http:\//g' > newfile.txt
Или попробуйте без sed:
cat test.html | grep -Eo "'[^'() ]+'" | tr -d \'\" | perl -pe 's/../http:\//' > newfile.txt
Это работает на образец файла, добавленный к вопросу автором:
cat test.html | grep -Eo "'[^|'() ]+'" | grep -wE "('..)" | tr -d \'\" | perl -pe 's/../http:\/\/mysite.mydomain.com/' > newfile.txt
Как упомянуто в комментариях необходимо преобразовать html
к текстовому формату. Для этого существует острота, которая должна покрыть все основания:
sed 's/ / /g; s/&/\&/g; s/</\</g; s/>/\>/g; s/"/\"/g; s/#'/\'"'"'/g; s/“/\"/g; s/”/\"/g;'
При преобразовании 100 с тысяч строк встроенные команды удара много раз быстрее:
#-------------------------------------------------------------------------------
LineOut="" # Make global
HTMLtoText () {
LineOut=$1 # Parm 1= Input line
# Replace external command: Line=$(sed 's/&/\&/g; s/</\</g;
# s/>/\>/g; s/"/\"/g; s/'/\'"'"'/g; s/“/\"/g;
# s/”/\"/g;' <<< "$Line") -- With faster builtin commands.
LineOut="${LineOut// / }"
LineOut="${LineOut//&/&}"
LineOut="${LineOut//</<}"
LineOut="${LineOut//>/>}"
LineOut="${LineOut//"/'"'}"
LineOut="${LineOut//'/"'"}"
LineOut="${LineOut//“/'"'}" # TODO: ASCII/ISO for opening quote
LineOut="${LineOut//”/'"'}" # TODO: ASCII/ISO for closing quote
} # HTMLtoText ()
Чтобы протестировать, если файл существует, используют производную этой функции:
function validate_url(){
if [[ `wget -S --spider $1 2>&1 | grep 'HTTP/1.1 200 OK'` ]]; then echo "true"; fi
}
Заключительный сценарий все еще должен быть записан на основе демонстрационных данных, полученных из допустимой веб-страницы с допустимыми именами файлов.