Habrastatistics: Entdeckt déi meescht an mannst besicht Sektioune vum Site

Hey Habr.

В virdrun Deel Den Habr Traffic gouf no den Haaptparameter analyséiert - d'Zuel vun den Artikelen, hir Meenungen a Bewäertungen. Wéi och ëmmer, d'Fro vun der Popularitéit vun de Site Sektiounen blouf net ënnersicht. Et gouf interessant dëst méi am Detail ze kucken an déi populärsten an onpopulärsten Hubs ze fannen. Schlussendlech wäert ech de Geektimes Effekt méi detailléiert kucken, op en Enn mat enger neier Auswiel vun de beschten Artikelen baséiert op neie Ranking.

Habrastatistics: Entdeckt déi meescht an mannst besicht Sektioune vum Site

Fir déi, déi interesséiert sinn wat geschitt ass, ass d'Fortsetzung ënner dem Schnëtt.

Loosst mech Iech nach eng Kéier drun erënneren datt d'Statistiken an d'Bewäertungen net offiziell sinn, ech hu keng Insiderinformatioun. Et ass och net garantéiert datt ech iergendwou kee Feeler gemaach hunn oder eppes verpasst hunn. Awer trotzdem mengen ech, datt et interessant ass. Mir fänke fir d'éischt mam Code un, déi net drun interesséiert sinn, kënnen déi éischt Rubriken iwwersprangen.

Datensammlung

An der éischter Versioun vum Parser gouf nëmmen d'Zuel vun de Meenungen, Kommentaren an Artikel Bewäertungen berücksichtegt. Dëst ass scho gutt, awer et erlaabt Iech net méi komplex Ufroen ze maachen. Et ass Zäit d'thematesch Sektiounen vum Site ze analyséieren, dëst erlaabt Iech ganz interessant Fuerschung ze maachen, zum Beispill, kuckt wéi d'Popularitéit vun der "C++" Sektioun iwwer e puer Joer geännert huet.

Den Artikel Parser gouf verbessert, elo gëtt et d'Hubs zréck, zu deenen den Artikel gehéiert, souwéi de Spëtznumm vum Auteur a seng Bewäertung (vill interessant Saache kënnen och hei gemaach ginn, awer dat wäert méi spéit kommen). D'Date ginn an enger Csv-Datei gespäichert déi sou ausgesäit:

2018-12-18T12:43Z,https://habr.com/ru/post/433550/,"Мессенджер Slack — причины выбора, косяки при внедрении и особенности сервиса, облегчающие жизнь",votes:7,votesplus:8,votesmin:1,bookmarks:32,
views:8300,comments:10,user:ReDisque,karma:5,subscribers:2,hubs:productpm+soft
...

Mir kréien eng Lëscht vun den Haaptthemateschen Hubs vum Site.

def get_as_str(link: str) -> Str:
    try:
        r = requests.get(link)
        return Str(r.text)
    except Exception as e:
        return Str("")

def get_hubs():
    hubs = []
    for p in range(1, 12):
        page_html = get_as_str("https://habr.com/ru/hubs/page%d/" % p)
        # page_html = get_as_str("https://habr.com/ru/hubs/geektimes/page%d/" % p)  # Geektimes
        # page_html = get_as_str("https://habr.com/ru/hubs/develop/page%d/" % p)  # Develop
        # page_html = get_as_str("https://habr.com/ru/hubs/admin/page%d" % p)  # Admin
        for hub in page_html.split("media-obj media-obj_hub"):
            info = Str(hub).find_between('"https://habr.com/ru/hub', 'list-snippet__tags') 
            if "*</span>" in info:
                hub_name = info.find_between('/', '/"')
                if len(hub_name) > 0 and len(hub_name) < 32:
                    hubs.append(hub_name)
    print(hubs)

D'find_between Funktioun an d'Str Klass wielt e String tëscht zwee Tags, ech hunn se benotzt virdrun. Thematesch Hubs si mat engem "*" markéiert fir datt se einfach identifizéiert kënne ginn, an Dir kënnt och déi entspriechend Zeilen unkommentéieren fir Sektiounen vun anere Kategorien ze kréien.

D'Ausgab vun der get_hubs Funktioun ass eng zimlech beandrockend Lëscht, déi mir als Wierderbuch späicheren. Ech presentéieren speziell d'Lëscht a senger Ganzheet, fir datt Dir säi Volumen schätze kënnt.

hubs_profile = {'infosecurity', 'programming', 'webdev', 'python', 'sys_admin', 'it-infrastructure', 'devops', 'javascript', 'open_source', 'network_technologies', 'gamedev', 'cpp', 'machine_learning', 'pm', 'hr_management', 'linux', 'analysis_design', 'ui', 'net', 'hi', 'maths', 'mobile_dev', 'productpm', 'win_dev', 'it_testing', 'dev_management', 'algorithms', 'go', 'php', 'csharp', 'nix', 'data_visualization', 'web_testing', 's_admin', 'crazydev', 'data_mining', 'bigdata', 'c', 'java', 'usability', 'instant_messaging', 'gtd', 'system_programming', 'ios_dev', 'oop', 'nginx', 'kubernetes', 'sql', '3d_graphics', 'css', 'geo', 'image_processing', 'controllers', 'game_design', 'html5', 'community_management', 'electronics', 'android_dev', 'crypto', 'netdev', 'cisconetworks', 'db_admins', 'funcprog', 'wireless', 'dwh', 'linux_dev', 'assembler', 'reactjs', 'sales', 'microservices', 'search_technologies', 'compilers', 'virtualization', 'client_side_optimization', 'distributed_systems', 'api', 'media_management', 'complete_code', 'typescript', 'postgresql', 'rust', 'agile', 'refactoring', 'parallel_programming', 'mssql', 'game_promotion', 'robo_dev', 'reverse-engineering', 'web_analytics', 'unity', 'symfony', 'build_automation', 'swift', 'raspberrypi', 'web_design', 'kotlin', 'debug', 'pay_system', 'apps_design', 'git', 'shells', 'laravel', 'mobile_testing', 'openstreetmap', 'lua', 'vs', 'yii', 'sport_programming', 'service_desk', 'itstandarts', 'nodejs', 'data_warehouse', 'ctf', 'erp', 'video', 'mobileanalytics', 'ipv6', 'virus', 'crm', 'backup', 'mesh_networking', 'cad_cam', 'patents', 'cloud_computing', 'growthhacking', 'iot_dev', 'server_side_optimization', 'latex', 'natural_language_processing', 'scala', 'unreal_engine', 'mongodb', 'delphi',  'industrial_control_system', 'r', 'fpga', 'oracle', 'arduino', 'magento', 'ruby', 'nosql', 'flutter', 'xml', 'apache', 'sveltejs', 'devmail', 'ecommerce_development', 'opendata', 'Hadoop', 'yandex_api', 'game_monetization', 'ror', 'graph_design', 'scada', 'mobile_monetization', 'sqlite', 'accessibility', 'saas', 'helpdesk', 'matlab', 'julia', 'aws', 'data_recovery', 'erlang', 'angular', 'osx_dev', 'dns', 'dart', 'vector_graphics', 'asp', 'domains', 'cvs', 'asterisk', 'iis', 'it_monetization', 'localization', 'objectivec', 'IPFS', 'jquery', 'lisp', 'arvrdev', 'powershell', 'd', 'conversion', 'animation', 'webgl', 'wordpress', 'elm', 'qt_software', 'google_api', 'groovy_grails', 'Sailfish_dev', 'Atlassian', 'desktop_environment', 'game_testing', 'mysql', 'ecm', 'cms', 'Xamarin', 'haskell', 'prototyping', 'sw', 'django', 'gradle', 'billing', 'tdd', 'openshift', 'canvas', 'map_api', 'vuejs', 'data_compression', 'tizen_dev', 'iptv', 'mono', 'labview', 'perl', 'AJAX', 'ms_access', 'gpgpu', 'infolust', 'microformats', 'facebook_api', 'vba', 'twitter_api', 'twisted', 'phalcon', 'joomla', 'action_script', 'flex', 'gtk', 'meteorjs', 'iconoskaz', 'cobol', 'cocoa', 'fortran', 'uml', 'codeigniter', 'prolog', 'mercurial', 'drupal', 'wp_dev', 'smallbasic', 'webassembly', 'cubrid', 'fido', 'bada_dev', 'cgi', 'extjs', 'zend_framework', 'typography', 'UEFI', 'geo_systems', 'vim', 'creative_commons', 'modx', 'derbyjs', 'xcode', 'greasemonkey', 'i2p', 'flash_platform', 'coffeescript', 'fsharp', 'clojure', 'puppet', 'forth', 'processing_lang', 'firebird', 'javame_dev', 'cakephp', 'google_cloud_vision_api', 'kohanaphp', 'elixirphoenix', 'eclipse', 'xslt', 'smalltalk', 'googlecloud', 'gae', 'mootools', 'emacs', 'flask', 'gwt', 'web_monetization', 'circuit-design', 'office365dev', 'haxe', 'doctrine', 'typo3', 'regex', 'solidity', 'brainfuck', 'sphinx', 'san', 'vk_api', 'ecommerce'}

Zum Verglach kucken d'Geektimes Sektiounen méi bescheiden aus:

hubs_gt = {'popular_science', 'history', 'soft', 'lifehacks', 'health', 'finance', 'artificial_intelligence', 'itcompanies', 'DIY', 'energy', 'transport', 'gadgets', 'social_networks', 'space', 'futurenow', 'it_bigraphy', 'antikvariat', 'games', 'hardware', 'learning_languages', 'urban', 'brain', 'internet_of_things', 'easyelectronics', 'cellular', 'physics', 'cryptocurrency', 'interviews', 'biotech', 'network_hardware', 'autogadgets', 'lasers', 'sound', 'home_automation', 'smartphones', 'statistics', 'robot', 'cpu', 'video_tech', 'Ecology', 'presentation', 'desktops', 'wearable_electronics', 'quantum', 'notebooks', 'cyberpunk', 'Peripheral', 'demoscene', 'copyright', 'astronomy', 'arvr', 'medgadgets', '3d-printers', 'Chemistry', 'storages', 'sci-fi', 'logic_games', 'office', 'tablets', 'displays', 'video_conferencing', 'videocards', 'photo', 'multicopters', 'supercomputers', 'telemedicine', 'cybersport', 'nano', 'crowdsourcing', 'infographics'}

Déi reschtlech Hubs goufen op déiselwecht Manéier konservéiert. Elo ass et einfach eng Funktioun ze schreiwen déi d'Resultat zréckginn ob den Artikel zu Geektimes oder e Profilhub gehéiert.

def is_geektimes(hubs: List) -> bool:
    return len(set(hubs) & hubs_gt) > 0

def is_geektimes_only(hubs: List) -> bool:
    return is_geektimes(hubs) is True and is_profile(hubs) is False

def is_profile(hubs: List) -> bool:
    return len(set(hubs) & hubs_profile) > 0

Ähnlech Funktiounen goufen fir aner Sektiounen gemaach ("Entwécklung", "Administratioun", asw.).

Veraarbechtung

Et ass Zäit ze analyséieren. Mir lueden den Dataset a veraarbecht den Hubdaten.

def to_list(s: str) -> List[str]:
    # "user:popular_science+astronomy" => [popular_science, astronomy]
    return s.split(':')[1].split('+')

def to_date(dt: datetime) -> datetime.date:
    return dt.date()

df = pd.read_csv("habr_2019.csv", sep=',', encoding='utf-8', error_bad_lines=True, quotechar='"', comment='#')
dates = pd.to_datetime(df['datetime'], format='%Y-%m-%dT%H:%MZ')
dates += datetime.timedelta(hours=3)
df['date'] = dates.map(to_date, na_action=None)
hubs = df["hubs"].map(to_list, na_action=None)
df['hubs'] = hubs
df['is_profile'] = hubs.map(is_profile, na_action=None)
df['is_geektimes'] = hubs.map(is_geektimes, na_action=None)
df['is_geektimes_only'] = hubs.map(is_geektimes_only, na_action=None)
df['is_admin'] = hubs.map(is_admin, na_action=None)
df['is_develop'] = hubs.map(is_develop, na_action=None)

Elo kënne mir d'Donnéeën no Dag gruppéieren an d'Zuel vun de Publikatiounen fir verschidden Hubs weisen.

g = df.groupby(['date'])
days_count = g.size().reset_index(name='counts')
year_days = days_count['date'].values
grouped = g.sum().reset_index()
profile_per_day_avg = grouped['is_profile'].rolling(window=20, min_periods=1).mean()
geektimes_per_day_avg = grouped['is_geektimes'].rolling(window=20, min_periods=1).mean()
geektimesonly_per_day_avg = grouped['is_geektimes_only'].rolling(window=20, min_periods=1).mean()
admin_per_day_avg = grouped['is_admin'].rolling(window=20, min_periods=1).mean()
develop_per_day_avg = grouped['is_develop'].rolling(window=20, min_periods=1).mean()

Mir weisen d'Zuel vun publizéierten Artikelen mat Matplotlib:

Habrastatistics: Entdeckt déi meescht an mannst besicht Sektioune vum Site

Ech hunn d'Artikelen "geektimes" an "geektimes nëmmen" an der Grafik opgedeelt, well En Artikel kann zu béide Sektiounen zur selwechter Zäit gehéieren (zum Beispill "DIY" + "Mikrokontroller" + "C++"). Ech hunn d'Bezeechnung "Profil" benotzt fir Profilartikelen um Site ze markéieren, obwuel vläicht den englesche Begrëff Profil fir dëst net ganz korrekt ass.

Am viregten Deel hu mir gefrot iwwer den "Geektimes Effekt" verbonne mat der Ännerung vun de Bezuelregele fir Artikele fir Geektimes ab dësem Summer. Loosst eis d'Geektimes Artikelen separat weisen:

df_gt = df[(df['is_geektimes_only'] == True)]
group_gt = df_gt.groupby(['date'])
days_count_gt = group_gt.size().reset_index(name='counts')
grouped = group_gt.sum().reset_index()
year_days_gt = days_count_gt['date'].values
view_gt_per_day_avg = grouped['views'].rolling(window=20, min_periods=1).mean()

D'Resultat ass interessant. De geschätzte Verhältnis vu Meenunge vu Geektimes Artikelen zum Gesamt ass iergendwou ongeféier 1:5. Awer wärend d'Gesamtzuel vun de Meenungen däitlech schwankt, ass d'Kucke vun "Entertainment" Artikelen ongeféier um selwechten Niveau bliwwen.

Habrastatistics: Entdeckt déi meescht an mannst besicht Sektioune vum Site

Dir kënnt och bemierken datt d'Gesamtzuel vun de Meenungen vun Artikelen an der Rubrik "Geektimes" nach ëmmer gefall ass nodeems Dir d'Regele geännert hutt, awer "duerch Auge", net méi wéi 5% vun de Gesamtwäerter.

Et ass interessant déi duerchschnëttlech Unzuel vun Meenungen pro Artikel ze kucken:

Habrastatistics: Entdeckt déi meescht an mannst besicht Sektioune vum Site

Fir "Entertainment" Artikelen ass et ongeféier 40% iwwer der Moyenne. Dëst ass wahrscheinlech net iwwerraschend. Den Echec Ufank Abrëll ass fir mech onverständlech, vläicht ass dat geschitt, oder et ass eng Zort Parsing-Feeler, oder vläicht ass ee vun de Geektime Autoren an d'Vakanz gaang ;).

Iwwregens, weist d'Grafik zwee méi bemierkenswäert Peaks an der Unzuel vun Meenungen vun Artikelen - d'New Joer a Mee Vakanz.

Hubs

Loosst eis op déi versprach Analyse vun Hubs weidergoen. Loosst eis déi Top 20 Hubs no Unzuel u Meenungen oplëschten:

hubs_info = []
for hub_name in hubs_all:
    mask = df['hubs'].apply(lambda x: hub_name in x)
    df_hub = df[mask]

    count, views = df_hub.shape[0], df_hub['views'].sum()
    hubs_info.append((hub_name, count, views))

# Draw hubs
hubs_top = sorted(hubs_info, key=lambda v: v[2], reverse=True)[:20]
top_views = list(map(lambda x: x[2], hubs_top))
top_names = list(map(lambda x: x[0], hubs_top))

plt.rcParams["figure.figsize"] = (8, 6)
plt.bar(range(0, len(top_views)), top_views)
plt.xticks(range(0, len(top_names)), top_names, rotation=90)
plt.ticklabel_format(style='plain', axis='y')
plt.tight_layout()
plt.show()

Resultat:

Habrastatistics: Entdeckt déi meescht an mannst besicht Sektioune vum Site

Iwwerraschend war de populäersten Hub a punkto Meenungen "Informatiounssécherheet" déi Top 5 Leader hunn och "Programméierung" a "Popularwëssenschaft" abegraff;

Antitop besetzt Gtk a Kakao.

Habrastatistics: Entdeckt déi meescht an mannst besicht Sektioune vum Site

Ech soen Iech e Geheimnis, déi Top Hubs kënnen och gesi ginn hei, obwuel d'Zuel vun de Meenungen do net ugewise gëtt.

Rating

An endlech, déi versprach Bewäertung. Mat Hub Analysedaten kënne mir déi populärste Artikele fir déi populärste Hubs fir dëst Joer 2019 weisen.

Informatioun Sécherheet

Programméieren

Populär Wëssenschaft

Karriär

Gesetzgebung an IT

Web Entwécklung

GTK

A schlussendlech, fir datt keen beleidegt ass, ginn ech d'Bewäertung vum mannst besichten Hub "gtk". Bannent engem Joer gouf et publizéiert одна Den Artikel, deen och "automatesch" déi éischt Zeil vun der Bewäertung besetzt.

Konklusioun

Et gëtt keng Conclusioun. Vill Gléck fir jiddereen ze liesen.

Source: will.com

Setzt e Commentaire