Saya ingin program baris perintah yang mencetak judul situs web. Untuk misalnya:
Alan:~ titlefetcher http://www.youtube.com/watch?v=Dd7dQh8u4Hc
harus memberi:
Why Are Bad Words Bad?
Anda memberikan url dan mencetak Judul.
Saya ingin program baris perintah yang mencetak judul situs web. Untuk misalnya:
Alan:~ titlefetcher http://www.youtube.com/watch?v=Dd7dQh8u4Hc
harus memberi:
Why Are Bad Words Bad?
Anda memberikan url dan mencetak Judul.
Jawaban:
wget -qO- 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' |
perl -l -0777 -ne 'print $1 if /<title.*?>\s*(.*?)\s*<\/title/si'
Anda dapat mengirimkannya ke GNU recode
jika ada hal-hal seperti <
di dalamnya:
wget -qO- 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' |
perl -l -0777 -ne 'print $1 if /<title.*?>\s*(.*?)\s*<\/title/si' |
recode html..
Untuk menghapus - youtube
bagian:
wget -qO- 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' |
perl -l -0777 -ne 'print $1 if /<title.*?>\s*(.*?)(?: - youtube)?\s*<\/title/si'
Untuk menunjukkan beberapa batasan:
Tidak ada perintah standar / portabel untuk melakukan permintaan HTTP. Beberapa dekade yang lalu, saya akan merekomendasikan di lynx -source
sini. Tetapi saat ini, wget
lebih portabel karena dapat ditemukan secara default pada sebagian besar sistem GNU (termasuk sebagian besar sistem operasi desktop / laptop berbasis Linux). Yang cukup portabel lainnya termasuk GET
perintah yang datang dengan perl
libwww yang sering diinstal lynx -source
,, dan pada tingkat lebih rendah curl
. Lainnya umum yang meliputi links -source
, elinks -source
, w3m -dump_source
, lftp -c cat
...
wget
mungkin tidak mendapatkan halaman yang sama dengan yang misalnya firefox
akan ditampilkan. Alasannya adalah bahwa server HTTP dapat memilih untuk mengirim halaman yang berbeda berdasarkan informasi yang disediakan dalam permintaan yang dikirim oleh klien.
Permintaan yang dikirim oleh wget / w3m / GET ... akan berbeda dari yang dikirim oleh firefox. Jika itu masalah, Anda bisa mengubah wget
perilaku untuk mengubah cara mengirimkan permintaan melalui opsi.
Yang paling penting dalam hal ini adalah:
Accept
dan Accept-language
: yang memberi tahu server tempat bahasa dan rangkaian karakter yang diinginkan klien untuk mendapatkan respons. wget
tidak mengirim apa pun secara default sehingga server biasanya akan mengirim dengan pengaturan default. firefox
di sisi lain kemungkinan dikonfigurasi untuk meminta bahasa Anda.User-Agent
: yang mengidentifikasi aplikasi klien ke server. Beberapa situs mengirim konten berbeda berdasarkan klien (meskipun itu sebagian besar untuk perbedaan antara interpretasi bahasa javascript) dan mungkin menolak untuk melayani Anda jika Anda menggunakan robot seperti agen pengguna wget
.Cookie
: jika Anda pernah mengunjungi situs ini sebelumnya, browser Anda mungkin memiliki cookie permanen untuk itu. wget
tidak akan.wget
akan mengikuti pengalihan ketika mereka dilakukan di tingkat protokol HTTP, tetapi karena tidak melihat konten halaman, bukan yang dilakukan oleh javascript atau hal-hal seperti <meta http-equiv="refresh" content="0; url=http://example.com/">
.
Di sini, karena malas, kami telah perl
membaca seluruh konten dalam memori sebelum mulai mencari <title>
tag. Mengingat bahwa judul ditemukan di <head>
bagian yang ada di beberapa byte pertama file, itu tidak optimal. Pendekatan yang lebih baik, jika GNU awk
tersedia di sistem Anda bisa:
wget -qO- 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' |
gawk -v IGNORECASE=1 -v RS='</title' 'RT{gsub(/.*<title[^>]*>/,"");print;exit}'
Dengan begitu, awk berhenti membaca setelah yang pertama </title
, dan dengan keluar, menyebabkan wget
berhenti mengunduh.
Di sini, wget
tulis halaman saat mengunduhnya. Pada saat yang sama perl
,, slurps output ( -0777 -n
) seluruh dalam memori dan kemudian cetak kode HTML yang ditemukan antara kejadian pertama <title...>
dan </title
.
Itu akan berfungsi untuk sebagian besar halaman HTML yang memiliki <title>
tag, tetapi ada kasus di mana itu tidak akan berfungsi.
Sebaliknya , solusi coffeeMug akan mem-parsing halaman HTML sebagai XML dan mengembalikan nilai yang sesuai untuk title
. Lebih tepat jika halaman dijamin XML yang valid . Namun, HTML tidak harus merupakan XML yang valid (versi bahasa yang lebih lama tidak), dan karena sebagian besar peramban di luar sana lunak dan akan menerima kode HTML yang salah, bahkan ada banyak kode HTML yang salah di luar sana.
Baik solusi saya dan coffeeMug akan gagal untuk berbagai kasus sudut, kadang-kadang sama, kadang tidak.
Misalnya, milik saya akan gagal pada:
<html><head foo="<title>"><title>blah</title></head></html>
atau:
<!-- <title>old</title> --><title>new</title>
Sementara itu akan gagal pada:
<TITLE>foo</TITLE>
(html valid, bukan xml) atau:
atau:
<title>...</title>
...
<script>a='<title>'; b='</title>';</script>
(lagi, valid html
, <![CDATA[
bagian yang hilang untuk menjadikannya XML yang valid).
<title>foo <<<bar>>> baz</title>
(html salah, tetapi masih ditemukan di sana dan didukung oleh sebagian besar browser)
Solusi itu menampilkan teks mentah antara <title>
dan </title>
. Biasanya, seharusnya tidak ada tag HTML di sana, mungkin ada komentar (meskipun tidak ditangani oleh beberapa browser seperti firefox jadi sangat tidak mungkin). Mungkin masih ada beberapa penyandian HTML:
$ wget -qO- 'http://www.youtube.com/watch?v=CJDhmlMQT60' |
perl -l -0777 -ne 'print $1 if /<title.*?>\s*(.*?)\s*<\/title/si'
Wallace & Gromit - The Cheesesnatcher Part 1 (claymation) - YouTube
Yang diurus oleh GNU recode
:
$ wget -qO- 'http://www.youtube.com/watch?v=CJDhmlMQT60' |
perl -l -0777 -ne 'print $1 if /<title.*?>\s*(.*?)\s*<\/title/si' |
recode html..
Wallace & Gromit - The Cheesesnatcher Part 1 (claymation) - YouTube
Tetapi klien web juga dimaksudkan untuk melakukan lebih banyak transformasi pada kode itu ketika menampilkan judul (seperti menyingkat beberapa bagian yang kosong, menghapus yang utama dan yang tertinggal). Namun tidak mungkin ada kebutuhan untuk itu. Jadi, seperti dalam kasus lain, terserah Anda memutuskan apakah itu sepadan dengan usaha.
Sebelum UTF-8, iso8859-1 digunakan untuk menjadi charset pilihan di web untuk karakter non-ASCII meskipun secara tegas mereka harus dituliskan sebagai é
. Versi HTTP dan bahasa HTML yang lebih baru telah menambahkan kemungkinan untuk menentukan karakter yang ditetapkan dalam header HTTP atau dalam header HTML, dan klien dapat menentukan charset yang diterimanya. UTF-8 cenderung menjadi charset default saat ini.
Jadi, itu berarti bahwa di luar sana, Anda akan menemukan é
ditulis sebagai é
, seperti é
, seperti UTF-8 é
, (0xc3 0xa9), seperti iso-8859-1 (0xe9), dengan untuk 2 yang terakhir, kadang-kadang informasi di charset di header HTTP atau header HTML (dalam format berbeda), terkadang tidak.
wget
hanya mendapatkan byte mentah, tidak peduli tentang artinya sebagai karakter, dan tidak memberi tahu server web tentang charset yang disukai.
recode html..
akan berhati-hati untuk mengubah é
atau é
menjadi urutan byte yang tepat untuk set karakter yang digunakan pada sistem Anda, tetapi untuk sisanya, itu lebih sulit.
Jika charset sistem Anda utf-8, kemungkinan itu akan baik-baik saja sebagian besar waktu karena cenderung menjadi charset default yang digunakan di luar sana saat ini.
$ wget -qO- 'http://www.youtube.com/watch?v=if82MGPJEEQ' |
perl -l -0777 -ne 'print $1 if /<title.*?>\s*(.*?)\s*<\/title/si'
Noir Désir - L'appartement - YouTube
Itu di é
atas adalah UTF-8 é
.
Tetapi jika Anda ingin menutupi untuk rangkaian karakter lain, sekali lagi, itu harus diurus.
Perlu juga dicatat bahwa solusi ini tidak akan berfungsi sama sekali untuk halaman yang disandikan UTF-16 atau UTF-32.
Idealnya, yang Anda butuhkan di sini, adalah browser web asli untuk memberi Anda informasi. Artinya, Anda perlu melakukan sesuatu untuk melakukan permintaan HTTP dengan parameter yang tepat, mengintepret respons HTTP dengan benar, sepenuhnya menafsirkan kode HTML seperti yang dilakukan browser, dan mengembalikan judul.
Karena saya tidak berpikir itu dapat dilakukan pada baris perintah dengan browser yang saya tahu (meskipun lihat sekarang trik ini denganlynx
), Anda harus menggunakan heuristik dan perkiraan, dan yang di atas sama baiknya dengan yang ada.
Anda mungkin juga ingin mempertimbangkan kinerja, keamanan ... Misalnya, untuk mencakup semua kasus (misalnya, halaman web yang memiliki beberapa javascript yang ditarik dari situs pihak ke-3 yang menetapkan judul atau mengalihkan ke halaman lain dalam suatu onload hook), Anda mungkin harus mengimplementasikan browser kehidupan nyata dengan mesin dom dan javascript yang mungkin harus melakukan ratusan pertanyaan untuk satu halaman HTML, beberapa di antaranya mencoba untuk mengeksploitasi kerentanan ...
Meskipun menggunakan regexps untuk mem-parsing HTML sering disukai , berikut ini adalah kasus khas di mana itu cukup baik untuk tugas (IMO).
<
karena judul tidak dijamin memiliki tag akhir dan tag lain apa pun harus memaksa terminasi tersebut. Anda mungkin juga ingin menghapus garis baru.
Anda juga dapat mencoba hxselect
(dari HTML-XML-Utils ) dengan wget
sebagai berikut:
wget -qO- 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' | hxselect -s '\n' -c 'title' 2>/dev/null
Anda dapat menginstal hxselect
di distro berbasis Debian menggunakan:
sudo apt-get install html-xml-utils
.
Pengalihan STDERR adalah untuk menghindari Input is not well-formed. (Maybe try normalize?)
pesan.
Untuk menyingkirkan "- YouTube", kirimkan output dari perintah di atas ke awk '{print substr($0, 0, length($0)-10)}'
.
sudo apt-get install html-xml-utils
hxselect
.
Anda juga dapat menggunakan curl
dan grep
melakukan ini. Anda harus meminta penggunaan PCRE (Perl Compatible Regular Expressions) di grep
untuk mendapatkan tampilan belakang dan fasilitas tampilan depan sehingga kita dapat menemukan <title>...</title>
tag.
$ curl 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' -so - | \
grep -iPo '(?<=<title>)(.*)(?=</title>)'
Why Are Bad Words Bad? - YouTube
The curl
switch:
-s
= diam-o -
= kirim output ke STDOUTThe grep
switch:
-i
= tidak sensitif huruf-o
= Hanya kembalikan bagian yang cocok-P
= Mode PCREPola untuk grep
:
(?<=<title>)
= cari string yang dimulai dengan ini di sebelah kiri itu(?=</title>)
= mencari string yang diakhiri dengan ini di sebelah kanannya(.*)
= semuanya di antaranya <title>..</title>
.Jika <title>...</titie>
membentang beberapa baris, maka di atas tidak akan menemukannya. Anda dapat mengurangi situasi ini dengan menggunakan tr
, untuk menghapus \n
karakter apa pun , yaitu tr -d '\n'
.
File sampel.
$ cat multi-line.html
<html>
<title>
this is a \n title
</TITLE>
<body>
<p>this is a \n title</p>
</body>
</html>
Dan contoh dijalankan:
$ curl 'http://www.jake8us.org/~sam/multi-line.html' -so - | \
tr -d '\n' | \
grep -iPo '(?<=<title>)(.*)(?=</title>)'
this is a \n title
Jika <title>
diset seperti ini, <title lang="en">
maka Anda harus menghapus ini sebelum grep
memasukkannya. Alat sed
ini dapat digunakan untuk melakukan ini:
$ curl 'http://www.jake8us.org/~sam/multi-line.html' -so - | \
tr -d '\n' | \
sed 's/ lang="\w+"//gi' | \
grep -iPo '(?<=<title>)(.*)(?=</title>)'
this is a \n title
Di atas menemukan string tidak peka huruf besar kecil lang=
diikuti oleh urutan kata ( \w+
). Ini kemudian dilucuti.
Pada titik tertentu regex akan gagal dalam memecahkan masalah jenis ini. Jika itu terjadi maka Anda mungkin ingin menggunakan parser HTML / XML nyata. Salah satu pengurai seperti itu adalah Nokogiri . Ini tersedia di Ruby sebagai Permata dan dapat digunakan seperti:
$ curl 'http://www.jake8us.org/~sam/multi-line.html' -so - | \
ruby -rnokogiri -e \
'puts Nokogiri::HTML(readlines.join).xpath("//title").map { |e| e.content }'
this is a \n title
Di atas adalah parsing data yang datang melalui curl
HTML ( Nokogiri::HTML
). Metode ini xpath
kemudian mencari node (tag) dalam HTML yang merupakan leaf node, ( //
) dengan namanya title
. Untuk setiap yang ditemukan, kami ingin mengembalikan kontennya ( e.content
). The puts
kemudian mencetak mereka keluar.
Anda juga dapat melakukan sesuatu yang serupa dengan Perl dan modul HTML :: TreeBuilder :: XPath .
$ cat title_getter.pl
#!/usr/bin/perl
use HTML::TreeBuilder::XPath;
$tree = HTML::TreeBuilder::XPath->new_from_url($ARGV[0]);
($title = $tree->findvalue('//title')) =~ s/^\s+//;
print $title . "\n";
Anda kemudian dapat menjalankan skrip ini seperti:
$ ./title_getter.pl http://www.jake8us.org/~sam/multi-line.html
this is a \n title
<title>Unix\nLinux</title>
seharusnya Unix Linux
, bukan UnixLinux
.
Menggunakan regex sederhana untuk mem-parsing HTML adalah naif. Misalnya dengan baris baru dan mengabaikan pengkodean karakter khusus yang ditentukan dalam file. Lakukan hal yang benar dan benar-benar mengurai halaman menggunakan salah satu parser nyata lainnya yang disebutkan dalam jawaban lain atau menggunakan liner berikut:
python -c "import bs4, urllib2; print bs4.BeautifulSoup(urllib2.urlopen('http://www.crummy.com/software/BeautifulSoup/bs4/doc/')).title.text"
(Di atas termasuk karakter Unicode).
BeautifulSoup juga menangani banyak HTML yang salah (mis. Tag penutup yang hilang), yang akan membuang regexing sederhana. Anda dapat menginstalnya dalam python standar menggunakan:
pip install beautifulsoup4
atau jika Anda tidak punya pip
, dengan
easy_install beautifulsoup4
Beberapa sistem operasi seperti Debian / Ubuntu juga telah dikemas ( python-bs4
paket pada Debian / Ubuntu).
bs4
tidak ada di pustaka standar python. Anda harus menginstalnya menggunakan easy_install beautfulsoup4
(bukan easyinstall bs4
).
Mungkin itu "curang" tetapi satu opsi adalah pup, sebuah parser HTML baris perintah .
Berikut adalah dua cara untuk melakukannya:
Menggunakan meta
bidang dengan property="og:title
atribut
$ wget -q 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' -O - | \
> pup 'meta[property=og:title] attr{content}'
Why Are Bad Words Bad?
dan cara lain menggunakan title
bidang secara langsung (dan kemudian memotong - YouTube
string di akhir).
$ wget -q 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' -O - | \
> pup 'title text{}' | sed 's/ - YouTube$//'
Why Are Bad Words Bad?
--plain
opsi pup .
Tampaknya dimungkinkan dengan lynx
menggunakan trik ini ( zsh
, bash
sintaks):
lynx -cfg=<(printf '%s\n' 'PRINTER:P:printf "%0s\\n" "$LYNX_PRINT_TITLE">&3:TRUE'
) lynx 3>&1 > /dev/null -nopause -noprint -accept_all_cookies -cmd_script <(
printf '%s\n' "key p" "key Select key" "key ^J" exit
) 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc'
Karena itu adalah peramban web kehidupan nyata, itu tidak menderita dari banyak keterbatasan yang saya sebutkan dalam jawaban saya yang lain .
Di sini, kami menggunakan fakta yang lynx
menetapkan $LYNX_PRINT_TITLE
variabel lingkungan ke judul halaman saat ini saat mencetak halaman.
Di atas, kami memberikan file konfigurasi (sebagai pipa) yang mendefinisikan "printer" lynx yang disebut P
yang hanya menampilkan konten variabel tersebut ke file descriptor 3
(file deskriptor tersebut dialihkan ke lynx
stdout dengan 3>&1
sementara lynx stdout dengan sendirinya dialihkan ke / dev / null).
Kemudian kami menggunakan lynx
fasilitas scripting untuk mensimulasikan pengguna menekan p
, dan End
(alias pilih), dan Enter
( ^J
).
-accept_all_cookies
karena jika tidak, lynx akan meminta konfirmasi kepada pengguna untuk setiap cookie.
Cara sederhana:
curl -s example.com | grep -o "<title>[^<]*" | tail -c+8
Beberapa alternatif:
curl -s example.com | grep -o "<title>[^<]*" | cut -d'>' -f2-
wget -qO- example.com | grep -o "<title>[^<]*" | sed -e 's/<[^>]*>//g'
Saya menyukai gagasan Stéphane Chazelas untuk menggunakan Lynx dan LYNX_PRINT_TITLE, tetapi skrip itu tidak berfungsi untuk saya di bawah Ubuntu 14.04.5.
Saya telah membuat versi yang disederhanakan dengan menggunakan Lynx dan menggunakan file yang sudah dikonfigurasikan sebelumnya.
Tambahkan baris berikut ke /etc/lynx-cur/lynx.cfg (atau di mana pun lynx.cfg Anda berada):
PRINTER:P:printenv LYNX_PRINT_TITLE>/home/account/title.txt:TRUE:1000
Baris ini menginstruksikan untuk menyimpan judul, saat mencetak, ke "/home/account/title.txt" - Anda dapat memilih nama file yang Anda inginkan. Anda meminta SANGAT halaman yang besar, tambahkan nilai di atas dari "1000" ke sejumlah baris per halaman yang Anda inginkan, jika tidak Lynx akan membuat prompt tambahan "saat mencetak dokumen yang berisi halaman yang sangat besar".
Kemudian buat file /home/account/lynx-script.txt dengan konten berikut:
key p
key Select key
key ^J
exit
Kemudian jalankan Lynx menggunakan opsi baris perintah berikut:
lynx -term=vt100 -display_charset=utf-8 -nopause -noprint -accept_all_cookies -cmd_script=/home/account/lynx-script.txt "http://www.youtube.com/watch?v=Dd7dQh8u4Hc" >/dev/nul
Setelah menyelesaikan perintah ini, file /home/account/title.txt akan dibuat dengan judul halaman Anda.
Singkatnya, berikut adalah fungsi PHP yang mengembalikan judul halaman berdasarkan URL yang diberikan, atau false jika terjadi kesalahan.
function GetUrlTitle($url)
{
$title_file_name = "/home/account/title.txt";
if (file_exists($title_file_name)) unlink($title_file_name); // delete the file if exists
$cmd = '/usr/bin/lynx -cfg=/etc/lynx-cur/lynx.cfg -term=vt100 -display_charset=utf-8 -nopause -noprint -accept_all_cookies -cmd_script=/home/account/lynx-script.txt "'.$url.'"';
exec($cmd, $output, $retval);
if (file_exists($title_file_name))
{
$title = file_get_contents($title_file_name);
unlink($title_file_name); // delete the file after reading
return $title;
} else
{
return false;
}
}
print GetUrlTitle("http://www.youtube.com/watch?v=Dd7dQh8u4Hc");
Menggunakan nokogiri, orang dapat menggunakan kueri berbasis CSS sederhana untuk mengekstrak teks bagian dalam tag:
$ nokogiri -e 'puts $_.at_css("title").content'
Why Are Bad Words Bad? - YouTube
Demikian pula, untuk mengekstrak nilai atribut "konten" dari tag:
$ nokogiri -e 'puts $_.at_css("meta[name=title]").attr("content")'
Why Are Bad Words Bad?