Habrastatistics: paggalugad sa pinakamadalas at hindi gaanong binibisitang mga seksyon ng site

Hoy Habr.

Π’ naunang bahagi Ang trapiko ni Habr ay nasuri ayon sa mga pangunahing parameter - ang bilang ng mga artikulo, ang kanilang mga view at rating. Gayunpaman, ang isyu ng katanyagan ng mga seksyon ng site ay nanatiling hindi napagmasdan. Naging kawili-wiling tingnan ito nang mas detalyado at hanapin ang pinakasikat at hindi sikat na mga hub. Sa wakas, titingnan ko ang epekto ng geektimes nang mas detalyado, na nagtatapos sa isang bagong seleksyon ng pinakamahusay na mga artikulo batay sa mga bagong ranggo.

Habrastatistics: paggalugad sa pinakamadalas at hindi gaanong binibisitang mga seksyon ng site

Para sa mga interesado sa nangyari, under the cut ang pagpapatuloy.

Paalalahanan ko kayong muli na ang mga istatistika at rating ay hindi opisyal, wala akong anumang impormasyon sa tagaloob. Hindi rin garantisado na hindi ako nagkamali sa kung saan o may napalampas. Ngunit gayon pa man, sa tingin ko ito ay naging kawili-wili. Magsisimula muna tayo sa code; maaaring laktawan ng mga hindi interesado dito ang mga unang seksyon.

Pagkolekta ng data

Sa unang bersyon ng parser, ang bilang lamang ng mga view, komento at mga rating ng artikulo ang isinasaalang-alang. Maganda na ito, ngunit hindi ka nito pinapayagang gumawa ng mas kumplikadong mga query. Panahon na upang pag-aralan ang mga pampakay na seksyon ng site; ito ay magbibigay-daan sa iyo na gumawa ng medyo kawili-wiling pananaliksik, halimbawa, tingnan kung paano nagbago ang katanyagan ng seksyong "C++" sa loob ng ilang taon.

Ang parser ng artikulo ay napabuti, ngayon ay ibinabalik nito ang mga hub kung saan kabilang ang artikulo, pati na rin ang palayaw ng may-akda at ang kanyang rating (maraming kawili-wiling mga bagay ang maaaring gawin dito, ngunit darating iyon sa ibang pagkakataon). Ang data ay nai-save sa isang csv file na mukhang ganito:

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

Makakatanggap kami ng listahan ng mga pangunahing thematic hub ng 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)

Ang find_between function at ang Str class ay pumili ng isang string sa pagitan ng dalawang tag, ginamit ko ang mga ito mas maaga. Ang mga thematic hub ay minarkahan ng "*" para madaling ma-highlight ang mga ito, at maaari mo ring i-uncomment ang mga kaukulang linya upang makakuha ng mga seksyon ng iba pang mga kategorya.

Ang output ng get_hubs function ay isang medyo kahanga-hangang listahan, na ise-save namin bilang isang diksyunaryo. Partikular kong inilalahad ang listahan sa kabuuan nito upang matantya mo ang dami nito.

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

Para sa paghahambing, ang mga seksyon ng geektimes ay mukhang mas katamtaman:

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

Ang natitirang mga hub ay napanatili sa parehong paraan. Ngayon ay madali nang magsulat ng isang function na nagbabalik ng resulta kung ang artikulo ay kabilang sa geektimes o isang profile hub.

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

Ang mga katulad na function ay ginawa para sa iba pang mga seksyon ("pag-unlad", "administrasyon", atbp.).

Pagproseso

Panahon na upang simulan ang pagsusuri. Nilo-load namin ang dataset at pinoproseso ang data ng 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)

Ngayon ay maaari na nating ipangkat ang data ayon sa araw at ipakita ang bilang ng mga publikasyon para sa iba't ibang hub.

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

Ipinapakita namin ang bilang ng mga nai-publish na artikulo gamit ang Matplotlib:

Habrastatistics: paggalugad sa pinakamadalas at hindi gaanong binibisitang mga seksyon ng site

Hinati ko ang mga artikulong "geektimes" at "geektimes lang" sa chart, dahil Ang isang artikulo ay maaaring kabilang sa parehong mga seksyon sa parehong oras (halimbawa, "DIY" + "microcontrollers" + "C++"). Ginamit ko ang pagtatalagang "profile" upang i-highlight ang mga artikulo sa profile sa site, kahit na marahil ang English term na profile para dito ay hindi ganap na tama.

Sa nakaraang bahagi nagtanong kami tungkol sa "geektimes effect" na nauugnay sa pagbabago sa mga panuntunan sa pagbabayad para sa mga artikulo para sa mga geektime simula ngayong tag-init. Ipakita natin ang mga artikulo ng geektimes nang hiwalay:

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

Ang resulta ay kawili-wili. Ang tinatayang ratio ng mga view ng mga artikulo ng geektimes sa kabuuan ay nasa 1:5. Ngunit habang ang kabuuang bilang ng mga panonood ay kapansin-pansing nagbabago, ang panonood ng mga artikulong "entertainment" ay nanatili sa humigit-kumulang sa parehong antas.

Habrastatistics: paggalugad sa pinakamadalas at hindi gaanong binibisitang mga seksyon ng site

Maaari mo ring mapansin na ang kabuuang bilang ng mga view ng mga artikulo sa seksyong "geektimes" ay bumaba pa rin pagkatapos baguhin ang mga panuntunan, ngunit "sa pamamagitan ng mata", ng hindi hihigit sa 5% ng kabuuang mga halaga.

Ito ay kagiliw-giliw na tingnan ang average na bilang ng mga view sa bawat artikulo:

Habrastatistics: paggalugad sa pinakamadalas at hindi gaanong binibisitang mga seksyon ng site

Para sa mga artikulong "entertainment" ito ay humigit-kumulang 40% sa itaas ng average. Ito ay malamang na hindi nakakagulat. Ang kabiguan sa simula ng Abril ay hindi malinaw sa akin, marahil iyon ang nangyari, o ito ay isang uri ng error sa pag-parse, o marahil ang isa sa mga may-akda ng geektimes ay nagbakasyon ;).

Sa pamamagitan ng paraan, ang graph ay nagpapakita ng dalawang mas kapansin-pansin na mga taluktok sa bilang ng mga view ng mga artikulo - ang mga pista opisyal ng Bagong Taon at Mayo.

Mga hub

Lumipat tayo sa ipinangakong pagsusuri ng mga hub. Ilista natin ang nangungunang 20 hub ayon sa bilang ng mga view:

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

Resulta:

Habrastatistics: paggalugad sa pinakamadalas at hindi gaanong binibisitang mga seksyon ng site

Nakapagtataka, ang pinakasikat na hub sa mga tuntunin ng mga view ay "Seguridad ng Impormasyon"; kasama rin sa nangungunang 5 pinuno ang "Programming" at "Popular na agham."

Sinasakop ng Antitop ang Gtk at Cocoa.

Habrastatistics: paggalugad sa pinakamadalas at hindi gaanong binibisitang mga seksyon ng site

I'll tell you a secret, makikita rin ang mga top hub dito, kahit na ang bilang ng mga view ay hindi ipinapakita doon.

Marka

At sa wakas, ang ipinangakong rating. Gamit ang data ng pagsusuri sa hub, maipapakita namin ang pinakasikat na mga artikulo para sa mga pinakasikat na hub para sa taong ito 2019.

Seguridad ng impormasyon

Programming

Popular Science

karera

Batas sa IT

Pagbuo ng web

gTK

At sa wakas, para walang masaktan, ibibigay ko ang rating ng hindi gaanong binibisitang hub na "gtk". Sa loob ng isang taon ay nai-publish ito ΠΎΠ΄Π½Π° Ang artikulo, na "awtomatikong" din ay sumasakop sa unang linya ng rating.

Konklusyon

Walang magiging konklusyon. Maligayang pagbabasa sa lahat.

Pinagmulan: www.habr.com

Magdagdag ng komento