Habrastatistik: meneroka bahagian tapak yang paling banyak dan paling kurang dilawati

Hai Habr.

Π’ bahagian sebelumnya Trafik Habr dianalisis mengikut parameter utama - bilangan artikel, pandangan dan penilaian mereka. Walau bagaimanapun, isu populariti bahagian tapak kekal tidak diteliti. Menjadi menarik untuk melihat perkara ini dengan lebih terperinci dan mencari hab yang paling popular dan paling tidak popular. Akhir sekali, saya akan melihat kesan geektimes dengan lebih terperinci, berakhir dengan pilihan baharu artikel terbaik berdasarkan kedudukan baharu.

Habrastatistik: meneroka bahagian tapak yang paling banyak dan paling kurang dilawati

Bagi mereka yang berminat dengan apa yang berlaku, kesinambungan adalah di bawah pemotongan.

Izinkan saya mengingatkan anda sekali lagi bahawa statistik dan penilaian tidak rasmi, saya tidak mempunyai sebarang maklumat orang dalam. Ia juga tidak dijamin bahawa saya tidak membuat kesilapan di suatu tempat atau terlepas sesuatu. Tetapi tetap, saya fikir ia ternyata menarik. Kami akan mulakan dengan kod dahulu; mereka yang tidak berminat dengan ini boleh melangkau bahagian pertama.

Pengumpulan data

Dalam versi pertama penghurai, hanya bilangan paparan, ulasan dan penarafan artikel diambil kira. Ini sudah bagus, tetapi ia tidak membenarkan anda membuat pertanyaan yang lebih kompleks. Sudah tiba masanya untuk menganalisis bahagian tematik tapak ini; ini akan membolehkan anda melakukan penyelidikan yang agak menarik, sebagai contoh, melihat bagaimana populariti bahagian "C++" telah berubah selama beberapa tahun.

Penghurai artikel telah dipertingkatkan, kini ia mengembalikan hab kepunyaan artikel itu, serta nama samaran pengarang dan penilaiannya (banyak perkara menarik juga boleh dilakukan di sini, tetapi itu akan datang kemudian). Data disimpan dalam fail csv yang kelihatan seperti ini:

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

Kami akan menerima senarai hab tematik utama tapak.

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 memilih rentetan antara dua tag, saya menggunakannya sebelum ini. Hab tematik ditandakan dengan "*" supaya ia boleh diserlahkan dengan mudah dan anda juga boleh menyahkomen baris yang sepadan untuk mendapatkan bahagian kategori lain.

Output fungsi get_hubs ialah senarai yang agak mengagumkan, yang kami simpan sebagai kamus. Saya secara khusus membentangkan senarai secara keseluruhan supaya anda boleh menganggarkan jumlahnya.

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, bahagian geektimes kelihatan 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'}

Hab yang selebihnya dipelihara dengan cara yang sama. Kini mudah untuk menulis fungsi yang mengembalikan hasil sama ada artikel itu milik geektimes atau hab 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 telah dibuat untuk bahagian lain ("pembangunan", "pentadbiran", dll.).

Pemprosesan

Sudah tiba masanya untuk mula menganalisis. Kami memuatkan set data dan memproses data hab.

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)

Kini kita boleh mengumpulkan data mengikut hari dan memaparkan bilangan penerbitan untuk hab yang berbeza.

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

Kami memaparkan bilangan artikel yang diterbitkan menggunakan Matplotlib:

Habrastatistik: meneroka bahagian tapak yang paling banyak dan paling kurang dilawati

Saya membahagikan artikel "masa geek" dan "masa geek sahaja" dalam carta, kerana Artikel boleh tergolong dalam kedua-dua bahagian pada masa yang sama (contohnya, "DIY" + "mikropengawal" + "C++"). Saya menggunakan sebutan "profil" untuk menyerlahkan artikel profil di tapak, walaupun mungkin profil istilah bahasa Inggeris untuk ini tidak betul sepenuhnya.

Pada bahagian sebelumnya kami bertanya tentang "kesan masa geek" yang dikaitkan dengan perubahan dalam peraturan pembayaran untuk artikel untuk masa geek mulai musim panas ini. Mari paparkan artikel geektimes secara berasingan:

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. Nisbah anggaran paparan artikel masa geek kepada jumlah keseluruhan adalah sekitar 1:5. Tetapi sementara jumlah tontonan turun naik dengan ketara, tontonan artikel "hiburan" kekal pada tahap yang lebih kurang sama.

Habrastatistik: meneroka bahagian tapak yang paling banyak dan paling kurang dilawati

Anda juga dapat melihat bahawa jumlah tontonan artikel dalam bahagian "masa geek" masih jatuh selepas menukar peraturan, tetapi "mengikut mata", tidak lebih daripada 5% daripada jumlah nilai.

Adalah menarik untuk melihat purata bilangan tontonan setiap artikel:

Habrastatistik: meneroka bahagian tapak yang paling banyak dan paling kurang dilawati

Untuk artikel "hiburan" adalah kira-kira 40% di atas purata. Ini mungkin tidak menghairankan. Kegagalan pada awal April tidak jelas bagi saya, mungkin itulah yang berlaku, atau ia adalah sejenis ralat penghuraian, atau mungkin salah seorang penulis geektimes pergi bercuti;).

Dengan cara ini, graf menunjukkan dua lagi puncak yang ketara dalam bilangan paparan artikel - cuti Tahun Baru dan Mei.

Hab

Mari kita beralih kepada analisis hab yang dijanjikan. Mari senaraikan 20 hab teratas mengikut bilangan paparan:

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

Keputusan:

Habrastatistik: meneroka bahagian tapak yang paling banyak dan paling kurang dilawati

Yang menghairankan, hab yang paling popular dari segi pandangan ialah "Keselamatan Maklumat"; 5 pemimpin teratas juga termasuk "Pengaturcaraan" dan "Sains popular".

Antitop menduduki Gtk dan Koko.

Habrastatistik: meneroka bahagian tapak yang paling banyak dan paling kurang dilawati

Saya akan memberitahu anda satu rahsia, hab teratas juga boleh dilihat di sini, walaupun bilangan tontonan tidak ditunjukkan di sana.

Penilaian

Dan akhirnya, rating yang dijanjikan. Menggunakan data analisis hab, kami boleh memaparkan artikel paling popular untuk hab paling popular untuk tahun 2019 ini.

Keselamatan maklumat

Pengaturcaraan

Sains Popular

kerjaya

Perundangan dalam IT

Pembangunan web

GTK

Dan akhirnya, supaya tiada siapa yang tersinggung, saya akan memberikan penarafan hab yang paling kurang dikunjungi "gtk". Dalam masa setahun ia diterbitkan 1 Artikel, yang juga "secara automatik" menduduki baris pertama penilaian.

Kesimpulan

Tidak akan ada kesimpulan. Selamat membaca semua.

Sumber: www.habr.com

Tambah komen