Π˜Π·Π²Π»ΠΈΡ‡Π°Π½Π΅ Π½Π° Π΄Π°Π½Π½ΠΈ Π·Π° Π°ΠΌΠΏΠ»ΠΈΡ‚ΡƒΠ΄Π°Ρ‚Π° Ρ‡Ρ€Π΅Π· API

въвСдСниС

Amplitude сС Π΅ Π΄ΠΎΠΊΠ°Π·Π°Π» ΠΌΠ½ΠΎΠ³ΠΎ Π΄ΠΎΠ±Ρ€Π΅ ΠΊΠ°Ρ‚ΠΎ инструмСнт Π·Π° ΠΏΡ€ΠΎΠ΄ΡƒΠΊΡ‚ΠΎΠ² Π°Π½Π°Π»ΠΈΠ· ΠΏΠΎΡ€Π°Π΄ΠΈ лСсната си настройка Π½Π° ΡΡŠΠ±ΠΈΡ‚ΠΈΡ ΠΈ Π³ΡŠΠ²ΠΊΠ°Π²ΠΎΡΡ‚Ρ‚Π° Π½Π° визуализацията. И чСсто ΠΈΠΌΠ° Π½ΡƒΠΆΠ΄Π° Π΄Π° настроитС свой собствСн ΠΌΠΎΠ΄Π΅Π» Π½Π° приписванС, Π΄Π° Π³Ρ€ΡƒΠΏΠΈΡ€Π°Ρ‚Π΅ ΠΏΠΎΡ‚Ρ€Π΅Π±ΠΈΡ‚Π΅Π»ΠΈ ΠΈΠ»ΠΈ Π΄Π° ΠΈΠ·Π³Ρ€Π°Π΄ΠΈΡ‚Π΅ Ρ‚Π°Π±Π»ΠΎ Π·Π° ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Π² Π΄Ρ€ΡƒΠ³Π° BI систСма. Π’ΡŠΠ·ΠΌΠΎΠΆΠ½ΠΎ Π΅ Π΄Π° сС ΠΈΠ·Π²ΡŠΡ€ΡˆΠΈ Ρ‚Π°ΠΊΠ°Π²Π° ΠΈΠ·ΠΌΠ°ΠΌΠ° само със сурови Π΄Π°Π½Π½ΠΈ Π·Π° ΡΡŠΠ±ΠΈΡ‚ΠΈΡ ΠΎΡ‚ Amplitude. Π’Π°Π·ΠΈ статия Ρ‰Π΅ Π²ΠΈ ΠΊΠ°ΠΆΠ΅ ΠΊΠ°ΠΊ Π΄Π° ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚Π΅ Ρ‚Π΅Π·ΠΈ Π΄Π°Π½Π½ΠΈ с ΠΌΠΈΠ½ΠΈΠΌΠ°Π»Π½ΠΈ познания ΠΏΠΎ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈΡ€Π°Π½Π΅.

ΠŸΡ€Π΅Π΄ΠΏΠΎΡΡ‚Π°Π²ΠΊΠΈ

  1. ΠŸΡ€ΠΎΠ΅ΠΊΡ‚ Π² Amplitude, Π² ΠΊΠΎΠΉΡ‚ΠΎ ΡΡŠΠ±ΠΈΡ‚ΠΈΡΡ‚Π° Π²Π΅Ρ‡Π΅ са ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€ΠΈΡ€Π°Π½ΠΈ ΠΏΡ€Π°Π²ΠΈΠ»Π½ΠΎ ΠΈ Π·Π° тях сС ΡΡŠΠ±ΠΈΡ€Π° статистика
  2. Python Π΅ инсталиран (работя във вСрсия 3.8.3), с ΠΊΠΎΠΉΡ‚ΠΎ потСнциалният Ρ‡ΠΈΡ‚Π°Ρ‚Π΅Π» Π²Π΅Ρ‡Π΅ ΠΌΠΎΠΆΠ΅ Π΄Π° Ρ€Π°Π±ΠΎΡ‚ΠΈ ΠΏΠΎΠ½Π΅ Π½Π° основно Π½ΠΈΠ²ΠΎ

Π˜Π½ΡΡ‚Ρ€ΡƒΠΊΡ†ΠΈΡ

Π‘Ρ‚ΡŠΠΏΠΊΠ° 1. ΠŸΠΎΠ»ΡƒΡ‡Π°Π²Π°Π½Π΅ Π½Π° API-ΠΊΠ»ΡŽΡ‡ ΠΈ сСкрСтСн ΠΊΠ»ΡŽΡ‡

Π—Π° Π΄Π° ΠΊΠ°Ρ‡ΠΈΡ‚Π΅ Π΄Π°Π½Π½ΠΈ, ΠΏΡŠΡ€Π²ΠΎ трябва Π΄Π° ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚Π΅ API ΠΊΠ»ΡŽΡ‡ ΠΈ Ρ‚Π°Π΅Π½ ΠΊΠ»ΡŽΡ‡.

ΠœΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° Π³ΠΈ Π½Π°ΠΌΠ΅Ρ€ΠΈΡ‚Π΅, ΠΊΠ°Ρ‚ΠΎ слСдватС слСдния ΠΏΡŠΡ‚:

  1. β€žΠ£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Π½Π° Π΄Π°Π½Π½ΠΈβ€œ (Π½Π°ΠΌΠΈΡ€Π° сС Π² долния ляв ъгъл Π½Π° Π΅ΠΊΡ€Π°Π½Π°)
  2. Π˜Π·Π±Π΅Ρ€Π΅Ρ‚Π΅ ТСлания ΠΏΡ€ΠΎΠ΅ΠΊΡ‚, ΠΎΡ‚ ΠΊΠΎΠΉΡ‚ΠΎ Ρ‰Π΅ сС изтСглят Π΄Π°Π½Π½ΠΈ, ΠΈ ΠΎΡ‚ΠΈΠ΄Π΅Ρ‚Π΅ Π½Π° Π½Π΅Π³ΠΎ
  3. Π’ ΠΌΠ΅Π½ΡŽΡ‚ΠΎ Π½Π° ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°, ΠΊΠΎΠ΅Ρ‚ΠΎ сС отваря, ΠΈΠ·Π±Π΅Ρ€Π΅Ρ‚Π΅ β€žΠΠ°ΡΡ‚Ρ€ΠΎΠΉΠΊΠΈ Π½Π° ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°β€œ
  4. НамирамС Π½ΠΈΠ·ΠΎΠ²Π΅Ρ‚Π΅ Π½Π° API-ΠΊΠ»ΡŽΡ‡Π° ΠΈ сСкрСтния ΠΊΠ»ΡŽΡ‡, ΠΊΠΎΠΏΠΈΡ€Π°ΠΌΠ΅ ΠΈ Π³ΠΈ Π·Π°ΠΏΠ°Π·Π²Π°ΠΌΠ΅ Π½Π° сигурно място.

Π‘Π΅Π· Π΄Π° ΠΊΠ»ΠΈΠΊΠ²Π°Ρ‚Π΅, ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° слСдватС Π²Ρ€ΡŠΠ·ΠΊΠ°Ρ‚Π°, която Π½Π°ΠΉ-ΠΎΠ±Ρ‰ΠΎ ΠΈΠ·Π³Π»Π΅ΠΆΠ΄Π° Ρ‚Π°ΠΊΠ°:
analytics.amplitude.com/$$$$$$$/manage/project/******/settings,
ΠΊΡŠΠ΄Π΅Ρ‚ΠΎ $$$$$$ Π΅ Π°ΠΌΠΏΠ»ΠΈΡ‚ΡƒΠ΄Π½ΠΎΡ‚ΠΎ Π²Π»ΠΈΠ·Π°Π½Π΅ Π½Π° Π²Π°ΡˆΠ°Ρ‚Π° организация, ****** Π΅ Π½ΠΎΠΌΠ΅Ρ€ΡŠΡ‚ Π½Π° ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°

Π‘Ρ‚ΡŠΠΏΠΊΠ° 2: ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Π½Π° Π½Π°Π»ΠΈΡ‡ΠΈΠ΅Ρ‚ΠΎ Π½Π° Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΈΡ‚Π΅ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ

Π”ΠΎΠ±Ρ€Π°Ρ‚Π° Π½ΠΎΠ²ΠΈΠ½Π° Π΅, Ρ‡Π΅ ΠΏΠΎΡ‡Ρ‚ΠΈ сигурно Π²Π΅Ρ‡Π΅ ΠΈΠΌΠ°Ρ‚Π΅ Ρ‚Π΅Π·ΠΈ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ, инсталирани ΠΏΠΎ ΠΏΠΎΠ΄Ρ€Π°Π·Π±ΠΈΡ€Π°Π½Π΅ ΠΈΠ»ΠΈ ΠΈΠ·Ρ‚Π΅Π³Π»Π΅Π½ΠΈ, Π½ΠΎ трябва Π΄Π° ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚Π΅. ΠŸΡŠΠ»Π½ΠΈΡΡ‚ списък Π½Π° Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈΡ‚Π΅, ΠΊΠΎΠΈΡ‚ΠΎ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ… ΠΏΠΎ Π²Ρ€Π΅ΠΌΠ΅ Π½Π° писанСто (вСрсиитС Π² скоби са посочСни, ΠΊΡŠΠ΄Π΅Ρ‚ΠΎ Π΅ подходящо):

  1. заявки (2.10.0) - ΠΈΠ·ΠΏΡ€Π°Ρ‰Π°Π½Π΅ Π½Π° заявка Ρ‡Ρ€Π΅Π· api Π·Π° ΠΏΠΎΠ»ΡƒΡ‡Π°Π²Π°Π½Π΅ Π½Π° Π΄Π°Π½Π½ΠΈ
  2. pandas (1.0.1) - Ρ‡Π΅Ρ‚Π΅Π½Π΅ Π½Π° json, създаванС Π½Π° Ρ€Π°ΠΌΠΊΠ° с Π΄Π°Π½Π½ΠΈ ΠΈ слСд Ρ‚ΠΎΠ²Π° запис във Ρ„Π°ΠΉΠ»
  3. zipfile - ΠΈΠ·Π²Π»ΠΈΡ‡Π°Π½Π΅ Π½Π° Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅ ΠΎΡ‚ Π°Ρ€Ρ…ΠΈΠ², ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ Ρ‡Ρ€Π΅Π· API
  4. gzip - Ρ€Π°Π·ΠΎΠΏΠ°ΠΊΠΎΠ²Π°Π½Π΅ Π½Π° json Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅ ΠΎΡ‚ .gz
  5. os - ΠΏΠΎΠ»ΡƒΡ‡Π°Π²Π°Π½Π΅ Π½Π° списък с Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅ ΠΎΡ‚ Ρ€Π°Π·ΠΎΠΏΠ°ΠΊΠΎΠ²Π°Π½ Π°Ρ€Ρ…ΠΈΠ²
  6. Π²Ρ€Π΅ΠΌΠ΅ - ΠΏΠΎ ΠΈΠ·Π±ΠΎΡ€, ΠΈΠ·ΠΌΠ΅Ρ€Π²Π°Π½Π΅ Π½Π° Π²Ρ€Π΅ΠΌΠ΅Ρ‚ΠΎ Π·Π° изпълнСниС Π½Π° скрипта
  7. tqdm - ΠΏΠΎ ΠΈΠ·Π±ΠΎΡ€, Π·Π° лСсно наблюдСниС Π½Π° Π½Π°ΠΏΡ€Π΅Π΄ΡŠΠΊΠ° Π½Π° ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ°Ρ‚Π° Π½Π° Ρ„Π°ΠΉΠ»Π°

Π‘Ρ‚ΡŠΠΏΠΊΠ° 3. ПисанС Π½Π° скрипт Π·Π° Π·Π°Ρ€Π΅ΠΆΠ΄Π°Π½Π΅ Π½Π° Π΄Π°Π½Π½ΠΈ

Π‘ΡŠΠ²Π΅Ρ‚: ΠΏΡŠΠ»Π½ΠΈΡΡ‚ скрипт Π·Π° изтСглянС Π΅ Π² края Π½Π° статията; Π°ΠΊΠΎ ΠΆΠ΅Π»Π°Π΅Ρ‚Π΅, ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π²Π΅Π΄Π½Π°Π³Π° Π΄Π° Π³ΠΎ Π²Π·Π΅ΠΌΠ΅Ρ‚Π΅ ΠΈ Π΄Π° сС ΠΎΠ±ΡŠΡ€Π½Π΅Ρ‚Π΅ към обяснСнията ΡΡ‚ΡŠΠΏΠΊΠ° ΠΏΠΎ ΡΡ‚ΡŠΠΏΠΊΠ°, Π°ΠΊΠΎ Π΅ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ.

Π‘Ρ‚ΡŠΠΏΠΊΠ° 3.1. Π˜ΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€Π°Π½Π΅ Π½Π° Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ

НиС ΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€Π°ΠΌΠ΅ всички Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ, ΠΈΠ·Π±Ρ€ΠΎΠ΅Π½ΠΈ във Π²Ρ‚ΠΎΡ€Π°Ρ‚Π° ΡΡ‚ΡŠΠΏΠΊΠ°.

# Π˜ΠΌΠΏΠΎΡ€Ρ‚ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊ
import requests
import pandas as pd
import zipfile
import gzip
import os
import time
import tqdm
from tqdm import tqdm

Π‘Ρ‚ΡŠΠΏΠΊΠ° 3.2. Π˜Π·ΠΏΡ€Π°Ρ‰Π°Π½Π΅ Π½Π° заявка Π΄ΠΎ Амплитуда

НСка ΠΎΡ‚ΠΊΡ€ΠΈΠ΅ΠΌ Π½Π°Ρ‡Π°Π»ΠΎΡ‚ΠΎ Π½Π° ΠΈΠ·ΠΏΡŠΠ»Π½Π΅Π½ΠΈΠ΅Ρ‚ΠΎ Π½Π° скрипта ΠΈ Π³ΠΎ запишСм Π² ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²Π° a.

startdate ΠΈ enddate са ΠΎΡ‚Π³ΠΎΠ²ΠΎΡ€Π½ΠΈ Π·Π° ΠΏΠ΅Ρ€ΠΈΠΎΠ΄Π° Π·Π° изтСглянС Π½Π° Π΄Π°Π½Π½ΠΈ ΠΈ са Π²Π³Ρ€Π°Π΄Π΅Π½ΠΈ Π² тСкста Π½Π° ΠΈΠ·ΠΏΡ€Π°Ρ‚Π΅Π½Π°Ρ‚Π° заявка към ΡΡŠΡ€Π²ΡŠΡ€Π° Π½Π° Amplitude; Π² допълнСниС към Π΄Π°Ρ‚Π°Ρ‚Π° ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° посочитС ΠΈ часа, ΠΊΠ°Ρ‚ΠΎ ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈΡ‚Π΅ стойността слСд 'T' Π² заявката.

api_key ΠΈ secret_key ΡΡŠΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²Π°Ρ‚ Π½Π° стойноститС, ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈ Π² ΠΏΡŠΡ€Π²Π°Ρ‚Π° ΡΡ‚ΡŠΠΏΠΊΠ°; ΠΎΡ‚ ΡΡŠΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΡ Π·Π° сигурност Ρ‚ΡƒΠΊ посочвам ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ»Π½ΠΈ послСдоватСлности вмСсто ΠΌΠΎΠΈΡ‚Π΅ собствСни.

a = time.time()
# ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ Π½Π°Ρ‡Π°Π»ΡŒΠ½ΠΎΠΉ ΠΈ ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎΠΉ Π΄Π°Ρ‚Ρ‹
startdate = '20200627'
enddate = '20200628'

api_key = 'kldfg844203rkwekfjs9234'
secret_key = '094tfjdsfmw93mxwfek'
# ΠžΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ запроса Π² Amplitude
response = requests.get('https://amplitude.com/api/2/export?start='+startdate+'T0&end='+enddate+'T0', auth = (api_key, secret_key))
print('1. Запрос ΠΎΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½')

Π‘Ρ‚ΡŠΠΏΠΊΠ° 3.3. Π˜Π·Ρ‚Π΅Π³Π»ΡΠ½Π΅ Π½Π° Π°Ρ€Ρ…ΠΈΠ² с Π΄Π°Π½Π½ΠΈ

ИзмислямС ΠΈΠΌΠ΅ Π·Π° Π°Ρ€Ρ…ΠΈΠ²Π° ΠΈ Π³ΠΎ записвамС Π² ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²Π°Ρ‚Π° Π·Π° ΠΈΠΌΠ΅ Π½Π° Ρ„Π°ΠΉΠ». Π—Π° ΠΌΠΎΠ΅ удобство посочвам ΠΏΠ΅Ρ€ΠΈΠΎΠ΄Π° + посочвам, Ρ‡Π΅ Ρ‚ΠΎΠ²Π° са Π°ΠΌΠΏΠ»ΠΈΡ‚ΡƒΠ΄Π½ΠΈ Π΄Π°Π½Π½ΠΈ. Π‘Π»Π΅Π΄ Ρ‚ΠΎΠ²Π° записвамС получСния ΠΎΡ‚Π³ΠΎΠ²ΠΎΡ€ ΠΎΡ‚ Amplitude Π² Π°Ρ€Ρ…ΠΈΠ²Π°.

# Π‘ΠΊΠ°Ρ‡ΠΈΠ²Π°Π½ΠΈΠ΅ Π°Ρ€Ρ…ΠΈΠ²Π° с Π΄Π°Π½Π½Ρ‹ΠΌΠΈ
filename = 'period_since'+startdate+'to'+enddate+'_amplitude_data'
with open(filename + '.zip', "wb") as code:
    code.write(response.content)
print('2. Архив с Ρ„Π°ΠΉΠ»Π°ΠΌΠΈ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ скачан')  

Π‘Ρ‚ΡŠΠΏΠΊΠ° 3.4. Π˜Π·Π²Π»ΠΈΡ‡Π°Π½Π΅ Π½Π° Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅ ΠΎΡ‚ ΠΏΠ°ΠΏΠΊΠ° Π½Π° вашия ΠΊΠΎΠΌΠΏΡŽΡ‚ΡŠΡ€

Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ°Ρ‚Π° zipfile Π²Π»ΠΈΠ·Π° Π² дСйствиС, Π·Π° Π΄Π° Π²ΠΈ ΠΏΠΎΠΌΠΎΠ³Π½Π΅ Π΄Π° ΠΈΠ·Π²Π»Π΅Ρ‡Π΅Ρ‚Π΅ Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅. Π’ трСтия Ρ€Π΅Π΄ Π²Π½ΠΈΠΌΠ°Π²Π°ΠΉΡ‚Π΅ ΠΈ Π·Π°ΠΏΠΈΡˆΠ΅Ρ‚Π΅ ΠΏΡŠΡ‚Ρ си ΠΎΡ‚ΠΊΡŠΠ΄Π΅Ρ‚ΠΎ Π²ΠΈ Π΅ ΠΏΠΎ-ΡƒΠ΄ΠΎΠ±Π½ΠΎ Π΄Π° ΠΈΠ·Π²Π»ΠΈΡ‡Π°Ρ‚Π΅.

# Π˜Π·Π²Π»Π΅Ρ‡Π΅Π½ΠΈΠ΅ Ρ„Π°ΠΉΠ»ΠΎΠ² Π² ΠΏΠ°ΠΏΠΊΡƒ Π½Π° ΠΊΠΎΠΌΠΏΡŒΡŽΡ‚Π΅Ρ€Π΅
z = zipfile.ZipFile(filename + '.zip', 'r')
z.extractall(path = 'C:\Users\...\'+filename)
print('3. Архив с Ρ„Π°ΠΉΠ»Π°ΠΌΠΈ ΠΈΠ·Π²Π»Π΅Ρ‡Π΅Π½ ΠΈ записан Π² ΠΏΠ°ΠΏΠΊΡƒ ' + filename)

Π‘Ρ‚ΡŠΠΏΠΊΠ° 3.5. json ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΡƒΠ²Π°Π½Π΅

Π‘Π»Π΅Π΄ ΠΊΠ°Ρ‚ΠΎ ΠΈΠ·Π²Π»Π΅Ρ‡Π΅Ρ‚Π΅ Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅Ρ‚Π΅ ΠΎΡ‚ Π°Ρ€Ρ…ΠΈΠ²Π°, трябва Π΄Π° ΠΊΠΎΠ½Π²Π΅Ρ€Ρ‚ΠΈΡ€Π°Ρ‚Π΅ json Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅ във Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ .gz ΠΈ Π΄Π° Π³ΠΈ Π·Π°ΠΏΠΈΡˆΠ΅Ρ‚Π΅ Π² Ρ€Π°ΠΌΠΊΠ° с Π΄Π°Π½Π½ΠΈ Π·Π° ΠΏΠΎ-Π½Π°Ρ‚Π°Ρ‚ΡŠΡˆΠ½Π° Ρ€Π°Π±ΠΎΡ‚Π°.

Моля, ΠΎΠ±ΡŠΡ€Π½Π΅Ρ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅, Ρ‡Π΅ Ρ‚ΡƒΠΊ трябва ΠΎΡ‚Π½ΠΎΠ²ΠΎ Π΄Π° ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈΡ‚Π΅ ΠΏΡŠΡ‚Ρ Π½Π° вашия собствСн ΠΈ вмСсто 000000 Π΄Π° Π½Π°ΠΏΠΈΡˆΠ΅Ρ‚Π΅ Π½ΠΎΠΌΠ΅Ρ€Π° Π½Π° вашия ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ ΠΎΡ‚ Amplitude (ΠΈΠ»ΠΈ Ρ€ΡŠΡ‡Π½ΠΎ Π΄Π° ΠΎΡ‚Π²ΠΎΡ€ΠΈΡ‚Π΅ ΠΏΡŠΡ‚Ρ, ΠΊΡŠΠ΄Π΅Ρ‚ΠΎ Π΅ ΠΈΠ·Π²Π»Π΅Ρ‡Π΅Π½ Π°Ρ€Ρ…ΠΈΠ²ΡŠΡ‚, ΠΈ Π΄Π° ΠΏΠΎΠ³Π»Π΅Π΄Π½Π΅Ρ‚Π΅ ΠΈΠΌΠ΅Ρ‚ΠΎ Π½Π° ΠΏΠ°ΠΏΠΊΠ°Ρ‚Π° Π²ΡŠΡ‚Ρ€Π΅).

По Ρ€Π΅Π΄:

ЗаписванС Π½Π° дирСктория Π² ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²Π°, ΠΏΠΎΠ»ΡƒΡ‡Π°Π²Π°Π½Π΅ Π½Π° списък с Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅ ΠΎΡ‚ дирСктория, създаванС Π½Π° ΠΏΡ€Π°Π·Π½Π° Ρ€Π°ΠΌΠΊΠ° ΠΎΡ‚ Π΄Π°Π½Π½ΠΈ, time.sleep(1), Π·Π° Π΄Π° Ρ€Π°Π±ΠΎΡ‚ΠΈ ΠΏΡ€Π°Π²ΠΈΠ»Π½ΠΎ tqdm, Π²ΡŠΡ‚Ρ€Π΅ Π² Ρ†ΠΈΠΊΡŠΠ»Π° отварямС .gz Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅ ΠΈ Π²Π΅Π΄Π½Π°Π³Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ pandas Π·Π° Ρ‡Π΅Ρ‚Π΅Π½Π΅ Π½Π° json ΠΈ попълванС Π΄Π°Π΄Π΅Π½Π°Ρ‚Π° Ρ€Π°ΠΌΠΊΠ° ΠΎΡ‚ Π΄Π°Π½Π½ΠΈ.

# ΠŸΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½ΠΈΠ΅ json ΠΊ ΠΎΠ±Ρ‹Ρ‡Π½ΠΎΠΌΡƒ Ρ‚Π°Π±Π»ΠΈΡ‡Π½ΠΎΠΌΡƒ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Ρƒ
directory = 'C:\Users\...\'+filename+'
# ΠŸΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½ΠΈΠ΅ json ΠΊ ΠΎΠ±Ρ‹Ρ‡Π½ΠΎΠΌΡƒ Ρ‚Π°Π±Π»ΠΈΡ‡Π½ΠΎΠΌΡƒ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Ρƒ
directory = 'C:\Users\...\'+filename+'\000000'
files = os.listdir(directory)
amplitude_dataframe = pd.DataFrame()
print('ΠŸΡ€ΠΎΠ³Ρ€Π΅ΡΡ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ Ρ„Π°ΠΉΠ»ΠΎΠ²:')
time.sleep(1)
for i in tqdm(files):
with gzip.open(directory + '\' + i) as f:
add = pd.read_json(f, lines = 'True')
amplitude_dataframe = pd.concat([amplitude_dataframe, add])
time.sleep(1)    
print('4. JSON Ρ„Π°ΠΉΠ»Ρ‹ ΠΈΠ· Π°Ρ€Ρ…ΠΈΠ²Π° ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½Ρ‹ ΠΈ записаны Π² dataframe')
0000' files = os.listdir(directory) amplitude_dataframe = pd.DataFrame() print('ΠŸΡ€ΠΎΠ³Ρ€Π΅ΡΡ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ Ρ„Π°ΠΉΠ»ΠΎΠ²:') time.sleep(1) for i in tqdm(files): with gzip.open(directory + '\' + i) as f: add = pd.read_json(f, lines = 'True') amplitude_dataframe = pd.concat([amplitude_dataframe, add]) time.sleep(1) print('4. JSON Ρ„Π°ΠΉΠ»Ρ‹ ΠΈΠ· Π°Ρ€Ρ…ΠΈΠ²Π° ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½Ρ‹ ΠΈ записаны Π² dataframe')

Π‘Ρ‚ΡŠΠΏΠΊΠ° 3.6. ПисанС Π½Π° Ρ€Π°ΠΌΠΊΠ° с Π΄Π°Π½Π½ΠΈ Π² excel

ΠšΠ°Ρ‡Π²Π°Π½Π΅Ρ‚ΠΎ Π² excel Π΅ само ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Ρ‚ΡƒΠΊ. Π’ ΠΌΠ½ΠΎΠ³ΠΎ случаи Π΅ ΠΏΠΎ-ΡƒΠ΄ΠΎΠ±Π½ΠΎ Π΄Π° Ρ€Π°Π±ΠΎΡ‚ΠΈΡ‚Π΅ с рСзултантния ΠΊΠ°Π΄ΡŠΡ€ с Π΄Π°Π½Π½ΠΈ Π² Python ΠΈΠ»ΠΈ Π΄Π° поставитС Π΄Π°Π½Π½ΠΈΡ‚Π΅ Π² Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π΅.

Π‘ΡŠΡ‰ΠΎ Ρ‚Π°ΠΊΠ° Ρ‰Π΅ трябва Π΄Π° Π·Π°ΠΌΠ΅Π½ΠΈΡ‚Π΅ ΠΏΡŠΡ‚Ρ Π·Π° ΠΊΠ°Ρ‡Π²Π°Π½Π΅ Π½Π° Π΄Π°Π½Π½ΠΈ Ρ‚ΡƒΠΊ със свой собствСн.

# Π—Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½ΠΎΠΉ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ Π² Excel-Ρ„Π°ΠΉΠ»
amplitude_dataframe.to_excel('C:\Users\...\'+filename+'.xlsx',index=False)
print('5. Dataframe ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ записан Π² Ρ„Π°ΠΉΠ» ' + filename)

Π‘Ρ‚ΡŠΠΏΠΊΠ° 3.7. ΠžΡ‚Ρ‡ΠΈΡ‚Π°ΠΌΠ΅ Π²Ρ€Π΅ΠΌΠ΅Ρ‚ΠΎ Π½Π° изпълнСниС Π½Π° скрипта

ЗаписванС Π½Π° Ρ‚Π΅ΠΊΡƒΡ‰ΠΎΡ‚ΠΎ Π²Ρ€Π΅ΠΌΠ΅ Π² ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²Π°Ρ‚Π° b, изчисляванС Π½Π° Ρ€Π°Π·Π»ΠΈΠΊΠ°Ρ‚Π° ΠΈ броя Π½Π° ΠΌΠΈΠ½ΡƒΡ‚ΠΈΡ‚Π΅, ΠΏΠΎΠΊΠ°Π·Π²Π°Π½Π΅ Π½Π° ΠΎΠ±Ρ‰ΠΈΡ‚Π΅ ΠΌΠΈΠ½ΡƒΡ‚ΠΈ. Π’ΠΎΠ²Π° Π΅ послСдната ΡΡ‚ΡŠΠΏΠΊΠ°.

b = time.time()
diff = b-a
minutes = diff//60
print('Π’Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ ΠΊΠΎΠ΄Π° заняло: {:.0f} ΠΌΠΈΠ½ΡƒΡ‚(Ρ‹)'.format( minutes))

Π—Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅

ΠœΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° ΠΈΠ·Π²ΠΈΠΊΠ°Ρ‚Π΅ Ρ‚Π°Π±Π»ΠΈΡ†Π°Ρ‚Π° ΠΈ Π΄Π° Π·Π°ΠΏΠΎΡ‡Π½Π΅Ρ‚Π΅ Π΄Π° Ρ€Π°Π±ΠΎΡ‚ΠΈΡ‚Π΅ с нСя, ΠΊΠ°Ρ‚ΠΎ ΠΈΠ·Π²ΠΈΠΊΠ°Ρ‚Π΅ ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²Π°Ρ‚Π° amplitude_dataframe, Π² която са записани Π΄Π°Π½Π½ΠΈΡ‚Π΅. Π©Π΅ ΠΈΠΌΠ° ΠΎΠΊΠΎΠ»ΠΎ 50 ΠΊΠΎΠ»ΠΎΠ½ΠΈ, ΠΎΡ‚ ΠΊΠΎΠΈΡ‚ΠΎ Π² 80% ΠΎΡ‚ случаитС Ρ‰Π΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ‚Π΅: event_type - ΠΈΠΌΠ΅ Π½Π° ΡΡŠΠ±ΠΈΡ‚ΠΈΠ΅Ρ‚ΠΎ, event_properties - ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΈ Π½Π° ΡΡŠΠ±ΠΈΡ‚ΠΈΠ΅Ρ‚ΠΎ, event_time - Π²Ρ€Π΅ΠΌΠ΅ Π½Π° ΡΡŠΠ±ΠΈΡ‚ΠΈΠ΅Ρ‚ΠΎ, uuid - ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ Π½Π° ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π°, user_properties - ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΈ Π½Π° ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π°, ΠΏΡŠΡ€Π²ΠΎ трябва Π΄Π° Π·Π°ΠΏΠΎΡ‡Π½Π΅Ρ‚Π΅ Π΄Π° Ρ€Π°Π±ΠΎΡ‚ΠΈΡ‚Π΅ с тях . И ΠΊΠΎΠ³Π°Ρ‚ΠΎ сравняватС Ρ†ΠΈΡ„Ρ€ΠΈ ΠΎΡ‚ Π²Π°ΡˆΠΈΡ‚Π΅ собствСни изчислСния с ΠΈΠ½Π΄ΠΈΠΊΠ°Ρ‚ΠΎΡ€ΠΈ ΠΎΡ‚ Ρ‚Π°Π±Π»Π°Ρ‚Π° Π·Π° ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Π½Π° Amplitude, Π½Π΅ трябва Π΄Π° забравятС, Ρ‡Π΅ систСмата ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π° собствСна мСтодология Π·Π° изчисляванС Π½Π° ΡƒΠ½ΠΈΠΊΠ°Π»Π½ΠΈ ΠΊΠ»ΠΈΠ΅Π½Ρ‚ΠΈ/Ρ„ΡƒΠ½ΠΈΠΈ ΠΈ Ρ‚.Π½., ΠΈ ΠΏΡ€Π΅Π΄ΠΈ Π΄Π° Π½Π°ΠΏΡ€Π°Π²ΠΈΡ‚Π΅ Ρ‚ΠΎΠ²Π°, ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΎ трябва Π΄Π° ΠΏΡ€ΠΎΡ‡Π΅Ρ‚Π΅Ρ‚Π΅ докумСнтацията Π½Π° Amplitude.

Благодаря Π·Π° Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅Ρ‚ΠΎ! Π‘Π΅Π³Π° ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° ΠΊΠ°Ρ‡Π²Π°Ρ‚Π΅ Π½Π΅ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π΅Π½ΠΈ Π΄Π°Π½Π½ΠΈ Π·Π° ΡΡŠΠ±ΠΈΡ‚ΠΈΡ Π² Amplitude ΠΈ Π΄Π° Π³ΠΈ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ‚Π΅ напълно Π² Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚Π° си.

ЦСлият скрипт:

# Π˜ΠΌΠΏΠΎΡ€Ρ‚ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊ
import requests
import pandas as pd
import zipfile
import gzip
import os
import time
import tqdm
from tqdm import tqdm
a = time.time()
# ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ Π½Π°Ρ‡Π°Π»ΡŒΠ½ΠΎΠΉ ΠΈ ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎΠΉ Π΄Π°Ρ‚Ρ‹
startdate = '20200627'
enddate = '20200628'

api_key = 'd988fddd7cfc0a8a'
secret_key = 'da05cf1aeb3a361a61'
# ΠžΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ запроса Π² Amplitude
response = requests.get('https://amplitude.com/api/2/export?start='+startdate+'T0&end='+enddate+'T0', auth = (api_key, secret_key))
print('1. Запрос ΠΎΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½')

# Π‘ΠΊΠ°Ρ‡ΠΈΠ²Π°Π½ΠΈΠ΅ Π°Ρ€Ρ…ΠΈΠ²Π° с Π΄Π°Π½Π½Ρ‹ΠΌΠΈ
filename = 'period_since'+startdate+'to'+enddate+'_amplitude_data'
with open(filename + '.zip', "wb") as code:
    code.write(response.content)
print('2. Архив с Ρ„Π°ΠΉΠ»Π°ΠΌΠΈ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ скачан')  

# Π˜Π·Π²Π»Π΅Ρ‡Π΅Π½ΠΈΠ΅ Ρ„Π°ΠΉΠ»ΠΎΠ² Π² ΠΏΠ°ΠΏΠΊΡƒ Π½Π° ΠΊΠΎΠΌΠΏΡŒΡŽΡ‚Π΅Ρ€Π΅
z = zipfile.ZipFile(filename + '.zip', 'r')
z.extractall(path = 'C:\Users\...\'+filename)
print('3. Архив с Ρ„Π°ΠΉΠ»Π°ΠΌΠΈ ΠΈΠ·Π²Π»Π΅Ρ‡Π΅Π½ ΠΈ записан Π² ΠΏΠ°ΠΏΠΊΡƒ ' + filename)

# ΠŸΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½ΠΈΠ΅ json ΠΊ ΠΎΠ±Ρ‹Ρ‡Π½ΠΎΠΌΡƒ Ρ‚Π°Π±Π»ΠΈΡ‡Π½ΠΎΠΌΡƒ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Ρƒ
directory = 'C:\Users\...\'+filename+'
# Π˜ΠΌΠΏΠΎΡ€Ρ‚ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊ
import requests
import pandas as pd
import zipfile
import gzip
import os
import time
import tqdm
from tqdm import tqdm
a = time.time()
# ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ Π½Π°Ρ‡Π°Π»ΡŒΠ½ΠΎΠΉ ΠΈ ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎΠΉ Π΄Π°Ρ‚Ρ‹
startdate = '20200627'
enddate = '20200628'
api_key = 'd988fddd7cfc0a8a'
secret_key = 'da05cf1aeb3a361a61'
# ΠžΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ запроса Π² Amplitude
response = requests.get('https://amplitude.com/api/2/export?start='+startdate+'T0&end='+enddate+'T0', auth = (api_key, secret_key))
print('1. Запрос ΠΎΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½')
# Π‘ΠΊΠ°Ρ‡ΠΈΠ²Π°Π½ΠΈΠ΅ Π°Ρ€Ρ…ΠΈΠ²Π° с Π΄Π°Π½Π½Ρ‹ΠΌΠΈ
filename = 'period_since'+startdate+'to'+enddate+'_amplitude_data'
with open(filename + '.zip', "wb") as code:
code.write(response.content)
print('2. Архив с Ρ„Π°ΠΉΠ»Π°ΠΌΠΈ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ скачан')  
# Π˜Π·Π²Π»Π΅Ρ‡Π΅Π½ΠΈΠ΅ Ρ„Π°ΠΉΠ»ΠΎΠ² Π² ΠΏΠ°ΠΏΠΊΡƒ Π½Π° ΠΊΠΎΠΌΠΏΡŒΡŽΡ‚Π΅Ρ€Π΅
z = zipfile.ZipFile(filename + '.zip', 'r')
z.extractall(path = 'C:\Users\...\'+filename)
print('3. Архив с Ρ„Π°ΠΉΠ»Π°ΠΌΠΈ ΠΈΠ·Π²Π»Π΅Ρ‡Π΅Π½ ΠΈ записан Π² ΠΏΠ°ΠΏΠΊΡƒ ' + filename)
# ΠŸΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½ΠΈΠ΅ json ΠΊ ΠΎΠ±Ρ‹Ρ‡Π½ΠΎΠΌΡƒ Ρ‚Π°Π±Π»ΠΈΡ‡Π½ΠΎΠΌΡƒ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Ρƒ
directory = 'C:\Users\...\'+filename+'\000000'
files = os.listdir(directory)
amplitude_dataframe = pd.DataFrame()
print('ΠŸΡ€ΠΎΠ³Ρ€Π΅ΡΡ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ Ρ„Π°ΠΉΠ»ΠΎΠ²:')
time.sleep(1)
for i in tqdm(files):
with gzip.open(directory + '\' + i) as f:
add = pd.read_json(f, lines = 'True')
amplitude_dataframe = pd.concat([amplitude_dataframe, add])
time.sleep(1)    
print('4. JSON Ρ„Π°ΠΉΠ»Ρ‹ ΠΈΠ· Π°Ρ€Ρ…ΠΈΠ²Π° ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½Ρ‹ ΠΈ записаны Π² dataframe')
# Π—Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½ΠΎΠΉ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ Π² Excel-Ρ„Π°ΠΉΠ»
amplitude_dataframe.to_excel('C:\Users\...\'+filename+'.xlsx',index=False)
print('5. Dataframe ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ записан Π² Ρ„Π°ΠΉΠ» ' + filename)
b = time.time()
diff = b-a
minutes = diff//60
print('Π’Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ ΠΊΠΎΠ΄Π° заняло: {:.0f} ΠΌΠΈΠ½ΡƒΡ‚(Ρ‹)'.format( minutes))
0000' files = os.listdir(directory) amplitude_dataframe = pd.DataFrame() print('ΠŸΡ€ΠΎΠ³Ρ€Π΅ΡΡ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ Ρ„Π°ΠΉΠ»ΠΎΠ²:') time.sleep(1) for i in tqdm(files): with gzip.open(directory + '\' + i) as f: add = pd.read_json(f, lines = 'True') amplitude_dataframe = pd.concat([amplitude_dataframe, add]) time.sleep(1) print('4. JSON Ρ„Π°ΠΉΠ»Ρ‹ ΠΈΠ· Π°Ρ€Ρ…ΠΈΠ²Π° ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½Ρ‹ ΠΈ записаны Π² dataframe') # Π—Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½ΠΎΠΉ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ Π² Excel-Ρ„Π°ΠΉΠ» amplitude_dataframe.to_excel('C:\Users\...\'+filename+'.xlsx',index=False) print('5. Dataframe ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ записан Π² Ρ„Π°ΠΉΠ» ' + filename) b = time.time() diff = b-a minutes = diff//60 print('Π’Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ ΠΊΠΎΠ΄Π° заняло: {:.0f} ΠΌΠΈΠ½ΡƒΡ‚(Ρ‹)'.format( minutes))

Π˜Π·Ρ‚ΠΎΡ‡Π½ΠΈΠΊ: www.habr.com

ДобавянС Π½Π° Π½ΠΎΠ² ΠΊΠΎΠΌΠ΅Π½Ρ‚Π°Ρ€