Habrastatistics: menjelajahi bagian situs yang paling banyak dikunjungi dan paling tidak dikunjungi

Hai, Habr.

Pada bagian sebelumnya , kehadiran Habr dianalisis dengan parameter utama - jumlah artikel, pandangan dan peringkat mereka. Namun, pertanyaan tentang popularitas bagian situs tidak dipertimbangkan. Menjadi menarik untuk memeriksa ini secara lebih rinci, dan menemukan hub paling populer dan paling tidak populer. Akhirnya, saya akan memeriksa "efek geektimes" secara lebih rinci, dan pada akhirnya, pembaca akan menerima pilihan baru dari artikel-artikel terbaik pada peringkat baru.



Siapa peduli apa yang terjadi, terus di bawah luka.

Saya mengingatkan Anda sekali lagi bahwa statistik dan peringkat tidak resmi, saya tidak memiliki informasi orang dalam. Juga tidak dijamin bahwa saya tidak salah tempat atau tidak melewatkan sesuatu. Tapi tetap saja, saya pikir itu menarik. Kami akan mulai dengan kode terlebih dahulu, kepada siapa ini tidak relevan, bagian pertama dapat dilewati.

Pengumpulan data


Dalam versi parser pertama, hanya jumlah tampilan, komentar, dan peringkat artikel yang diperhitungkan. Ini sudah bagus, tetapi tidak memungkinkan Anda untuk membuat pertanyaan yang lebih kompleks. Sudah waktunya untuk menganalisis bagian tematik dari situs ini, ini akan memungkinkan kami untuk melakukan studi yang cukup menarik, misalnya, untuk melihat bagaimana popularitas bagian "C ++" telah berubah selama beberapa tahun.

Pengurai artikel telah diperbaiki, sekarang mengembalikan hub tempat artikel tersebut berada, serta nama panggilan penulis dan peringkatnya (di sini Anda juga dapat melakukan banyak hal menarik, tetapi ini nanti). Data disimpan dalam file csv kira-kira tipe berikut:

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 ... 

Dapatkan daftar hub tematik utama situs.

 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) 

Fungsi find_between dan kelas Str menyoroti garis antara dua tag, saya menggunakannya sebelumnya . Hub tematik ditandai dengan "*", sehingga mudah disorot, Anda juga dapat menghapus tanda komentar pada baris yang sesuai untuk mendapatkan bagian dari kategori lain.

Pada output fungsi get_hubs, kami mendapatkan daftar yang cukup mengesankan, yang kami simpan sebagai kamus. Saya secara khusus mengutip seluruh daftar sehingga volumenya dapat diperkirakan.

 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'} 

Sebagai perbandingan, bagian geektimes terlihat lebih sederhana:

 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'} 

Demikian pula, hub yang tersisa diselamatkan. Sekarang mudah untuk menulis fungsi yang mengembalikan hasilnya, artikel merujuk ke geektimes atau ke hub profil.

 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 

Fungsi serupa dibuat untuk bagian lain ("pengembangan", "administrasi", dll.).

Pengolahan


Saatnya memulai analisis. Kami memuat dataset dan memproses data hub.

 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) 

Sekarang kita dapat mengelompokkan data berdasarkan hari dan menampilkan jumlah publikasi berdasarkan hub yang berbeda.

 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() 

Tampilkan jumlah artikel yang diterbitkan menggunakan Matplotlib:



Saya membagi artikel "geektimes" dan "hanya geektimes" dalam grafik, karena sebuah artikel dapat menjadi milik kedua bagian secara bersamaan (misalnya, "DIY" + "mikrokontroler" + "C ++"). Dengan β€œprofil” penunjukan, saya menyoroti artikel-artikel profil dari situs tersebut, walaupun ada kemungkinan bahwa profil istilah bahasa Inggris tidak cukup tepat untuk ini.

Pada bagian sebelumnya kami bertanya tentang "efek geektimes" yang terkait dengan perubahan aturan untuk membayar artikel untuk geektimes dari musim panas ini. Kami memperoleh artikel geektimes terpisah:

 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() 

Hasilnya menarik. Rasio perkiraan tampilan artikel geektimes dengan total sekitar 1: 5. Tetapi jika jumlah total penayangan berfluktuasi secara nyata, maka tampilan artikel "menghibur" dipertahankan pada tingkat yang hampir sama.



Anda juga dapat melihat bahwa jumlah total penayangan artikel di bagian "geektimes" setelah mengubah aturan masih turun, tetapi "dengan mata", tidak lebih dari 5% dari total nilai.

Sangat menarik untuk melihat jumlah rata-rata tampilan per artikel:



Untuk artikel "menghibur", sekitar 40% di atas rata-rata. Ini mungkin tidak mengejutkan. Kegagalan pada awal April tidak jelas bagi saya, mungkin itu, atau itu semacam kesalahan parsing, atau mungkin salah satu penulis geektimes pergi berlibur;).

By the way, pada grafik adalah dua puncak yang lebih terlihat dalam jumlah tampilan artikel - liburan Tahun Baru dan Mei.

Hub


Mari kita beralih ke analisis hub yang dijanjikan. Kami akan menampilkan 20 hub teratas berdasarkan jumlah tampilan:

 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() 

Hasil:



Yang mengejutkan, hub "Keamanan Informasi" ternyata menjadi yang paling populer dalam hal tampilan, juga "Pemrograman" dan "Ilmu pengetahuan populer" berada di 5 pemimpin teratas.

Antitope mengambil Gtk dan Cocoa.



Saya akan memberi tahu Anda sebuah rahasia, hub teratas juga dapat dilihat di sini , meskipun jumlah tampilan tidak ditampilkan di sana.

Peringkat


Dan akhirnya, peringkat yang dijanjikan. Menggunakan data dari analisis hub, kami dapat menampilkan artikel paling populer di hub paling populer untuk tahun 2019 ini.

Keamanan informasi


Pemrograman


Ilmu pengetahuan populer


Karier


Perundang-undangan di bidang TI


Pengembangan web


GTK

Dan akhirnya, agar tidak menyinggung siapa pun, saya akan memberi Anda peringkat "gtk" hub yang paling jarang dikunjungi. Di dalamnya, satu artikel diterbitkan sepanjang tahun, itu juga "secara otomatis" menempati peringkat pertama peringkat.


Kesimpulan


Tidak akan ada kesimpulan. Nikmati membaca untuk semua orang.

Source: https://habr.com/ru/post/id467429/


All Articles