Skip to content

Latest commit

 

History

History
128 lines (114 loc) · 11.4 KB

python102.md

File metadata and controls

128 lines (114 loc) · 11.4 KB

recap: Целта на втората сбирка беше да свикнем с "разходките" в речници и как да ги изследваме.
Common denominator a.k.a. най-малко общо кратно между всички присъстващи беше играта Apex Legends, следователно реших че е добро упражнение да си видим статистиките с малко код вместо браузър. Набързо се регистрирах там и изтествах API-то им което дори работеше.
Съвсем простичко REST-like с допълнителен HTTP header за автентикация. Повечето онлайн игри вече имат статистика за всеки играч.
Статистиките на Apex далеч не са блестящи на пръв поглед, освен това не можах да намеря официален тракер.
Оказва се че не са блестящи съвсем целенасочено - да си харчиш вътрешната валута по-честичко та да си купиш "тракерите"(баджовете за отделните статистики). Ограничението на APIто е в статистиките които се показват в последната игра. Най-близкият до такъв беше tracker.gg който има почти безкраен капацитет преди rate-limiting за разлика от всички останали и на всичко отгоре вероятно препродават тяхната услуга.
Всеки от нас се регистрира там и си получи API key.
pip install requests
Готови сме да разцъкаме

dict

  • Създаваме речник чрез къдравите скоби { }
  • Създаваме речник чрез извикване на dict() с параметър изброим обект с четен брой елементи
  • .keys() ни вади списък с всички ключове в речника по които можем да достъпваме стойностите
  • .values() е "обратното" на .keys() - вади списък с всички стойности
  • .items() ни връща list[с tuples(ключ, стойност)]
  • ключовете още познати като хешове (hashes) се използват най-често заради константното време за търсене и намиране на елемент
  • в личният речник с термини записваме hashmap, hashtable и dictionary на същият ред като синоними.
    разлика между тях може да има на имплементационно или контекстуално ниво(например друг език), но на практика означават едно и също нещо.
  • можем да проверим дали даден ключ съществува в речник чрез ключовата дума in

Взимаме следните речници за пример:

>>> names = {'Dani': 63461912, 'Niki': 881961, 'Boyan': 971934}
>>> combatstats = {'damage': 63461912, 'headshots': 1471, 'knockdowns': 5683, 'kills': 1964}
>>> 'Dani' in names
True

можем да достъпим стойността зад 'Dani' чрез ключа в квадратни скоби [ ] :

>>> names['Dani']
63461912
>>> combatstats['headshots']
1471

Можем да имаме вложени(nested) изброими структури от данни.

>>> combatstatsdani = {'damage': 63461912, 'headshots': 1471, 'knockdowns': 5683, 'kills': 1964}
>>> combatstatsniki = {'damage': 923566, 'headshots': 366, 'knockdowns': 582, 'kills': 105}
>>> combatstatsboyan = {'damage': 2361634, 'headshots': 682, 'knockdowns': 968, 'kills': 371}
>>> names = {'Dani': combatstatsdani, 'Niki': combatstatsniki, 'Boyan': combatstatsboyan}

функцията len() ни връща колко елемента има в изброимото зададено като параметър

>>> len(names)
3
>>> len(names['Dani'])
4
>>> names['Dani']
{'damage': 63461912, 'headshots': 1471, 'knockdowns': 5683, 'kills': 1964}
>>> names['Dani']['knockdowns']
5683

requests библиотеката служи за работа с HTTP услуги и с нейна помощ ще изтеглим статистиките от tracker.gg
За да се възползваме от билбиотека трябва да използваме ключовата дума import

import requests

в нея се намира метода get() който прави HTTP GET заявка към web servera който обслужва статистиките

r = requests.get("https://public-api.tracker.gg/v2/apex/standard/profile/5/an10n",
             headers={"TRN-Api-Key": '7b38625d-addf-4a4d-baa2-c4b163640730'}
             # use your own API key! you sloth

Аргумента headers очаква dict() който съдържа допълнителни хедъри които да бъдат изпратени към заявката до сървъра.
Тези хедъри често са извън HTTP стандарта и създателите на уеб приложенията са си написали допълнителен код който да ги обработва -(Да се чете като) тези допълнителни хедъри често са специфични само за само и точно определен сайт и/или ресурс към него (в случая - "TRN-Api-Key").

След като вече сме направили заявката към tracker.gg очакваме резултат от тази заявка която се съхранява в променливата r.
Можем да проверим състоянието от изпълнението на заявката чрез r.status_code.
Стойността която се съхранява в r.status_code е код-число което описва резултата при изпълнението на заява.
https://httpstatuses.com/ съдържа прекрасно описание кой код какво означава
Очакваме код 200 който означава Oll Korect, сиреч заявката е обработена успешно

>>> r.status_code
200
>>> r.reason
'OK'

В example_datasets има json файл с отговора на една такава заявка за справка.

Чрез r.content можем да достъпим "суровото" съдържание от отговора на заявката което връща тип bytes(споменаваме го за първи път) - този тип уместно е да го използваме когато имаме данни различни от текст и нямат точна репрезентация.
Например ако имаме аудио, видео, компресирани или криптирани данни - те никога няма да са под формата на текст освен ако не са трансформирани през някакъв енкодер специално за тази цел(виж base64).
Използваме r.text - ако сме сигурни че данните с които работим са текстови,
или използваме r.json() ако знаем че отговора на заявката може да бъде JSON форматиран.
3те начина за достъпване на информацията в отговора на заявката са от най-бърз към най-бавен; какво означава това?

  • r.content връща съдържанието на отговора без никаква обработка
>>> len(r.content)
8996
  • r.text прави опит за трансформация през стандартен utf-8 encoder
  • r.json прави json.loads(r.text) - съответно прави опит да: 1. parse-ва текста, 2. проверява за грешки, 3. създава нов dict() обект, 4. попълва съответните ключове и стойности.

Защо ни интересува това? Ето храна за размисъл...
Давам примери под формата на крайна цел - хипотетично искаме да направим HTTP Proxy - посредник с който да правим заявки:

  • ако искаме да водим записки до кои сайтове се отправят заявки ни трябва само r.url()
  • ако искаме да водим пълни записки и дори с данните (вероятно четем 'подслушваме') - няма нужда да извикваме r.json(), за да записваме данни ни трябват суровите такива който r.content връща
  • ако искаме в реално време да изписваме данните които получаваме - да речем за debug - това доста вероятно би причинило безумно голямо количество спам - тогава вече можем да използваме r.text[:50] за да изпишем само първите 50 символа от отговора вместо всичките 8996
  • ако искаме точно определено поле чак тогава вече има смисъл да викаме r.json()
  • ако искаме да изведем големината на отговора ще използваме len(r.content) вместо len(r.text).
    Защо? при трансофмрацията с .text от различни енкодинги може да има разминаване и да се губят или добавят байтове*

Неупотребените резултати от излишна обработка водят до глобално затопляне!
(четем - "Не купуваме храна която ще изхвърлим" - логично нали?!;
"Освен това по-бързо и лесно намираме храната която търсим в хладилника, той самият мирише по-малко и създаваме по-малко боклук който изхвърляме"
-guilt tripping 101, the old low-level testament)

В ролите: Еди, Боян, Дани, Ники
Сценарист: Еди

Продукция:

Текста четоха:
Боян, вероятно Боян, Ники, Дани, Андрей, вероятно Иван