Що це взагалі таке
Ліричний відступ про парсери
Основна характеристика парсеру сайтів, або інших слабо структурованих форматів - це кількість знань про окремі випадки використання формату в дикій природі.
Вироджений випадок володіння всіма знаннями - це парсер якогось одного сайту. Тобто якщо ми хочемо красти статті з Хабрахабр, наприклад, щоб роздруковувати їх вночі на струменевому принтері і приносити в жертву Сатані - ми можемо подивитися на існуючу верстку і легко визначити, що заголовок поста це h1.title.
Програма, написана таким способом, майже не буде помилятися; для кожного відмінного від Хабрахабра сайту доведеться писати нову програму.
Вироджений ідеальний випадок: парсер взагалі не знає, в якому форматі він отримав дані. Приклад такої програми - strings (існує в більшості неігрових операційних систем).
Якщо застосувати strings до якого щось не призначеному для читання файлу, можна отримати список всього, що схоже на текст всередині цього файлу. Наприклад, команда надрукує купу рядків для форматування всередині бінарники ls. і довідку.
Чим менше знань, тим універсальніше парсер.
Що вже є
Актуальна версія Readability закрита і обвішана пляшками різноманітної затребуваності. Є API.
Існує форк першої версії Readability компанією Apple (функція Reader в браузері Safari). Вихідний код не дуже-то відкритий, але подивитися на нього можна, там ще більше регулярних виразів і окремих випадків (наприклад, є така змінна - isWordPressSite).
Проблеми оригінального скрипта - складність модифікації, аркадна евристика. В основному працює, але вимагає нетривіальною доведення напильником. Версія Apple ще і ліцензована незрозуміло.
Що треба написати
Парсер сайтів, що володіє мінімальними знаннями про розмітку. Вхідні дані - одна сторінка сайту, або фрагмент сторінки. Результат - текстове представлення вхідних даних.
Важливий критерій - універсальність: програма буде працювати і на клієнті, і на сервері. Тому ми не прив'язуємося до існуючих реалізацій DOM, а будуємо свою структуру даних (вона ще й працює швидше, ніж повноцінний DOM, тому що даних нам потрібно як кіт, припустимо, ніс).
З цієї ж причини програма не вміти самостійно завантажувати сторінки з інтернету, зберігати результати на диску, володіти призначеним для користувача інтерфейсом, вишивати хрестиком.
Життя і пригоди алгоритму
У пошуковику знайшлося кілька статей на тему алгоритмізації описаного вище процесу. Найбільше мені сподобалися ось ці китайці PDF.
Формули у мене вийшли трохи інші, тому я розповім коротенько про свій варіант китайського алгоритму.
Простір для трудового подвигу
Я про всяк випадок перевіряю ще, що після видалення сміття оцінка батька виросла, якщо немає (або зросла несуттєво) - щось не видаляю, хіба мало що там.
HTML. В алгоритмі не використовуються знання про структуру документа, їх можна тепер додати, щоб поліпшити (або прискорити) роботу програми. Тобто допустимо, пессімізіровать заздалегідь
Текстові сигнали. Якщо в тексті присутні коми, крапки і інші знаки пунктуації, це з великою ймовірністю зв'язний текст (на відміну від навігації, наприклад). Така евристика була в Readability.
Тут треба звернути увагу на те, що знаки пунктуації в різних мовах все-таки різні, і коми в китайському ( "# 65292;" Unicode U + FF0C) відрізняються від символу "," (ASCII 44).
Що вийшло, як користуватися
Результат я назвав невигадливо readability2, виклав в npm.
Коротенько про тести
Тестувати таку штуку треба обов'язково, щоб уникнути регрессий (і взагалі автоматично тестувати програми - це класно).
Вихідні тексти без тестів: GitHib
приклад використання
Для ілюстративних цілей я написав сторінку demo.html. в якій два рядки тексту серед усякої навігації.
Текст називається «Назва». Змістовна частина:
Весь мікрорайон тихенько чудо боже спостерігав:
Поп Ігнатій тілібонькал свій церковний прічіндал.
Таким повинен бути результат прогону програми. Якщо результат не такий, значить, все зламалося.
Документація, вона ж API
конструктор:
Нічого не приймає.
SAX інтерфейс:
Тут всі аргументи - рядки.
Щоб отримати результат:
На виході: res.heading - назва статті та text - основний текст без форматування.
Замість reader.clean можна написати інший форматтер, тоді буде виходити не текст, а проста розмітка, наприклад.
Важливе зауваження: картинка зліва не має ніякого відношення до посту. Тому якщо вона не завантажилася, і ви не бачите зліва ніякої картинки - не турбуйтеся.