Saya menulis crawler di Ruby (1.9) yang mengkonsumsi banyak HTML dari banyak situs acak.
Ketika mencoba mengekstrak tautan, saya memutuskan untuk menggunakan saja .scan(/href="(.*?)"/i)
daripada nokogiri / hpricot (percepatan besar). Masalahnya adalah sekarang saya menerima banyak " invalid byte sequence in UTF-8
" kesalahan.
Dari apa yang saya pahami, net/http
perpustakaan tidak memiliki opsi khusus pengkodean dan hal-hal yang masuk pada dasarnya tidak diberi tag dengan benar.
Apa cara terbaik untuk benar-benar bekerja dengan data yang masuk itu? Saya mencoba .encode
dengan set opsi ganti dan tidak valid, tetapi sejauh ini tidak berhasil ...
109
'U*'
membatalkan'C*'
?Jawaban:
Di Ruby 1.9.3, Anda dapat menggunakan String.encode untuk "mengabaikan" urutan UTF-8 yang tidak valid. Berikut ini cuplikan yang akan berfungsi baik di 1.8 ( iconv ) dan 1.9 ( String # encode ):
atau jika Anda memiliki masukan yang sangat merepotkan, Anda dapat melakukan konversi ganda dari UTF-8 ke UTF-16 dan kembali ke UTF-8:
sumber
file_contents.encode!('UTF-16', 'UTF-8', :invalid => :replace, :replace => '')
file_contents.encode!('UTF-8', 'UTF-16')
force_encoding
. Jika Anda telah membaca ISO8859-1 sebagai UTF-8 (dan karena itu string tersebut berisi UTF-8 yang tidak valid) maka Anda dapat "menafsirkan ulang" sebagai ISO8859-1 dengan the_string.force_encoding ("ISO8859-1") dan langsung bekerja dengan string itu dalam pengkodean aslinya..encode('UTF-8')
sudah tidak ada, dan tidak ada pemeriksaan yang dijalankan. Ruby Core Documentation untuk encode . Namun, mengonversinya ke UTF-16 terlebih dahulu memaksa semua pemeriksaan untuk urutan byte yang tidak valid dijalankan, dan penggantian dilakukan sesuai kebutuhan.Jawaban yang diterima atau jawaban lainnya cocok untuk saya. Saya menemukan posting ini yang menyarankan
Ini memperbaiki masalah saya.
sumber
Solusi saya saat ini adalah menjalankan:
Ini setidaknya akan menghilangkan pengecualian yang merupakan masalah utama saya
sumber
valid_encoding?
yang sepertinya mendeteksi ketika ada sesuatu yang salah.val.unpack('C*').pack('U*') if !val.valid_encoding?
.\xB0
simbol punggung saya ke derajat. Bahkanvalid_encoding?
datang kembali benar tapi aku masih memeriksa apakah itu tidak dan menghapus karakter menyinggung menggunakan jawaban Amir di atas:string.encode!('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
. Saya juga telah mencobaforce_encoding
rute tersebut tetapi gagal.Coba ini:
sumber
Saya menyarankan Anda untuk menggunakan parser HTML. Temukan saja yang tercepat.
Parsing HTML tidak semudah kelihatannya.
Browser mengurai urutan UTF-8 yang tidak valid, dalam dokumen HTML UTF-8, cukup dengan meletakkan simbol " ". Jadi, setelah urutan UTF-8 yang tidak valid di HTML diurai, teks yang dihasilkan adalah string yang valid.
Bahkan di dalam nilai atribut Anda harus mendekode entitas HTML seperti amp
Berikut adalah pertanyaan bagus yang merangkum mengapa Anda tidak dapat mengurai HTML dengan ekspresi reguler secara andal: RegEx mencocokkan tag terbuka kecuali tag mandiri XHTML
sumber
Ini sepertinya berhasil:
sumber
sumber
Saya menemukan string, yang memiliki campuran bahasa Inggris, Rusia, dan beberapa abjad lainnya, yang menyebabkan pengecualian. Saya hanya perlu bahasa Rusia dan Inggris, dan saat ini ini berfungsi untuk saya:
sumber
Sementara solusi Nakilon berfungsi, setidaknya sejauh melewati kesalahan, dalam kasus saya, saya memiliki karakter aneh yang berasal dari Microsoft Excel yang dikonversi ke CSV yang mendaftar di ruby sebagai (dapatkan ini) cyrillic K yang di ruby adalah K. yang tebal. Untuk memperbaikinya, saya menggunakan 'iso-8859-1' yaitu.
CSV.parse(f, :encoding => "iso-8859-1")
, yang mengubah Cyrillic K saya yang aneh menjadi jauh lebih mudah diatur/\xCA/
, yang kemudian bisa saya hapus denganstring.gsub!(/\xCA/, '')
sumber
Sebelum Anda menggunakan
scan
, pastikan bahwaContent-Type
header halaman yang diminta adalahtext/html
, karena mungkin ada link ke hal-hal seperti gambar yang tidak dikodekan dalam UTF-8. Halaman tersebut juga bisa non-html jika Anda mengambilhref
sesuatu seperti<link>
elemen. Cara memeriksanya bervariasi pada pustaka HTTP apa yang Anda gunakan. Kemudian, pastikan hasilnya hanya ascii denganString#ascii_only?
(bukan UTF-8 karena HTML seharusnya hanya menggunakan ascii, entitas dapat digunakan sebaliknya). Jika kedua tes tersebut lulus, maka aman digunakanscan
.sumber
Jika Anda tidak "peduli" dengan data, Anda dapat melakukan sesuatu seperti:
search_params = params[:search].valid_encoding? ? params[:search].gsub(/\W+/, '') : "nothing"
Saya hanya biasa
valid_encoding?
melewatinya. Milik saya adalah bidang pencarian, jadi saya menemukan keanehan yang sama berulang kali jadi saya menggunakan sesuatu seperti: hanya agar sistem tidak rusak. Karena saya tidak mengontrol pengalaman pengguna untuk melakukan validasi otomatis sebelum mengirim info ini (seperti umpan balik otomatis untuk mengatakan "dummy up!") Saya hanya dapat menerimanya, menghapusnya, dan mengembalikan hasil kosong.sumber