Когда был доеден новогодний оливье, мне стало нечего делать, и я решил скачать себе на компьютер все статьи с Хабрахабра (и смежных платформ) и поисследовать.


Получилось несколько интересных сюжетов. Первый из них — это развитие формата и тематики статей за 12 лет существования сайта. Например, достаточно показательна динамика некоторых тем. Продолжение — под катом.



Процесс парсинга


Чтобы понять, как развивался Хабр, нужно было обойти по все его статьи и выделить из них метаинформацию (например, даты). Обход дался легко, потому что ссылки на все статьи имеют вид "habrahabr.ru/post/337722/", причём номера задаются строго по порядку. Зная, что последний пост имеет номер чуть меньше 350 тысяч, я просто прошёлся по всем возможным id документов циклом (код на Python):


import numpy as np
from multiprocessing import Pool
with Pool(100) as p:
    docs = p.map(download_document, np.arange(350000))

Функция download_document пытается загружает страницу с соответствующим id и пытается вытащить из структуры html содержательную информацию.


import requests
from bs4 import BeautifulSoup

def get_doc_by_id(pid):
    """ Download and process a Habr document and its comments """
    # выгрузка документа
    r = requests.get('https://habrahabr.ru/post/' +str(pid) + '/')
    # парсинг документа
    soup = BeautifulSoup(r.text, 'html5lib') # instead of html.parser
    doc = {}
    doc['id'] = pid
    if not soup.find("span", {"class": "post__title-text"}):
        # такое бывает, если статья не существовала или удалена
        doc['status'] = 'title_not_found'
    else:
        doc['status'] = 'ok'
        doc['title'] = soup.find("span", {"class": "post__title-text"}).text
        doc['text'] = soup.find("div", {"class": "post__text"}).text
        doc['time'] = soup.find("span", {"class": "post__time"}).text
        # create other fields: hubs, tags, views, comments, votes, etc.
        # ...
    # сохранение результата в отдельный файл
    fname = r'files/' + str(pid) + '.pkl'
    with open(fname, 'wb') as f:
        pickle.dump(doc, f)

В процессе парсинга открыл для себя несколько новых моментов.


Во-первых, говорят, что создавать больше процессов, чем ядер в процессоре, бесполезно. Но в моём случае оказалось, что лимитирующий ресурс — не процессор, а сеть, и 100 процессов отрабатывают быстрее, чем 4 или, скажем, 20.


Во-вторых, в некоторых постах встречались сочетания спецсимволов — например, эвфемизмы типа "%&#@". Оказалось, что html.parser, который я использовал сначала, реагирует на комбинацию &# болезненно, считая её началом html-сущности. Я уж было собирался творить чёрную магию, но на форуме подсказали, что можно просто поменять парсер.


В-третьих, мне удалось выгрузить все публикации, кроме трёх. Документы под номерами 65927, 162075, и 275987 моментально удалил мой антивирус. Это статьи соответственно про цепочку джаваскриптов, загружающую зловредный pdf, SMS-вымогатель в виде набора плагинов для браузеров, и сайт CrashSafari.com, который отправляет айфоны в перезагрузку. Ещё одну статью антивирь обнаружил позднее, во время скана системы: пост 338586 про скрипты на сайте зоомагазина, использующие процессор пользователя для майнинга криптовалюты. Так что можно считать работу антивируса вполне адекватной.


"Живых" статей оказалась только половина от потенциального максимума — 166307 штук. Про остальные Хабр даёт варианты "страница устарела, была удалена или не существовала вовсе". Что ж, всякое бывает.


За выгрузкой статей последовала техническая работа: например, даты публикации нужно было перевести из формата "'21 декабря 2006 в 10:47" в стандартный datetime, а "12,8k" просмотров — в 12800. На этом этапе вылезло ещё несколько казусов. Самый весёлый связан с подсчётом голосов и типами данных: в некоторых старых постах произошло переполнение инта, и они получили по 65535 голосов.



В результате тексты статей (без картинок) заняли у меня 1.5 гигабайта, комментарии с метаинформацией — ещё 3, и около сотни мегабайт — метаинформация о статьях. Такое можно полностью держать в оперативной памяти, что было для меня приятной неожиданностью.


Начал анализ статей я не с самих текстов, а с метаинформации: дат, тегов, хабов, просмотров и "лайков". Оказалось, что и она может многое поведать.


Тренды развития Хабрахабра


Статьи на сайте публикуются с 2006 года; наиболее интенсивно — в 2008-2016 годах.



Насколько активно эти статьи читали в разное время, оценить не так просто. Тексты 2012 года и младше более активно комментировали и рейтинговали, но у более новых текстов больше просмотров и добавлений в закладки. Одинаково вели себя (вдвое упали) эти метрики только однажды, в 2015 году. Возможно, в ситуации экономического и политического кризиса внимание читателей перешло с айтишных блогов к более болезненным вопросам.



Кроме самих статей, я выкачал ещё комментарии к ним. Комментариев получилось 6 миллионов, правда, 240 тысяч из них оказались забаненными ("нло прилетело и опубликовало эту надпись здесь"). Полезное свойство комментариев в том, что для них указано время. Изучая время комментариев, можно примерно понять и то, когда вообще статьи читают.


Оказалось, что большую часть статей и пишут, и комментируют где-то с 10 до 20 часов, т.е. в типичный московский рабочий день. Это может значить и что Хабр читают в профессиональных целях, и что это хороший способ прокрастинации на работе. Кстати, это распределение времени суток стабильно с самого основания Хабра до сегодняшнего дня.



Однако основная польза от метки времени комментария — не время суток, а срок "активной жизни" статьи. Я подсчитал, как распределено время от публикации статьи до её комментария. Оказалось, что сейчас медианный комментарий (зелёная линия) приходит примерно через 20 часов, т.е. в первые сутки после публикации оставляют в среднем чуть больше половины всех комментариев к статье. А за двое суток оставляют 75% всех комментариев. При этом раньше статьи читали ещё быстрее — так, в 2010 году половина комментариев приходила уже в первые 6 часов.



Для меня стало сюрпризом, что комментарии удлинились: среднее количество символов в комментарии за время существования Хабра выросло почти вдвое!



Более простая обратная связь, чем комментарии — это голоса. В отличие от многих других ресурсов, на Хабре можно ставить не только плюсы, но и минусы. Впрочем, последней возможностью читатели пользуются не так часто: текущая доля дизлайков составляет около 15% от всех отданных голосов. Раньше было больше, но со временем читатели подобрели.



Менялись со временем и сами тексты. Например, типичная длина текста не прекращает устойчиво расти с самого запуска сайта, несмотря на кризисы. За десятилетие тексты стали почти в десять раз длиннее!



Стилистика текстов (в первом приближении) тоже менялась. За первые годы существования Хабра, например, выросла доля кода и чисел в текстах:



Разобравшись с общей динамикой сайта, я решил измерить, как менялась популярность различных тем. Темы можно выделять из текстов автоматически, но для начала можно не изобретать велосипед, а воспользоваться готовыми тегами, проставленными авторами каждой статьи. Четыре типичных тренда я вывел на графике. Тема "Google" изначально доминировала (возможно, в основном в связи с SEO-оптимизацией), но с каждым годом теряла вес. Javascript был популярной темой и продолжает постепенно, а вот машинное обучение начало стремительно набирать популярность лишь в последние годы. Linux же остаётся одинаково актуальным на протяжении всего десятилетия.



Конечно же, мне стало интересно, какие темы привлекают больше читательской активности. Я подсчитал медианное число просмотров, голосов и комментов в каждой теме. Вот что получилось:


  • Самые просматриваемые темы: arduino, веб-дизайн, веб-разработка, дайджест, ссылки, css, html, html5, nginx, алгоритмы.
  • Самые "лайкабельные" темы: вконтакте, юмор, jquery, opera, c, html, веб-разработка, html5, css, веб-дизайн.
  • Самые обсуждаемые темы: opera, skype, фриланс, вконтакте, ubuntu, работа, nokia, nginx, arduino, firefox.

Кстати, раз уж я сравниваю темы, можно сделать их рейтинг по частоте (и сравнить результаты с аналогичной статьёй от 2013 года).


  • За все годы существования Хабра самыми популярными тегами (в порядке убывания) стали google, android, javascript, microsoft, linux, php, apple, java, python, программирование, стартапы, разработка, ios, стартап, социальные сети
  • В 2017 году наиболее популярны были javascript, python, java, android, разработка, linux, c++, программирование, php, c#, ios, машинное обучение, информационная безопасность, microsoft, react

При сравнении этих рейтингов можно обратить внимание, например, на победоносное шествие Питона и вымирание php, или на "закат" стартаперской тематики и взлёт машинного обучения.


Не все теги на Хабре имеют столь очевидную тематическую окраску. Вот, например, десяток тегов, которые встречались всего лишь один раз, но просто показались мне забавными. Итак: "идея движитель прогресса", "загрузка с образа дискеты", "штат айова", "драматургия", "супералеша", "паровой двигатель", "чем заняться в субботу", "у меня лисица в мясорубке", "а получилось как всегда", "смешных тэгов придумать не удалось". Чтобы определить тематику таких статей, тегов недостаточно — придётся осуществлять тематическое моделирование над текстами статей.


Более подробный анализ содержания статей будет в следующем посте. Во-первых, я собираюсь построить модель, прогнозирующую количество просмотров статьи в зависимости от её содержания. Во-вторых, хочется научить нейросеть генерировать тексты в той же стилистике, что и у авторов Хабра. Так что подписывайтесь :)

Комментарии (44)


  1. baldr
    08.01.2018 17:24
    +1

    Сразу видно что вы теоретик.
    Уже 2 часа прошло, а к статье ни одного комментария. А стоило только добавить метки из тех самых «самых обсуждаемых».


    1. cointegrated Автор
      08.01.2018 18:01
      +1

      Я скорее неторопливый практик :) Про идеально привлекательный текст будет следующая статья.


      1. OKyJIucT
        09.01.2018 01:28

        Его напишет нейросеть?)


        1. JekaMas
          09.01.2018 10:57

          Децентрализованно, в докере и получая данные будут получаться через смарт-контракт в блокчейне…
          Плюсы будут обеспечены, особенно, если вы таксист.


  1. derSmoll
    08.01.2018 18:23
    +2

    Самые «лайкабельные» темы: вконтакте, юмор, jquery


    Что-то в этом есть :)

    Спасибо за анализ


    1. System12
      09.01.2018 15:35

      Старый закон Паркинсона: «Время обсуждения любой проблемы обратно пропорциональна ее важности»


  1. dionket
    08.01.2018 19:19
    +1

    Для парсинга логичнее использовать потоки, а не процессы. Пробовал и так и эдак. Если правильно помню, 256 потоков едва загружали 1 ядро, правда сайт был довольно простой.


  1. BuriK666
    08.01.2018 20:06

    Мне для парсинга понравился scrapy


  1. pozharskiy
    08.01.2018 21:18

    крутой датасет, выложите куда-нибудь, думаю многим будет интересно покопаться


    1. cointegrated Автор
      08.01.2018 22:16

      Да, когда сам наиграюсь с ним, выложу на яндекс.диск.


      1. qwert_ukg
        09.01.2018 15:56

        А может дадите список валидных PostId? А мы сами их опросим.


  1. dmnBrest
    08.01.2018 22:13

    А сколько по времени занял процесс стягивания контента? Хабр не банит чрезмерно активных пользователей?


    1. cointegrated Автор
      08.01.2018 22:15

      Если не считать простоев, когда всё падало (в основном из за несоответствия структуры html ожидаемой), около 8 часов. На ноутбуке :)


  1. AIxray
    08.01.2018 22:34

    Было бы очень здорово добавлять по памяти сколько темы занимают и комментарии которых 6 миллионов.
    Спасибо за то, что учли!


    1. cointegrated Автор
      08.01.2018 22:57

      Добавил!

      В результате тексты статей (без картинок) заняли у меня 1.5 гигабайта, комментарии с метаинформацией (автор, дата, голоса...) — ещё 3, и около сотни мегабайт — метаинформация о статьях. Такое можно полностью держать в оперативной памяти, что было для меня приятной неожиданностью.


  1. kost
    09.01.2018 02:44

    «Живых» статей оказалась только половина от потенциального максимума — 166307 штук. Про остальные Хабр даёт варианты «страница устарела, была удалена или не существовала вовсе».


    Когда-то от Хабра отделился Geektimes, и часть статей была перенесена.


    1. Squoworode
      09.01.2018 17:43

      Перенесённые статьи при открытии по номеру перенаправляются в актуальное раположение. Не существуют только созданные после отделения.


  1. allnightlong
    09.01.2018 08:55

    Обычно, в таких ситуациях логичнее индексировать мобильную версию, а не десктопную, тем более, если сами пишете, что бутылочным горлышком была именно сеть.

    К пример, ваша статья:
    habrahabr.ru/post/346198 — 42кб
    m.habrahabr.ru/post/346198 — 13кб
    т.е. разница в 4 раза.

    Ну и парсить потом будет проще.


    1. oleg_chornyi
      09.01.2018 11:24

      Частично, это связано с тем что в мобильной версии комментарии находятся на отдельной странице, но тем не менее вы правы — экономия будет все равно будет на уровне 60%.


  1. bro-dev
    09.01.2018 10:07

    Неужели никакой защиты нету, типа не больше 1к постов одному ип в сутки.


    1. c4boomb
      09.01.2018 11:32

      А зачем или от кого?


    1. BuriK666
      09.01.2018 12:30

      Я спрашивал у TM разрешения спарсить toster.ru.
      Ответ:

      Мы не запрещаем пользователям парсить наши ресурсы.


  1. vyatsek
    09.01.2018 12:11

    А почему не использовали RSS?


    1. cointegrated Автор
      09.01.2018 12:25
      +2

      Не подумал :)


      1. vyatsek
        09.01.2018 14:15

        Все равно спасибо, интересно :)


    1. delvin-fil
      10.01.2018 03:39

      Да, кстати.
      У меня практически 85% из фидера. Ссылки вида habrahabr.ru/post/346198?utm_source=habrahabr&utm_medium=rss&utm_campaign=346198 не учтены в статье.


      1. cointegrated Автор
        10.01.2018 09:15

        Почему же не учтены? Они эквивалентны просто habrahabr.ru/post/346198


        1. delvin-fil
          10.01.2018 14:09

          эквивалентны

          Я знаю, но имел ввиду другое.
          Многие люди пользуются фидерами и о них, фидерах, ни слова. А мне было бы интересно узнать процент от общего количества пользователей.


          1. cointegrated Автор
            10.01.2018 14:15

            Насколько я понимаю, открытых данных о доле просмотров Хабра через фидеры нет.
            Можно попробовать спросить у его админов :)


            1. delvin-fil
              10.01.2018 14:17

              ХМ! Действительно, не подумал. :(


  1. System12
    09.01.2018 12:25

    Неплохая статистическая подборка для анализа.


  1. user-vova
    09.01.2018 12:50

    "Во-первых, говорят, что создавать больше процессов, чем ядер в процессоре, бесполезно."


    С чего бы это? Вы же не асинхронное приложение пишите. А операции IO прекрасный кандидат для многопоточного приложения.


  1. Gorodnya
    09.01.2018 13:55

    «Живых» статей оказалась только половина от потенциального максимума — 166307 штук. Про остальные Хабр даёт варианты «страница устарела, была удалена или не существовала вовсе». Что ж, всякое бывает.

    Где-то видел комментарий, что такая нумерация статей (грубо говоря, через одну) сделана намеренно.


    1. Squoworode
      09.01.2018 17:40

      Это последствия отделения Geektimes


  1. andreyons
    09.01.2018 17:41

    Во-первых, я собираюсь построить модель, прогнозирующую количество просмотров статьи в зависимости от её содержания.

    Тут ведь ещё и время решает + естественный рост аудитории, да?
    Во-вторых, хочется научить нейросеть генерировать тексты в той же стилистике, что и у авторов Хабра.

    Как Ализар? =)


    1. cointegrated Автор
      09.01.2018 17:42

      Время решает, но можно попытаться включить его как фактор) Ну или ограничиться комментариями, для которых точно известно время.

      Можно ссылку на статью Ализара? :)


      1. BuriK666
        09.01.2018 20:50

        у него их 2.4к. alizar


  1. Ekzodev
    09.01.2018 17:41

    Весьма занятно, спасибо!
    Подобную задачку решаю сейчас на досуге над другим известным порталом.
    В ожидании вашего дата сета в общем доступе.


  1. Rebel028
    09.01.2018 17:41

    «Живых» статей оказалась только половина от потенциального максимума — 166307 штук. Про остальные Хабр даёт варианты «страница устарела, была удалена или не существовала вовсе».

    Чтобы получить больше результатов можно попробовать парсить через сохабр, например, и/или другие архивы


    1. zartarn
      10.01.2018 09:31

      Сохабр этому ой как не обрадуется. Ему порой и так тяжко.


  1. sfocusov
    10.01.2018 14:05

    Интересно, это сеошники именно с Хабра ушли или из SEO в принципе… А то был такой тренд одно время — Panda и Penguin подсобили :)
    cointegrated Не подскажете пост/статью, как парсить с помощью Python (для чайников)?


    1. cointegrated Автор
      10.01.2018 14:09

      sfocusov, тут есть два подхода.
      Можно get-запросами тягать сырые странички, и парсить с помощью beautifulsoup — вот здесь есть пример habrahabr.ru/post/280238
      А если ваши странички сложные, и там должны отрабатывать джаваскрипты, то можно использовать Selenium, чтобы управлять из питона браузером — как тут vk.com/wall-130785301_96 или тут habrahabr.ru/post/131966


      1. sfocusov
        10.01.2018 14:15

        Отлично. Спасибо!


  1. MagicMight
    10.01.2018 16:16

    Самое любопытное, что в ноябре я сделал ровно то же самое! Написал парсер, который проходит по всем статьям каждого хаба от начала времен.
    Заленился, разве что, на рисовании графиков и собственно написания статьи
    В любом случае, занятно, что за короткий промежуток времени вижу точную реализацию собственной мысли!