Экспорт избранного Хабра в FB2

    Ненавижу длинные вступления
    И поэтому не буду писать их даже под спойлером.

    • Зачем?
      • Для оффлайнового просмотра на читалках.
    • Моя читалка не поддерживает FB2!
    • Хочу!
      1. Обзаводимся Python 2.7+. Тестировалось на Python 2.7.3.
      2. Ставим библиотеку BeautifulSoup 4. Вкратце варианты:
        • apt-get install python-beautifulsoup4
        • easy_install beautifulsoup4
        • pip install beautifulsoup4
        • Исходники и python setup.py install
      3. Качаем код из репозитория (прямая ссылка на последнюю версию).
      4. Открываем файл habrafav.py и в строке username = ... прописываем свой логин.
      5. python habrafav.py (или просто habrafav.py под Windows)
      6. Ждём. У меня с кэшированными данными экспорт ~150 статей занимает около 6 минут и 600 Мб оперативной памяти.
      7. Забираем habrahabr_favorites.fb2. Мой занимает примерно 62 Мб.


    • Уже было.
      • Знаю. Только
        • PDF нормально отображается не везде;
        • у меня так и не получилось запустить тот код.
    • А комментарии есть?
      • Нет. Есть парсинг, но нет экспорта. Прикрутить несложно, но тогда получаемый файл раздуется ещё раза в два-три.
    • Почему FB2?
    • Преобразование корректное?
      • Не совсем. Валидацию получающиеся файлы не проходят.
      • Результаты валидации моего избранного
        • This element is not expected.
          • <empty-line> — 287 раз
          • <code> — 83 раза
          • <emphasis> — 19 раз
          • <strong> — 7 раз
          • <subtitle> — 5 раз
          • <cite> — 4 раза
          • <a> — 3 раза
          • <image> — 2 раза
          • <sup> — 1 раз
        • Character content other than whitespace is not allowed because the content type is 'element-only'. Тег — <cite>, 245 раз.
        • empty tag. Тег — <td>, 19 раз.
      • Тем не менее, мой Kindle получившийся файл (после конвертации в .mobi) прекрасно отображает.
    • А с неформальной точки зрения?
      • UPD: Fixed. Баг был у меня. Перекачайте версию из репозитория.
        Есть странный баг с исчезанием пробелов вокруг тегов, находящихся внутри текста. То есть HTML-код yet another bicycle превращается в yetanotherbicycle. Вероятно, это баг BeautifulSoup, но, возможно, ошибка где-то у меня.
    • Что-нибудь интересное в реализации?
      • Не особо. Весь парсинг сводится к правильным библиотечным вызовам. После него я выкачиваю все картинки и заменяю теги на <image l:href="#image_id"/>. Затем при помощи небольшого набора костылей перестраиваю деревья разбора. Удаляю одни теги, заменяю другие, вставляю третьи. Наконец, собираю всё это вместе, добавляю шапку, подвал и пишу в файл. Единственный не совсем тривиальный момент — замена тегов <br> на . Грубо говоря - вместо разделителей между параграфами я выделяю сами параграфы. Кому интересно - файл conversion.py, функция make_paragraphs.

      Да этому же прямая дорога на govnokod.ru!
      • Вполне возможно. Я только изучаю возможности BeautifulSoup, поэтому наверняка какие-то вещи сделал не так, как это принято. Напишите в комментариях вашу точку зрения, обсудим.

      Я нашёл ещё баг!

    Поделиться публикацией

    Похожие публикации

    Комментарии 50

      +10
      Обожаю топики в стиле FAQ.
        +2
        Вот только нужно было убрать «Что? Сабж.» и маркеры, смотрится — грязно.
        +2
        Наверное уже многих достал уже своим Sfile, но по идее там хотел делать связь (модуль с удобным API + некий интерфейс в веб+мобильный) с хабром, а там уже можно логиниться брать данные вроде избранного и хоть оффлайн грузить в клиент, однако все это в планах, но моя система должна позволять любому написать модуль например для конвертирования избранного в fb2 просто используя доступ к избранному через API. Правда я думаю что мне надо будет отдельно договариваться с хабром о доступе, т.к. выдавать поля логина, пароля и капчи, а потом хранить все это дело на сервере будет крайне некультурно, так потом заново капчу вводить. Хотя были идеи создания например универсального плагина для Firefox, который бы используя модули, уже на стороне клиента мог собирать данные для связи, да хоть сделать модуль фотоальбома и выбирая фото на любой страничке грузить их в систему. Однако идей много а времени так мало, благо сейчас лето начинается скоро буду дорабатывать API и надеюсь уже через пол месяца можно будет читать хабр с пережатыми картинками под экран телефона или планшета с сжатием всего содержимого и упрощением интерфейса (например мне не нужны соц кнопки, голосование не нужно т.к. у меня кармы нет, добавление в избранное редко нужно + читаю только Все — Новые и мне не нужны рекламные блоки майкрософта, все равно блокирую, не нужна компания для и Q&A нижк) да даже прямой эфир и лучшие мне не нужны, хотя прямой эфир можно и включить. Но главная фича этой оболочки будет не сколько Ajax который сэкономит львиную долю трафика и ускорит работу на мобильном или на планшете, сколько удаление ненужных блоков или добавление других. Например лучшие можно обрезать на 5 значений, но при этом показывать 10 последних новых постов. А если еще использовать мобильный клиент то можно настроить автозакрузку текста статей и комментариев (там еще например правила на обновления их) и например некоторые блоги можно подгружать сразу с изображениями. Да и вообще пережатие для мобильного это будет то что надо. Часто авторы или загружают что то в статью этак на 10 мбайт и размером для FullHD или в комментариях кто то зальет картинку на 5 мбайт (тут можно сделать предупреждение о трафике без автозагрузки)
        Короче вариантов масса, если кого заинтересует, напишите мне.
        Насчет статьи — действительно не помешала бы онлайн версия. Все таки FB2 для моб девайсов вроде книжек или планшетов, неплохо прямо с них и конвертировать.
          +1
          ваш комментарий немного больше статьи получился )
          ну ничего
            0
            Если совсем утрировать мою систему, то у каждого мог быть бы свой комментарий где видно только его интересующую информацию.
            Меня поразило вот это
            «Ждём. У меня с кэшированными данными экспорт ~150 статей занимает около 6 минут и 600 Мб оперативной памяти.»
            Это из за питона, или там все так не оптимизированно? Судя по занимаемой памяти она наверное вообще не очищается, питон не знаю, но сейчас посмотрю код, даже интересно стало почему так много ест.
          0
          А я все мечтаю о экспорте архива getpocket в fb2
            +6
            А комментарии есть? Нет. Есть парсинг, но нет экспорта. Прикрутить несложно, но тогда получаемый файл раздуется ещё раза в два-три.
            Советую вам как можно скорее прикрутить эту возможность (хоть флагом). Хабр — одно из мест, где я, помимо чтения топика, ожидаю увидеть и грамотные комменты к оному.
              0
              Там ещё одна проблема есть, помимо увеличения размера файла. Дерево комментариев нарисовать не получится. Максимум, на что можно рассчитывать, — все ответы на корневой комментарий будут с отступом (как в теге <blockquote>). Ну и заголовок у каждого комментария типа author1 #comment_id1 (ответ на author2 #comment_id2). К тому же, непонятно, как сделать быстрый переход к комментариям. Можно, например, поделить весь раздел со статьёй на две части: «Статья» и «Комментарии», но тогда оглавление будет выглядеть некрасиво.

              Короче, прикрутить кое-как несложно, а вот качественно — задача не самая тривиальная.
                0
                Если не опоздал :):
                оставлять коменнтарии только 1-го уровня (ну плюс один второго, если он один или 2) а остальное выносить в сноску!
                  0
                  Вообще-то скрипт уже давно не работает, поскольку на сайте поменялась разметка, но если хотите, можете форкнуть (проект лежит на BitBucket) и допилить. У меня самого сейчас заниматься им нет ни времени, ни желания…
              0
              Нужен плагин под браузеры (хотя бы хром). Типа Evernote Clipper.
                0
                Есть ещё Pocket, но он без fb2.
                +1
                Грустно без комментов. У половины топиков смысл весь в них.

                А вот как хорошо экспортнуть, чтоб удобно на kindle читать я не знаю.
                  0
                  Добавляете в начале адреса «m.» и сохраняете в Instapaper. В мобильной версии хабра комментарии не обрезаются.
                0
                Не знаю в чём именно проблема в скрипте или самом питоне, но по завершению экспорта, процесс питона отожрал 2Гб памяти и продолжал поедать её без остановки.
                  +1
                  А у меня почему-то крашится:(
                  Лог
                  C:\...afarianist-habrafav-ecf26c772051>habrafav.py
                  Retrieving article list…
                  Traceback (most recent call last):
                  File «C:\_Tmp\habr\Pastafarianist-habrafav-ecf26c772051\habrafav.py», line 60,
                  in main(username, output_filename)
                  File «C:\_Tmp\habr\Pastafarianist-habrafav-ecf26c772051\habrafav.py», line 44,
                  in main
                  ids = load_identifiers()
                  File «C:\_Tmp\habr\Pastafarianist-habrafav-ecf26c772051\habrafav.py», line 16,
                  in load_identifiers
                  ids = list(article_ids(username))
                  File «C:\_Tmp\habr\Pastafarianist-habrafav-ecf26c772051\identifiers.py», line
                  27, in article_ids
                  for page_number in xrange(1, get_page_count() + 1):
                  File «C:\_Tmp\habr\Pastafarianist-habrafav-ecf26c772051\identifiers.py», line
                  15, in get_page_count
                  count = int(a['href'].split('/')[-2][4:])
                  TypeError: 'NoneType' object is not subscriptable
                    0
                    Я не учёл, что избранное может занимать меньше одной страницы :) Fixed.
                    0
                    Падает при попытки загрузки картинок
                    traceback
                    Downloading images for article #131595…
                    Downloading images for article #124704…
                    dl.dropbox.com/u/19527104/images/game/habr_1.png...
                    Traceback (most recent call last):
                    File «C:\fav\habrafav.py», line 60, in main(username, output_filename)
                    File «C:\fav\habrafav.py», line 51, in main
                    result = render(articles, nickname=username)
                    File «C:\fav\rendering.py», line 23, in render
                    binary = make_binary(articles) # this modifies articles so it should be befo
                    re make_body
                    File «C:\fav\rendering.py», line 66, in make_binary
                    images = process_images(article['content'], images)
                    File «C:\fav\images.py», line 56, in process_images
                    binary = download_data(src)
                    File «C:\fav\common.py», line 27, in download_data
                    response = urllib2.urlopen(url)
                    File «C:\Python27\lib\urllib2.py», line 126, in urlopen
                    return _opener.open(url, data, timeout)
                    File «C:\Python27\lib\urllib2.py», line 400, in open
                    response = self._open(req, data)
                    File «C:\Python27\lib\urllib2.py», line 418, in _open
                    '_open', req)
                    File «C:\Python27\lib\urllib2.py», line 378, in _call_chain
                    result = func(*args)
                    File «C:\Python27\lib\urllib2.py», line 1207, in http_open
                    return self.do_open(httplib.HTTPConnection, req)
                    File «C:\Python27\lib\urllib2.py», line 1180, in do_open
                    r = h.getresponse(buffering=True)
                    File «C:\Python27\lib\httplib.py», line 1030, in getresponse
                    response.begin()
                    File «C:\Python27\lib\httplib.py», line 407, in begin
                    version, status, reason = self._read_status()
                    File «C:\Python27\lib\httplib.py», line 365, in _read_status
                    line = self.fp.readline()
                    File «C:\Python27\lib\socket.py», line 447, in readline
                    data = self._sock.recv(self._rbufsize)
                    socket.error: [Errno 10054]
                      0
                      Убрал статью из избранного, пока парсится нормально. Видимо проблемы только с dropbox
                        0
                        Не обязательно убирать статью из избранного на сайте. Идентификаторы всех найденных статей сохраняются в файл identifiers.txt, который можно отредактировать, после чего перезапустить программу.
                          0
                          Fixed. Исключение теперь грубо подавляется.
                        +2
                        Хорошо, что у меня есть Kindle и Klip.me
                          0
                          Спасибо!
                            0
                            Хорошо что есть Evernote WebClipper
                            0
                            Использую Readability для отправки материалов, но работает только с Kindle.
                              0
                              А у меня вот такая ошибка возникает:
                              посмотреть
                              $ python habrafav.py
                              Traceback (most recent call last):
                              File «habrafav.py», line 4, in from rendering import render
                              File "/home/t_q_l/1/rendering.py", line 4, in from conversion import convert
                              File "/home/t_q_l/1/conversion.py", line 36
                              replace.update({'h' + str(i): 'subtitle' for i in xrange(1, 7)})
                              ^
                              SyntaxError: invalid syntax
                              +1
                              Статья про избранное, ушла в избранное. Как то так получается.
                                –1
                                Рекурсия!
                                0
                                У меня тоже вываливается, правда в файле /usr/lib/python2.7/socket.py:

                                Посмотреть
                                File "/usr/lib/python2.7/httplib.py", line 1030, in getresponse
                                response.begin()
                                File "/usr/lib/python2.7/httplib.py", line 407, in begin
                                version, status, reason = self._read_status()
                                File "/usr/lib/python2.7/httplib.py", line 365, in _read_status
                                line = self.fp.readline()
                                File "/usr/lib/python2.7/socket.py", line 447, in readline
                                data = self._sock.recv(self._rbufsize)
                                socket.error: [Errno 104] Connection reset by peer
                                  +1
                                  Fixed. Исключение теперь грубо подавляется. Перекачайте версию из репозитория.
                                    0
                                    ок, спс!
                                      0
                                      Теперь падает здесь:

                                      Посмотреть
                                      File "/home/username/Downloads/Pastafarianist-habrafav-a3eaa3feac82/images.py", line 56, in process_images
                                      binary = download_data(src)
                                      File "/home/username/Downloads/Pastafarianist-habrafav-a3eaa3feac82/common.py", line 31, in download_data
                                      raise urllib2.URLError # this exception is handled in images.py
                                      TypeError: __init__() takes exactly 2 arguments (1 given)

                                  0
                                  Да, вы правы. Fixed. Again.
                                  0
                                  У меня в Ubuntu 12.10 пакет python-beautifulsoup4 называется python-bs4.
                                  Я ставил через pip в вирт окружение, но вдруг кому-то понадобится.
                                    0
                                    Исправил баг с пробелами вокруг тегов. Перекачайте версию из репозитория.
                                      0
                                      Долго генерировалось из-за того, что часть изображений уже удалили.
                                      Но все получилось. Огромное спасибо.

                                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                      Самое читаемое