├── .gitignore ├── Homeworks ├── AdditionalHW.md ├── Final_project.md ├── HW1.md ├── HW2.md ├── HW5.md ├── HW6.md ├── HW7.md ├── PapersHW.md ├── Project.ipynb └── QuestionnaireHW.md ├── LICENSE ├── Lessons ├── Flask │ ├── 10. Flask (2) .ipynb │ ├── 9. Flask (1).ipynb │ ├── flask_example │ │ ├── my_app.py │ │ └── templates │ │ │ ├── answer.html │ │ │ ├── books.html │ │ │ ├── index.html │ │ │ ├── question.html │ │ │ └── thanks.html │ └── langcodes.csv ├── Heroku и командная строка │ ├── 13a. Heroku.md │ ├── 13b. Командная строка UNIX, логин на сервере.md │ └── cmd cheatsheet.md ├── JSON │ ├── 3. JSON.ipynb │ └── data.json ├── Markdown и git │ ├── 1. Intro.ipynb │ ├── DS_Store-gitignore.md │ ├── Markdown.md │ ├── cmd cheatsheet.md │ └── deadline.jpg ├── Matplotlib │ ├── 11. Matplotlib.ipynb │ └── nanai-vowels.csv ├── Telegram-боты │ ├── TelegramBot1.ipynb │ ├── TelegramBot2.ipynb │ ├── TelegramBot3.ipynb │ ├── bot_example │ │ ├── bot.py │ │ ├── results.csv │ │ └── reviews.csv │ ├── dal_proverbs.csv │ └── reviews.csv ├── Twitter API │ └── Tweepy.ipynb ├── VK API │ ├── 14. VK API (1).ipynb │ ├── 15. VK API (2).ipynb │ ├── comment.jpg │ └── post_cloud.png ├── Word2vec │ ├── liza_lem.txt │ ├── ru_analogy_tagged.txt │ └── word2vec.ipynb ├── Базы данных │ └── 12. Базы данных.ipynb ├── Веб-запросы и формы │ └── 8. Запросы и формы.ipynb ├── Графы │ └── Графы, networkx.ipynb ├── Интерактивные визуализации │ └── Интерактивные графики и карты в вебе.md ├── Краулеры и парсинг веб-документов │ ├── 4a. Urllib.ipynb │ ├── 4b. Краулеры.ipynb │ └── lxml_bs4.ipynb ├── Морфологический анализ │ ├── 6. Mystem.md │ ├── 7. pymorphy2, pymystem3.ipynb │ └── rus_stopwords.txt └── Структуры данных │ ├── 2. Структуры данных.ipynb │ ├── KILI_seminar2_datatypes.pdf │ └── kilipractice.py └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | 106 | conf.py -------------------------------------------------------------------------------- /Homeworks/AdditionalHW.md: -------------------------------------------------------------------------------- 1 | # pymystem3 & pymorphy2 2 | ## Необязательное задание 3 | 4 | *Задание дает возможность поднять накопленную оценку. У тех, кто его сделает, накопленная за д/з будет разделена на 8, а у тех, кто не сделает, — на 7 (по количеству выполненных работ).* 5 | 6 | Написать flask-приложение, с которым можно разговаривать: пользователь пишет ему реплику, а оно отвечает предложением, в котором все слова заменены на какие-то случайные другие слова той же части речи и с теми же грамматическими характеристиками. Предложение-ответ должно быть согласованным. Ответ должен появляться на той же странице, где пользователь вводит фразу. 7 | 8 | Например, на фразу "Мама мыла раму" программа может ответить "Девочка пела песню". 9 | 10 | Для такой программы вам понадобится большой список русских слов: 11 | 12 | * можно взять список словоформ с сайта НКРЯ - http://ruscorpora.ru/corpora-freq.html 13 | * можно взять просто любой большой текст, вытащить из него слова и использовать их 14 | 15 | Из этого списка вам нужен только список разных лемм разных частей речи, и затем нужно будет использовать функции `parse` и `inflect` из `pymorphy2`. 16 | 17 | **NB! Задание выполняется в виде обычного .py скрипта (или нескольких скриптов).** 18 | 19 | ## Критерии оценки 20 | 21 | |Балл|Критерий| 22 | |----|--------| 23 | |1|Программа запускается и оформлена по PEP8. Соответствие PEP8 можно проверить с помощью команды `pycodestyle my_script_name.py` в командной строке.| 24 | |1|Список слов взят с сайта НКРЯ или сопоставим по объему (т.е. список из 100-200 слов не подойдет).| 25 | |2|Программа генерирует ответ. Ответ выводится на той же странице, что и форма ввода, форма ввода никуда не исчезает. | 26 | |2|Все слова в ответе заменены на слова с такими же грамматическими характеристиками. Слова выбираются случайным образом. Слова, введенные пользователем, не используются в ответе.| 27 | |2|Ответ программы (будь то предложение или просто словосочетание) грамматически согласован.| 28 | |2|Сайт оформлен с помощью `bootstrap`| 29 | 30 | ## Дедлайн 31 | 32 | |Группа|Дедлайн| 33 | |----|--------| 34 | |1|15 мая, 10.00| 35 | |2|13 мая, 10.00| 36 | |3|15 мая, 10.00| 37 | |4|24 мая, 10.00| 38 | -------------------------------------------------------------------------------- /Homeworks/Final_project.md: -------------------------------------------------------------------------------- 1 | 2 | ## Заготовки тем для финальных проектов 3 | 4 | **Свою тему нужно будет вписать [вот в эту табличку](https://docs.google.com/spreadsheets/d/18KH0d2gKIFB5Ddl3YYPbkYpyj0Ob_qSYpINiE77VHyg/edit?usp=sharing).** 5 | 6 | Код проекта должен быть выложен в репозиторий в папку `FinalProject`, а также на `heroku`. Т.е. веб-сервис или телеграм-бот должен работать вне зависимости от того, запущен ли код на вашем/чьем-то другом компьютере. Ссылка на ваше herokuapp должна быть в `README` в папке с проектом. 7 | 8 | 9 | №|Шаблон|Описание|Что выбрать самостоятельно 10 | -|------|--------------------------|---- 11 | 1.|«Гарри Поттер и...»|Веб-сервис/телеграм-бот, который присылает пользователю фразы, сгенерированные с помощью марковской цепи.|Данные, на которых будет обучаться марковская цепь, сходные по объему со [всеми книгами о Гарри Поттере](https://www.dropbox.com/s/gg62ggme0hi7zqk/%D0%94%D0%B6%D0%BE%D0%B0%D0%BD%20%D0%A0%D0%BE%D1%83%D0%BB%D0%B8%D0%BD%D0%B3.%20%D0%93%D0%B0%D1%80%D1%80%D0%B8%20%D0%9F%D0%BE%D1%82%D1%82%D0%B5%D1%80%20%282018%29.fb2?dl=0) 12 | 2.|Анекдоты|Веб-сервис/телеграм-бот, который по заданному персонажу находит в корпусе анекдоты о нем|Это тема для одного человека 13 | 3.|Толстой или компьютер?|Веб-сервис/телеграм-бот, который играет с пользователем в игру: предлагает угадать, оригинальное ли перед ним предложение какого-либо автора или сгенерированное компьютером с помощью word2vec. В конце показывает результат пользователя и статистику правильных ответов.|Автора, в произведениях которого будут заменяться слова. 14 | 4.|Пушкин каждый день|Веб-сервис/телеграм-бот, который в ответ на реплику пользователя отвечает строчкой из какого-либо русского поэта в рифму|Можно сделать либо веб-сервис, либо телеграм-бота; можно взять как стихи какого-нибудь одного поэта, так и нескольких (лучше всего использовать поэтический корпус НКРЯ 15 | 5.|Бот-рифмоплет|Веб-сервис/телеграм-бот, который генерирует стихотворение со словом, которые ввел пользователь|Можно сделать либо веб-сервис, либо телеграм-бота; можно выбрать формат стихов: пирожки, порошки, рифмованные двустишия, хайку... 16 | 6.|Новостные тренды|Веб-сервис, которое периодически скачивает новости с любого сайта, где они есть (от "Известий" до главной страницы Школы лингвистики) и строит график совместной встречаемости полнозначных слов в окне 3.| Новостной сайт 17 | 7.|Все, что вы хотели знать о...|Веб-сервис, которое по id пользователя/сообщества Вконтакте выводит график самых частотных полнозначных слов на заданнный период времени, а также статистику по комментаторам: город, пол, возраст|Это тема для одного человека 18 | 8.|«...» Вконтакте|Веб-сервис, который обращается к заданному набору сообществ Вконтакте на определенную тему, скачивает последние 300 записей и строит графики частотности ключевых слов по этой тематике (их набор, 10-20 штук, вы определяете самостоятельно). Для каждого сообщества должен быть отдельный график, + график-сравнение по всем сообществам|Тематику, набор сообществ вк по этой тематике и ключевые слова 19 | 9.|The PenPal|Веб-сервис, где пользователь вводит текст, а программа автоматически ему отвечает. Необходимо обеспечить определённую степень связности между тем, что пишет пользователь, и тем, что отвечает программа. Ожидается, что будут комментарии или отдельный текстовый файл, объясняющий, как обеспечивается связность. Для этого нужно использовать пройденные темы (в любых комбинациях): регулярные выражения, морфологический анализ, word2vec, VK API и т.д. |Выбрать "персону" программы: она может сочувствовать, ругать, давать советы и т.п. 20 | 10.|Fieldwork Crowdsourcing|Веб-сервис, который позволяет носителям (малых) языков и лингвистам, занимающимся этими языками, добавлять тексты и другие материалы (можно выбрать жестовый язык, тогда добавляться будут фото и видео). Программа создаёт базу данных, в которой хранятся тексты (видео, фото), социолингвистическая информация о добавивших тексты (видео, фото). Есть страница поиска (по словам, по социолингвистическим параметрам); есть страница, отражающая статистику по социолингвистическим параметрам.| Выбрать язык (стартовые материалы по языку можно выкачать из интернета), выбрать конкретные параметры, которые веб-сервис будет позволять добавлять.| 21 | 11.|Своя тема|Необходимо использовать как минимум 3 пройденных за год темы (в любых комбинациях): например, VK API, matplotlib, морфологический анализ; flask, word2vec, графы и т.д.| 22 | 23 | -------------------------------------------------------------------------------- /Homeworks/HW1.md: -------------------------------------------------------------------------------- 1 | ## Домашнее задание №1 2 | ### Игра "Виселица" 3 | 4 | - Придумайте любые 3 темы (например, "лингвистические термины", "фамилии актеров", "блюда грузинской кухни") и составьте по каждой из них список из 10-15 слов, лучше длинных. Списки слов по разным темам должны быть сохранены в отдельных txt-файлах. 5 | 6 | - При запуске программа должна предлагать пользователю выбрать одну из трех тем и загружать список слов, соответствующий выбору. Далее она должна случайным образом выбирать из списка и говорить пользователю что-то на подобии "У вас есть N попыток, чтобы угадать слово из X букв" и выводить строчку из _ по количеству букв в слове, разделенных пробелами. Количество попыток нужно выбрать самостоятельно, оно должно всегда быть одинаковым. 7 | 8 | - Если пользователь угадал букву, то программа должна заменять _ в соответствующем месте на угаданную букву 9 | 10 | - Программа должна выдавать разные сообщения в зависимости от того, угадал пользователь букву или нет, а также если он уже вводил эту букву или если введенный символ — не буква. Чувствительность к регистру не нужна! 11 | 12 | - Если названной буквы нет в слове, то программа должна рисовать деталь человечка. Обратите внимание, что количество деталей должно быть равно количеству попыток! Как будет выглядеть картинка, выбирайте сами 13 | 14 | - Код должен быть оформлен в виде функций с соблюдением правил PEP8. Не забывайте писать комментарии к функциям! 15 | 16 | **Примечание №1**: Код должен быть оформлен в ipython notebook! 17 | 18 | **Примечание №2**: Для ввода обязательно используйте функцию `input()`, что позволит получить строку ввода. 19 | 20 | **Примечание №3**: Отдельным одним баллом будет оценено умение программы согласовывать числительные с существительными, то есть выводить сообщения не "Осталось попыток: 5", а "Осталось 5 попыток, осталась 1 попытка" и т.п. 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
БаллКритерий
1Созданы текстовые файлы со словами
1Программа запускается и оформлена по PEP8
1Программа разделена на функции
2Программа загадывает случайное слово из выбранной категории и правильно указывает, есть ли в нем буква, введенная пользователем
2Программа умеет выводит нижние подчеркивания вместо неотгаданных букв
2Программа корректно обрабытвает ошибочный ввод пользователя (как неправильно угаданная буква, так и некорректный символ), выводит число попыток и предлагает начать игру заново
1Программа рисует детали человечка
1Бонусный балл. Программа умеет склонять слово "попытка"
34 | -------------------------------------------------------------------------------- /Homeworks/HW2.md: -------------------------------------------------------------------------------- 1 | ## Домашнее задание №2 2 | 3 | Написать программу, которая получает на вход список пользователей гитхаба и умеет делать следующее: 4 | 5 | 1. Выбрать какого-то одного пользователя из полученного списка и распечатать список его репозиториев (name) и их описания (description). Выбор пользователя должен осуществляться с помощью ввода с клавиатуры (функция `input()`). 6 | 2. Распечатать список языков (language) выбранного пользователя и количество репозиториев, в котором они используются. 7 | 3. Узнать, у кого из пользователей в списке больше всего репозиториев. 8 | 4. Узнать, какой язык самый популярный среди пользователей списка. 9 | 5. Узнать, у кого из пользователей списка больше всего фолловеров? (фолловеров можно достать по ссылке `https://api.github.com/users/username/followers`, где вместо username -- имя пользователя) 10 | 11 | **Подсказка №1**. Для каждой из перечисленных операций нужно написать свою функцию. Каждая из них потом должна быть вызвана в функции `main()`, которой и передается список пользователей. 12 | 13 | **Подсказка №2**. В выводе каждая операция должна сопровождаться распространенным текстовым комментарием (вспоминайте форматирование строк!). Выглядеть это должно *примерно* так: 14 | 15 | Вы выбрали пользователя githubuser. 16 | 17 | Вот список его репозиториев: 18 | name1: description1, 19 | name2: description2, 20 | name3: description3. 21 | 22 | Пользователь githubuser пишет на JavaScript и C#. 23 | 24 | Язык JavaScript используется в репозитории name1 и name2, язык C# используется в репозитории name3. 25 | 26 | Из списка githubuser, githubuser1, githubuser2, githubuser3 больше всего репозиториев у пользователя githubuser2. 27 | 28 | Самый популярный язык среди пользователей из списка githubuser, githubuser1, githubuser2, githubuser3 -- JavaScript. 29 | 30 | Больше всего подписчиков у пользователя githubuser3. 31 | 32 | 33 | Тренироваться можно, например, на следующих 20 (не)случайных юзерах гитхаба: `elmiram, maryszmary, lizaku, nevmenandr, ancatmara, roctbb, akutuzov, agricolamz, lehkost, kylepjohnson, mikekestemont, demidovakatya, shwars, JelteF, timgraham, arogozhnikov, jasny, bcongdon, whyisjake, gvanrossum`. 34 | 35 | ### Критерии оценки 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 |
БаллКритерий
1Программа запускается и оформлена по PEP8
1Программа разделена на функции
1Программа умеет выбирать пользователя из заданного списка и распечатывать список его репозиториев с описаниями
1Имя пользователя вводится с клавиатуры, при этом программа умеет ругаться, если введено что-то кроме имен пользователей из имеющегося списка, и просит в таком случае повторить попытку ввода
1Программа умеет распечатывать список языков пользователя и количество репозиториев, в которых они используются
1Программа умеет узнавать, у кого из пользователей больше всего репозиториев
1Программа умеет узнавать, у кого из пользователей больше всего подписчиков
2Программа умеет узнавать, какой язык самый популярный среди пользователей списка
1Грамотно, с использованием форматирования строк оформлен вывод
50 | -------------------------------------------------------------------------------- /Homeworks/HW5.md: -------------------------------------------------------------------------------- 1 | ## Поисковая система для корпуса 2 | 3 | В этом задании вам нужно будет написать свой "Яндекс", который будет искать информацию в ранее собранном вами корпусе газеты из [третьго ДЗ](https://github.com/ancatmara/learnpython2018/blob/master/Homeworks/Project.ipynb). 4 | 5 | Для этого вам потребуется: 6 | 7 | 1. Придумать структуру базы данных и добавить в нее названия статей, их тексты, очищенные от тегов и прочего мусора (те, что лежат у вас в папке `plain` в третьем ДЗ), лемматизированные тексты (те, что лежат в папке `mystem-plain`) и ссылки на эти статьи на сайте вашей газеты. По желанию можно добавить в базу и другие метаданные: дату, автора и т.д. 8 | 2. Создать веб-сервис, в котором можно будет вбить произвольную фразу и получить ссылки на материалы, где она встречается, и кусочек страницы с ней. Т.е. на странице результатов поиска должен выводиться список всех статей, в тексте которых нашлось заданное слово / фраза. Каждый элемент списка -- это ссылка на эту статью на сайте и кусочек текста статьи (того, что лежит в вашей базе данных), содержащий запрос. Размер выводимого кусочка статьи -- на ваше усмотрение, рекомендуемая длина -- 250-500 символов. 9 | 3. На запрос по любой форме слова должны выводиться статьи, где это слово встречается в любой форме, а не только в этой. Например, вы вводите "котик" и получаете статьи со словами "котикам", "котика", "котику" и т.д. Ровно такая же выдача должна получиться и по запросу "котиков", "котиками" и т.д. 10 | 11 | Результаты поиска желательно выводить на главной странице. Если для них создана отдельная страница, то поле для ввода поискового запроса должно быть и там. 12 | 13 | В качестве СУБД рекомендуем использовать SQLite. 14 | 15 | ### Критерии 16 | 17 | |Балл|Критерий| 18 | |----|--------| 19 | |1|Программа запускается и оформлена по PEP8. Соответствие PEP8 можно проверить с помощью команды `pycodestyle my_script_name.py` в командной строке.| 20 | |1|Создана структура базы данных, удовлетворяющая требованиям задачи.| 21 | |2|Выполнен перенос всех необходимых данных в БД (названия статей, ссылки, обычные и лемматизированные тексты).| 22 | |1|Создано фласк-приложение с формой поиска на главной странице| 23 | |2|При отправке запроса через форму поиска выдаются ссылки на статьи из базы данных (хотя бы какие-то - 1 балл, все нужные данные из базы со словом из запроса в любых формах - 2 балла).| 24 | |2|Помимо ссылок и названий статей на странице отображается кусок страницы, в котором был найден текст запроса (как в Яндексе, лемматизированное описание - 1 балл, исходный текст - 2 балла).| 25 | |1|Постраничное отображение результатов поиска (как в Яндексе).| 26 | |1|**Бонусный балл** за оформление сайта с помощью bootstrap| 27 | 28 | **NB!** Это задание, как и предыдущее, лучше сдавать в виде обычного .py скрипта (а не тетрадки). 29 | 30 | **NB!** Если Вы не сделали задание 3, то создайте базу данных с нуля. 31 | -------------------------------------------------------------------------------- /Homeworks/HW6.md: -------------------------------------------------------------------------------- 1 | # Домашнее задание №6 2 | ## VK API 3 | 4 | В домашнем задании вам нужно написать программу, которая обращается к открытому (то есть такому, чтобы для просмотра контента не нужна была авторизация) сообществу Вконтакте, выкачивает посты со стены и комментарии к ним. Сообщество можно выбрать любое, но постарайтесь не повторяться! 5 | 6 | Выберите сообщество поживее, чтобы там было много постов и много комментариев к ним. Посты должны содержать текст, и желательно не одну строчку, чтобы было, что исследовать. Обязательное условие: программа должна уметь скачивать со стены больше, чем 100 постов, и больше, чем 100 комментариев к посту (если их действительно больше 100). Кроме выкачивания нужно сделать следующее: 7 | 8 | * Посчитайте длину каждого поста и каждого комментария в словах. 9 | * Создайте график, описывающий, как длина поста соотносится со средней длиной комментариев. 10 | * Помимо выкачивания постов и комментариев, программа должна смотреть в профиль пользователя, который написал пост или сделал комментарий, и узнавать о нём социолингвистическую информацию: например, возраст и город (если они указаны). В таком случае, название города по его id можно узнать [средствами API](https://vk.com/dev/database.getCitiesById), а возраст нужно уметь вычислять. Обратите внимание, что разные поля в описании профиля ведут себя по-разному, для каждого нужно обязательно посмотреть документацию! 11 | * Постройте графики зависимости средней длины поста и средней длины комментария от различных социолингвистических параметров. 12 | 13 | **NB!** Для графиков, описывающих среднюю длину поста и комментария (в словах), нужно выбрать 4 каких-нибудь **разных** параметра: город, возраст, наличие фото, средняя длина описания в поле "о себе", вуз, количество указанных в профиле учебных заведений, количество друзей, количество языков и т.п. Два из этих параметров нужно использовать для построения графиков зависимости длины поста, другие два — для комментария. Т.е. всего в этом пункте 4 графика. 14 | 15 | Допустим, вы выбрали какой-нибудь паблик, где все посты публикуются от имени сообщества. Тогда можно построить графики зависимости средней длины поста, напимер, от месяца публикации и от года публикации (потому что об авторе нам тут сложно что-то узнать, а даже если и можно — он один, и это неинтересно). А комментаторов много, поэтому здесь можно использовать социолингвистическую информацию и построить графики зависимости длины комментария, например, от возраста и города. Или от пола и наличия фотографии в профиле. Или от пола и учебного заведения. Или от количества языков и средней длины "о себе". И так далее — простор для фантазии почти безграничен. 16 | 17 | Хотя бы 2 параметра должны быть информацией из профиля пользователя (т.е. если у вас все 4 графика, например, про время — число, месяц, год и день недели публикации — то так не пойдет, т.к. программа должна уметь доставать информацию из профиля автора). 18 | 19 | * Постройте график частотности для топ 20-30 слов, удалив перед этим стоп-слова. Проделайте это сначала с нелемматизированными текстами, а потом с лемматизированными (для лемматизации можно использовать pymystem pymorphy, на ваш вкус). Сильно ли отличаются эти графики? По желанию можно написать краткий анализ различий из 3-5 предложений. Можно построить не только диаграмму, но и облако слов. 20 | * Всего у вас должно получиться 7 графиков. Оформить грайфики можно как угодно, но главное, чтобы это было не оформление по умолчанию! Т.е. что-то в стиле нужно изменить самостоятельно. Также на графиках обязательно должен быть заголовок, подписи осей и подписи делений (например, в случае с городами подписями по оси Х будут названия городов). Картинки с графиками должны быть сохранены отдельными файлами в репозитории (а не только отображаться в тетрадке). 21 | * Выложите скачанные тексты: как и в случае с газетным корпусом, нужно выкладывать **не** на github, а в какое-нибудь облако, а ссылку на корпус добавить в readme. 22 | * Формат корпуса: должно быть выложено два файла в plain text, один с оригинальными текстами, другой с лемматизированными. Порядок постов и коментариев неважен. Объем корпуса: > 100 постов с комментариями (т.е. начиная от 101 до бесконечности). Если к какому-то из постов написано больше 100 комментариев, то все они должны быть выкачаны. 23 | 24 | **NB! Задание выполняется в ipynb-тетрадке с понятным названием (скажем, HW6_VK). Кроме того, обязательно должна быть ссылка на корпус! Без соблюдения этих двух условий задание не проверяется!** 25 | 26 | ## Критерии оценки 27 | 28 | |Балл|Критерий| 29 | |----|--------| 30 | |1|Программа запускается и оформлена по PEP8. Соответствие PEP8 можно проверить с помощью команды `pycodestyle my_script_name.py` в командной строке.| 31 | |2|Программа умеет выкачивать посты и комментариии (больше 100 постов и больше 100 комментариев к посту).| 32 | |1|Посчитана средняя длина поста и комментария в словах и построены соответствующие графики.| 33 | |1|Программа умеет доставать из профиля пользователя параметры №1 и №2 для графиков про среднюю длину **поста** (например, город с названием и возраст). В случае пабликов можно брать параметры не из профиля автора (например, год и день недели публикации поста).| 34 | |1|Построены графики зависимости средней длины поста от этих двух параметров, оформленные согласно требованиям. Графики со стандартными настройками без подписей — 0.5 балла.| 35 | |1|Программа умеет доставать из профиля пользователя параметры №3 и №4 для графиков про среднюю длину **комментария**.| 36 | |1|Построены графики зависимости средней длины поста от этих двух параметров, оформленные согласно требованиям. Графики со стандартными настройками без подписей — 0.5 балла.| 37 | |1|Построен график частотности для топ 20-30 слов по нелемматизированным текстам. График со стандартными настройками без подписей — 0.5 балла.| 38 | |1|Построен график частотности для топ 20-30 слов по лемматизированным текстам. График со стандартными настройками без подписей — 0.5 балла.| 39 | |**1**|**Бонусный балл.** Построено облако слов для топ 20-30 слов по лемматизированным текстам.| 40 | |**4**|**Бонусный балл.** Более сложная структура корпуса: сохранены не только тексты, но информация о пользователях, написавших тот или иной пост (id, город, возраст, пол, имя и далее по желанию), id поста/комментария и связь комментариев с постами. Можно сделать это в виде базы данных, можно просто в csv-таблице. В случае с БД за это задание дается 4 балла, в случае с таблицей — 3 балла.| 41 | 42 | ## Дедлайн 43 | 44 | |Группа|Дедлайн| 45 | |----|--------| 46 | |1|4 мая, 23.59| 47 | |2|28 апреля, 23.59| 48 | |3|4 мая, 23.59| 49 | |4|| 50 | -------------------------------------------------------------------------------- /Homeworks/HW7.md: -------------------------------------------------------------------------------- 1 | # ДЗ по графам и word2vec 2 | 3 | Ваша задача построить сеть для произвольного [семантического поля](https://www.krugosvet.ru/enc/gumanitarnye_nauki/lingvistika/SEMANTICHESKOE_POLE.html), где узлами будут слова, а ребрами наличие косинусного расстояния ≥0.5 в word2vec-модели (можно взять любую). Алгоритм работы следующий: 4 | 5 | 1. Выберите какое-нибудь семантическое поле, например, "транспорт", "глаголы говорения" и т.п. и в качестве первого узла или нескольких первых узлов возьмите любые слова из этого поля. Слова должны быть одной части речи! 6 | 2. Найдите соседей узла (узлов), заданного вами в качестве отправной точки, отфильтруйте их по значению косинусной близости и добавьте в граф. 7 | 3. Найдите соседей узлов, добавленных на предыдущем этапе, отфильтруйте их по значению косинусной близости и добавьте в граф. 8 | 4. Вычислите самые центральные узлы графа по degree centrality, betweenness centrality, closeness centrality и eigencentrality. 9 | 5. Вычислите плотность графа, его диаметр, радиус, коэффициент кластеризации и коэффициент ассортативности. 10 | 6. Попробуйте разделить граф на сообщества (можно выбрать любой алгоритм) и интерпретировать эти сообщества. Интерпретацию нужно написать в отдельной текстовой ячейке после кода, разбивающего граф на сообщества, или после визуализации графа. 11 | 7. Визуализируйте граф. Размер и цвет узлов должен соответствовать каким-то параметрам — например, размер может показывать центральность по любой из метрик, а цвет — разбиение на сообщества. Выбранные параметры должны быть указаны либо в комментариях к коду, либо в отдельной текстовой ячейке с описанием графа. Узлы должны быть подписаны. 12 | 13 | **NB! Задание выполняется в виде .ipynb-тетрадки. Однако, если вы решите делать веб-приложение на бонусный балл, необходимо сдать обычный .py скрипт (или несколько скриптов).** 14 | 15 | ## Критерии оценки 16 | 17 | |Балл|Критерий| 18 | |----|--------| 19 | |1|Программа запускается и оформлена по PEP8. Соответствие PEP8 можно проверить с помощью команды `pycodestyle my_script_name.py` в командной строке.| 20 | |2|Строится граф для какого либо семантического поля. Находятся соседи первого и второго порядка для изначально заданного узла (узлов).| 21 | |1|В граф добавляются только узлы, имеющие косинусную близость **≥0.5** к любому из уже имеющихся| 22 | |1|Реализована фильтрация по частям речи: узлами являются только существительные, только глаголы и т.п.| 23 | |1|Рассчитана центральность узлов графа по метрикам, указанным в п.4.| 24 | |1|Рассчитано значение метрик, указанных в п.5.| 25 | |1|Граф разбит на сообщества, есть краткая интерпретация.| 26 | |1|Граф визуализирован| 27 | |1|Внешний вид графа задан в соответствии с п.7| 28 | |5|**Бонусный балл.** Задание оформлено в виде веб-приложения, где пользователь может ввести любое слово в качестве начального узла и получить картинку с соответствующим графом и все статистики по нему (те, что указаны в задании + количество узлов и ребер).| 29 | 30 | 31 | 32 | ## Дедлайн 33 | 34 | |Группа|Дедлайн| 35 | |----|--------| 36 | |1|7 июня 10:00| 37 | |2|10 июня 10.00| 38 | |3|7 июня 10:00| 39 | |4|3 июня 10:00| 40 | -------------------------------------------------------------------------------- /Homeworks/PapersHW.md: -------------------------------------------------------------------------------- 1 | # Собери корпус из газет 2 | 3 | ## Про проект 4 | 27-го октября (в 9:00), в репозитории должен лежать готовый код, который умеет делать всё, что перечислено ниже, а также в файле Readme.md в папке с проектом должна находиться ссылка на скачанные и обработанные файлы вашей газеты, лежащие **одним архивом** на Яндекс.Диске, Google Drive, Облаке@Мэйл.ру или на чём угодно подобном (но, пожалуйста, не надо заливать эти архивы на гитхаб). 5 | 6 | При этом 7 | 8 | 1. Общий объём скачанных текстов должен быть не меньше 100 тыс. слов. 9 | 2. В именах файлов не должно быть не-ascii символов (убираем их из url - [stackoverflow](https://stackoverflow.com/questions/4389572/how-to-fetch-a-non-ascii-url-with-python-urlopen)). 10 | 3. Структура каталогов, в которых хранятся файлы, должна быть следующей: корень/год/месяц/файлы с материалами за этот месяц 11 | 4. В корне также должна лежать csv-таблица с такими полями (разделитель - знак табуляции): 12 | 13 | ``` 14 | path author sex birthday header created sphere genre_fi type topic chronotop style audience_age audience_level audience_size source publication publisher publ_year medium country region language 15 | ``` 16 | 17 | Имена полей означают следующее: 18 | 19 | **path** -- это путь к чистому неразмеченному файлу со статьёй,
20 | **author** -- имя автора, если его можно достать со страницы (и вообще если оно есть),
21 | **sex** -- поле оставить пустым,
22 | **birthday** -- оставить пустым
23 | **header** -- название статьи
24 | **created** -- дата в формате 07.01.2012 (день.месяц.год)
25 | **sphere** -- слово "публицистика"
26 | **genre_fi** -- оставить пустым
27 | **type** -- оставить пустым
28 | **topic** -- категория, если мы её можем найти на странице со статьёй
29 | **chronotop** -- оставить пустым
30 | **style** -- слово "нейтральный"
31 | **audience_age** -- слово "н-возраст"
32 | **audience_level** -- слово "н-уровень"
33 | **audience_size** -- "районная", если газета районная, "республиканская", если газета республиканская, "городская" -- если городская
34 | **source** -- URL, откуда статья была скачана
35 | **publication** -- название газеты
36 | **publisher** -- оставить пустой
37 | **publ_year** -- год публикации
38 | **medium** -- слово "газета"
39 | **country** -- слово "Россия"
40 | **region** -- Название региона, откуда ваша газета
41 | **language** -- слово "ru"
42 | 43 | Таким образом, со страницы со статьей нужно еще извлечь, если возможно, имя автора, дату публикации, название публикации, приписанные категории. 44 | 45 | Кроме того, коллекция текстов с сайта газеты должна быть представлена в трёх видах (каждый вид в отдельной папке): 46 | 47 | 1. Неразмеченный текст в формате "для чтения" (текст разделен на абзацы тэгами

+ картинки, но ничего кроме этого). 48 | 49 | В нём перед текстом должны быть такие строки (после собаки и примыкающего к ней слова через пробел нужно написать релевантную информацию): 50 | 51 | @au имя автора (если автора нет, пишем Noname)
52 | @ti Название статьи
53 | @da дата в формате 12.02.2012
54 | @topic категория, если мы её можем найти на странице со статьёй
55 | @url URL, откуда мы скачали страницу

56 | 57 | 2. Размеченный mystem текст в формате XML 58 | 59 | 3. Размеченный mystem текст в формате plain text 60 | 61 | 62 | Соответственно, сама программа (в одном или в нескольких файлах) должна уметь: 63 | 64 | 1. Скачивать страницы с выбранного сайта, обходя его по принципу краулера. При этом программа не должна заходить на одни и те же страницы несколько раз. 65 | 2. Извлекать со страниц информацию для метатаблицы (если она доступна) и сам текст. 66 | 3. Генерировать вид "для чтения", убирая со страницы всю лишнюю информацию. 67 | 4. Раскладывать скачанные тексты по папкам. 68 | 5. Вызывать mystem и делать морфологическую разметку текста (таким образом, чтобы каждому слову была присвоена информация о лемме и грамматическая информация с учётом контекстно снятой омонимии). 69 | 70 | 71 | ## Про каталог еще раз 72 | 73 | Каталог должен выглядеть вот так: 74 | 75 | ``` 76 | 📂газета 77 | | 78 | |____ metadata.csv 79 | | 80 | |____📂html 81 | | | 82 | | |____📂2016 83 | | | | 84 | | | |____📂1 85 | | | | | 86 | | | | |____ статья1.html 87 | | | | | 88 | | | | |____ статья2.html 89 | | | | 90 | | | |____📁2 91 | | | 92 | | |____📁2015 93 | | 94 | |____📂mystem-xml
95 | | | 96 | | |____📂2016 97 | | | | 98 | | | |____📂1 99 | | | | | 100 | | | | |____ статья1.xml 101 | | | | | 102 | | | | |____ статья2.xml 103 | | | | 104 | | | |____📁2 105 | | | 106 | | |____📁2015 107 | | 108 | |____📂mystem-plain 109 | | 110 | |____📂2016 111 | | | 112 | | |____📂1 113 | | | | 114 | | | |____ статья1.txt 115 | | | | 116 | | | |____ статья2.txt 117 | | | 118 | | |____📁2 119 | | 120 | |____📁2015 121 | ``` 122 | 123 | ## Про устройство программы 124 | 125 | Подумаем, как может быть устроена ваша программа. 126 | 127 | **Путь первый** 128 | 129 | Для каждой задачи написать отдельную функцию. Написать главную функцию, которая запускает программу. 130 | 131 | 132 | **Путь второй** 133 | 134 | Можно для каждой логической группы функций создать отдельный файл, например, файл для функций, работающих с майстемом, файл для функций, выкачивающих газетные страницы и т.д. Создать главный файл, в котором прописана основная логика программы. В этот главный файл импортируются все остальные функции. 135 | 136 | ## Про папки 137 | 138 | Вспомним, как на питоне работать с папками. Для этого используется модуль `os`. 139 | 140 | Создать папку: `os.mkdir(dirname)` или `os.makedirs(dirname)`. `mkdir` создает директорию и вызывает ошибку, если она существует. `makedirs` создает директории и все несуществующие директории в указанном пути (например, если в `dirname` указан путь `./dir1/dir2/dir3`, и при этом dir1 и dir2 не существуют, то функция их создаст). 141 | 142 | Проверить, существует ли папка: `os.path.exists(dirname)` (возвращает `True` или `False`). 143 | Пройтись по каталогу: `os.walk(dirname)`. 144 | 145 | Вот такой маленький сниппет, возможно, вам пригодится: 146 | ```python 147 | import os 148 | 149 | if not os.path.exists(directory): 150 | os.makedirs(directory) 151 | ``` 152 | 153 | ## Как просто вставить куски строки в шаблон 154 | 155 | Для такого форматирования можно использовать оператор %. 156 | 157 | `%s` в строке значит, что в это место вставится строка. `%d` значит, что в это место вставится число. Эти последовательности пишутся в том месте строки, куда нужно что-то вставить. 158 | 159 | После строки пишется знак `%` и затем кортеж (в круглых скобочках) из элементов, которые нужно вставить: 160 | 161 | ```python 162 | row = '%s\t%s\t\t\t%s\t%s\tпублицистика\t\t\t%s\t\tнейтральный\tн-возраст\tн-уровень\tрайонная(если районная)\t%s\tназвание газеты\t\t%s\tгазета\tРоссия\tкакой-то регион\tru' 163 | 164 | print(row % ('тут ссылка', 'Петя', 'Название статьи', '26.09.2016', 'образование', 'url', '2016')) 165 | print(row % ('тут другая ссылка', 'Автор', 'Другая статья', '27.09.2016', 'спорт', 'url2', '2016')) 166 | ``` 167 | 168 | 169 | 170 | -------------------------------------------------------------------------------- /Homeworks/Project.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Собери корпус из газет\n", 8 | "\n", 9 | "## Про проект\n", 10 | "Итак, уже скоро мы завершаем марафон \"Собери корпус из газет\". К концу сессионно недели, 29 октября (в 10:00), в репозитории должен лежать готовый код, который умеет делать всё, что перечислено ниже, а также в файле Readme.md в папке с проектом должна находиться ссылка на скачанные и обработанные файлы вашей газеты, лежащие **одним архивом** на Яндекс.Диске, Google Drive, Облаке@Мэйл.ру или на чём угодно подобном (но, пожалуйста, не надо заливать эти архивы на гитхаб).\n", 11 | "\n", 12 | "При этом \n", 13 | "\n", 14 | "1. Общий объём скачанных текстов должен быть не меньше 100 тыс. слов. \n", 15 | "2. В именах файлов не должно быть не-ascii символов (убираем их из url - [stackoverflow](https://stackoverflow.com/questions/4389572/how-to-fetch-a-non-ascii-url-with-python-urlopen)).\n", 16 | "3. Структура каталогов, в которых хранятся файлы, должна быть следующей: корень/год/месяц/файлы с материалами за этот месяц\n", 17 | "4. В корне также должна лежать csv-таблица с такими полями (разделитель - знак табуляции):" 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": null, 23 | "metadata": {}, 24 | "outputs": [], 25 | "source": [ 26 | "path\tauthor\theader\tcreated\tsphere\ttopic\tstyle\taudience_age\taudience_level\taudience_size\tsource\tpublication\tpubl_year\tmedium\tcountry\tregion\tlanguage" 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "metadata": {}, 32 | "source": [ 33 | "Имена полей означают следующее:\n", 34 | "\n", 35 | "**path** -- это путь к чистому неразмеченному файлу со статьёй,
\n", 36 | "**author** -- имя автора, если его можно достать со страницы (и вообще если оно есть),
\n", 37 | "**header** -- название статьи
\n", 38 | "**created** -- дата в формате 07.01.2012 (день.месяц.год)
\n", 39 | "**sphere** -- слово \"публицистика\"
\n", 40 | "**topic** -- категория, если мы её можем найти на странице со статьёй
\n", 41 | "**style** -- слово \"нейтральный\"
\n", 42 | "**audience_age** -- слово \"н-возраст\"
\n", 43 | "**audience_level** -- слово \"н-уровень\"
\n", 44 | "**audience_size** -- \"районная\", если газета районная, \"республиканская\", если газета республиканская, \"городская\" -- если городская
\n", 45 | "**source** -- URL, откуда статья была скачана
\n", 46 | "**publication** -- название газеты
\n", 47 | "**publ_year** -- год публикации
\n", 48 | "**medium** -- слово \"газета\"
\n", 49 | "**country** -- слово \"Россия\"
\n", 50 | "**region** -- название региона, откуда ваша газета
\n", 51 | "**language** -- слово \"ru\"
\n", 52 | "\n", 53 | "Таким образом, со страницы со статьей нужно еще извлечь, если возможно, имя автора, дату публикации, название публикации, приписанные категории.\n", 54 | "\n", 55 | "Кроме того, коллекция текстов с сайта газеты должна быть представлена в трёх видах (каждый вид в отдельной папке):\n", 56 | "\n", 57 | "1. Неразмеченный текст. \n", 58 | "\n", 59 | " В нём перед текстом должны быть такие строки (после собаки и примыкающего к ней слова через пробел нужно написать релевантную информацию):\n", 60 | "\n", 61 | " @au имя автора (если автора нет, пишем None)
\n", 62 | " @ti Название статьи
\n", 63 | " @da дата в формате 12.02.2012
\n", 64 | " @topic категория, если мы её можем найти на странице со статьёй (если нет, пишем None)
\n", 65 | " @url URL, откуда мы скачали страницу

\n", 66 | "\n", 67 | "2. Размеченный mystem текст в формате XML\n", 68 | "\n", 69 | "3. Размеченный mystem текст в формате plain text\n", 70 | "\n", 71 | "\n", 72 | "Соответственно, сама программа (в одном или в нескольких файлах) должна уметь:\n", 73 | "\n", 74 | "1. Скачивать страницы с выбранного сайта, обходя его по принципу краулера. При этом программа не должна заходить на одни и те же страницы несколько раз.\n", 75 | "2. Извлекать со страниц информацию для метатаблицы (если она доступна) и сам текст.\n", 76 | "3. Раскладывать скачанные тексты по папкам.\n", 77 | "4. Вызывать mystem и делать морфологическую разметку текста таким образом, чтобы каждому слову была присвоена информация о лемме и грамматическая информация с учётом контекстно снятой омонимии. Начальную форму печатать не нужно. Граммемы должны быть английскими. Каждое предложение должно быть с новой строки (т.е. нужно полностью копировать ввод на вывод). \n", 78 | "\n", 79 | "\n", 80 | "## Про каталог еще раз\n", 81 | "\n", 82 | "Каталог должен выглядеть вот так:" 83 | ] 84 | }, 85 | { 86 | "cell_type": "code", 87 | "execution_count": null, 88 | "metadata": { 89 | "collapsed": true 90 | }, 91 | "outputs": [], 92 | "source": [ 93 | "📂газета\n", 94 | "|\n", 95 | "|____ metadata.csv\n", 96 | "|\n", 97 | "|____📂plain\n", 98 | "| |\n", 99 | "| |____📂2016\n", 100 | "| | |\n", 101 | "| | |____📂1\n", 102 | "| | | |\n", 103 | "| | | |____ статья1.txt\n", 104 | "| | | |\n", 105 | "| | | |____ статья2.txt\n", 106 | "| | |\n", 107 | "| | |____📁2\n", 108 | "| |\n", 109 | "| |____📁2015\n", 110 | "|\n", 111 | "|____📂mystem-xml\n", 112 | "| |\n", 113 | "| |____📂2016\n", 114 | "| | |\n", 115 | "| | |____📂1\n", 116 | "| | | |\n", 117 | "| | | |____ статья1.xml\n", 118 | "| | | |\n", 119 | "| | | |____ статья2.xml\n", 120 | "| | |\n", 121 | "| | |____📁2\n", 122 | "| |\n", 123 | "| |____📁2015\n", 124 | "|\n", 125 | "|____📂mystem-plain\n", 126 | " |\n", 127 | " |____📂2016\n", 128 | " | |\n", 129 | " | |____📂1\n", 130 | " | | |\n", 131 | " | | |____ статья1.txt\n", 132 | " | | |\n", 133 | " | | |____ статья2.txt\n", 134 | " | |\n", 135 | " | |____📁2\n", 136 | " |\n", 137 | " |____📁2015" 138 | ] 139 | }, 140 | { 141 | "cell_type": "markdown", 142 | "metadata": {}, 143 | "source": [ 144 | "## Про устройство программы\n", 145 | "\n", 146 | "Подумаем, как может быть устроена ваша программа.\n", 147 | "\n", 148 | "**Путь первый** \n", 149 | "\n", 150 | "Для каждой задачи написать отдельную функцию. Написать главную функцию, которая запускает программу. При таком устройстве программы лучше писать ее в jupyter notebook.\n", 151 | "\n", 152 | "\n", 153 | "**Путь второй**\n", 154 | "\n", 155 | "Можно для каждой логической группы функций создать отдельный файл, например, файл для функций, работающих с майстемом, файл для функций, выкачивающих газетные страницы и т.д. Создать главный файл, в котором прописана основная логика программы. В этот главный файл импортируются все остальные функции. При таком устройстве программы каждый модуль будет отдельным скриптом с расширением .py" 156 | ] 157 | }, 158 | { 159 | "cell_type": "markdown", 160 | "metadata": {}, 161 | "source": [ 162 | "## Про папки\n", 163 | "\n", 164 | "Вспомним, как на питоне работать с папками. Для этого используется модуль `os`.\n", 165 | "\n", 166 | "Создать папку: `os.mkdir(dirname)` или `os.makedirs(dirname)`. `mkdir` создает директорию и вызывает ошибку, если она существует. `makedirs` создает директории и все несуществующие директории в указанном пути (например, если в `dirname` указан путь `./dir1/dir2/dir3`, и при этом dir1 и dir2 не существуют, то функция их создаст).\n", 167 | " \n", 168 | "Проверить, существует ли папка: `os.path.exists(dirname)` (возвращает `True` или `False`).\n", 169 | "Пройтись по каталогу: `os.walk(dirname)`.\n", 170 | "\n", 171 | "Вот такой маленький сниппет, возможно, вам пригодится:" 172 | ] 173 | }, 174 | { 175 | "cell_type": "code", 176 | "execution_count": null, 177 | "metadata": { 178 | "collapsed": true 179 | }, 180 | "outputs": [], 181 | "source": [ 182 | "import os\n", 183 | "\n", 184 | "if not os.path.exists(directory):\n", 185 | " os.makedirs(directory)" 186 | ] 187 | }, 188 | { 189 | "cell_type": "markdown", 190 | "metadata": {}, 191 | "source": [ 192 | "## Как просто вставить куски строки в шаблон\n", 193 | "\n", 194 | "Для такого форматирования можно использовать оператор %. \n", 195 | "\n", 196 | "`%s` в строке значит, что в это место вставится строка. `%d` значит, что в это место вставится число. Эти последовательности пишутся в том месте строки, куда нужно что-то вставить. \n", 197 | "\n", 198 | "После строки пишется знак `%` и затем кортеж (в круглых скобочках) из элементов, которые нужно вставить:" 199 | ] 200 | }, 201 | { 202 | "cell_type": "code", 203 | "execution_count": 8, 204 | "metadata": {}, 205 | "outputs": [ 206 | { 207 | "name": "stdout", 208 | "output_type": "stream", 209 | "text": [ 210 | "тут ссылка\tПетя\tНазвание статьи\t26.09.2016\tпублицистика\t\tобразование\tнейтральный\tн-возраст\tн-уровень\tрайонная(если районная)\turl\tназвание газеты\t2016\tгазета\tРоссия\tкакой-то регион\tru\n" 211 | ] 212 | } 213 | ], 214 | "source": [ 215 | "row = '%s\\t%s\\t%s\\t%s\\tпублицистика\\t\\t%s\\tнейтральный\\tн-возраст\\tн-уровень\\tрайонная(если районная)\\t%s\\tназвание газеты\\t%s\\tгазета\\tРоссия\\tкакой-то регион\\tru'\n", 216 | "\n", 217 | "print(row % ('тут ссылка', 'Петя', 'Название статьи', '26.09.2016', 'образование', 'url', '2016'))" 218 | ] 219 | }, 220 | { 221 | "cell_type": "code", 222 | "execution_count": 9, 223 | "metadata": {}, 224 | "outputs": [ 225 | { 226 | "name": "stdout", 227 | "output_type": "stream", 228 | "text": [ 229 | "тут другая ссылка\tАвтор\tДругая статья\t27.09.2016\tпублицистика\t\tспорт\tнейтральный\tн-возраст\tн-уровень\tрайонная(если районная)\turl2\tназвание газеты\t2016\tгазета\tРоссия\tкакой-то регион\tru\n" 230 | ] 231 | } 232 | ], 233 | "source": [ 234 | "print(row % ('тут другая ссылка', 'Автор', 'Другая статья', '27.09.2016', 'спорт', 'url2', '2016'))" 235 | ] 236 | }, 237 | { 238 | "cell_type": "markdown", 239 | "metadata": {}, 240 | "source": [ 241 | "Программа оценивается в 0 баллов в следующих случаях:\n", 242 | "- обнаружен плагиат;\n", 243 | "- скачано менее 100 000 слов.\n", 244 | "\n", 245 | "\n", 246 | " \n", 247 | " \n", 248 | " \t\n", 249 | " \n", 250 | " \n", 251 | " \n", 252 | " \n", 253 | " \n", 254 | " \n", 255 | "
БаллКритерий
1Программа запускается и оформлена по PEP8
1Программа разделена на функции
2Программа умеет автоматически скачивать материалы с выбранного сайта.
1Корректная структура папок, которая создается автоматически.
1Имена файлов содержат только ascii символы.
2Программа умеет автоматически извлекать метаданные со страницы и записывает их в CSV файл.
2Программа корректно использует MyStem для обработки текстов.
2Бонусный балл. Программа умеет генерировать вид \"для чтения\" (со страницы убираеются все ненужные данные кроме текста, разбитого на абзацы и картинок в этом тексте.
\n" 256 | ] 257 | }, 258 | { 259 | "cell_type": "code", 260 | "execution_count": null, 261 | "metadata": {}, 262 | "outputs": [], 263 | "source": [] 264 | } 265 | ], 266 | "metadata": { 267 | "kernelspec": { 268 | "display_name": "Python 3", 269 | "language": "python", 270 | "name": "python3" 271 | }, 272 | "language_info": { 273 | "codemirror_mode": { 274 | "name": "ipython", 275 | "version": 3 276 | }, 277 | "file_extension": ".py", 278 | "mimetype": "text/x-python", 279 | "name": "python", 280 | "nbconvert_exporter": "python", 281 | "pygments_lexer": "ipython3", 282 | "version": "3.6.6" 283 | } 284 | }, 285 | "nbformat": 4, 286 | "nbformat_minor": 1 287 | } 288 | -------------------------------------------------------------------------------- /Homeworks/QuestionnaireHW.md: -------------------------------------------------------------------------------- 1 | ## Проект №2 - Сайт-анкета 2 | 3 | Нужно написать сайт-анкету для (полевой) работы с информантом. 4 | 5 | **На сайте должны быть:** 6 | 7 | 1) Главная страница (127.0.0.1), на которой показывается анкета с полями. 8 | Данные, которые будут вводиться в анкету, должны записываться в файл (лучше всего csv). 9 | 10 | 2) Страница статистики (127.0.0.1/stats), на которой результаты должны систематизироваться и в удобном виде выводиться 11 | на экран (это могут быть таблицы, какие-то подсчеты и тд). 12 | 13 | 3) Страница с выводом всех данных (127.0.0.1/json), на которой возвращается json со всеми введенными на сайте данными. Этот json должен выводиться на веб-странице. 14 | 15 | 4) Страница поиска (127.0.0.1/search) и результатов поиска (127.0.0.1/results) . 16 | В ней нужно сделать минимум два поля поиска (например, текстовый ввод для поиска конкретного слова в ответах и чекбокс, где можно будет выбрать пол информанта). На странице должно быть описано, по каким данным ведется поиск. 17 | 18 | **Тема может быть любой**, вот примеры: 19 | 20 | - Лексико-типологическая анкета по какому-то лексическому полю (части тела, цвета, предметы мебели, домашняя утварь и всё, на что хватит вашей лингвистической фантазии). Анкета может быть в виде веб-формы с картинками того предмета/цвета, который должен назвать информант, и текстовыми полями, в которых он впишет названия предмета/цвета на своём языке. Кроме полей для названий предметов/цветов форма будет содержать поле, в котором информант должен будет указать свой язык. 21 | - Сбор словаря/грамматики в экспедиции. Например, в анкете могут быть слова из списка Сводеша, а информант должен ввести их перевод на свой язык. Кроме того, у каждого перевода может быть какой-то комментарий или какая-то другая дополнительная информация. 22 | - Сбор бытовой лексики русского языка. (Посмотрите, как это делает Борис Иомдин, например, вконтакте) 23 | - Что-то социолингвистическое, могут быть вопросы типа голосования (твОрог или творОг?) и обязательно информация о заполняющем (родной город, язык, возраст, образование, пол и тд) 24 | - Что-угодно другое лингвистическое и интересующее лично вас. 25 | 26 | ## Критерии 27 | 28 | |Балл|Критерий| 29 | |----|--------| 30 | |1|Программа запускается и оформлена по PEP8. Соответствие PEP8 можно проверить с помощью команды `pycodestyle my_script_name.py` в командной строке.| 31 | |2|На сайте есть главная страница с работающей формой-анкетой| 32 | |1|Данные из анкеты сохраняются в файл| 33 | |2|На сайте есть страница со статистикой по всем введенным данным| 34 | |2|На сайте есть страница, при обращении к которой программа выдает пользователю все результаты в json| 35 | |2|На сайте есть страница поиска; поиск работает| 36 | |**2**|**Дополнительный балл** за внешнее оформление сайта с использованием [bootstrap](https://www.w3schools.com/booTsTrap/default.asp)| 37 | |**1**|**Дополнительный балл:** на странице со статистикой есть визуализация: график или диаграмма, сделанная с помощью `matplotlib`| 38 | 39 | **NB!** Это задание лучше выполнять не в тетрадке, а в виде скрипта с расширением `.py`. Папка с html-файлами должна называться `templates` и лежать рядом с файлом программы. Если у вас есть картинки, то там же должна быть папка `static` с ними. 40 | 41 | ### Как вставить картинку в сайт на фласке? 42 | 43 | Картинки нужно сложить в папку `static`. В html-шаблоне нужно написать: 44 | 45 | `` 46 | 47 | Чтобы просто вставить картинку в html (без фласка), нужно написать так: 48 | `` 49 | -------------------------------------------------------------------------------- /Lessons/Flask/10. Flask (2) .ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Flask (2)\n", 8 | "\n", 9 | "## Словари в шаблонах\n", 10 | "\n", 11 | "Предположим, у нас есть словарь, в котором хранятся имена наших друзей и их почтовые адреса. И мы хотим выводить эти имена с адресами на нашем сайте. Мы можем написать что-то такое:" 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": 4, 17 | "metadata": { 18 | "collapsed": true 19 | }, 20 | "outputs": [], 21 | "source": [ 22 | "from flask import Flask\n", 23 | "from flask import render_template\n", 24 | "\n", 25 | "app = Flask(__name__)\n", 26 | "\n", 27 | "\n", 28 | "@app.route('/')\n", 29 | "def index():\n", 30 | " emailbook = {'Петя': 'petya@example.com',\n", 31 | " 'Вася': 'vasya@example.com',\n", 32 | " 'Катя': 'katya@example.com'}\n", 33 | " return render_template('index.html', emails=emailbook)\n", 34 | "\n", 35 | "if __name__ == '__main__':\n", 36 | " app.run()" 37 | ] 38 | }, 39 | { 40 | "cell_type": "markdown", 41 | "metadata": {}, 42 | "source": [ 43 | "Тогда в папке `templates` нам нужно создать файл `index.html`, в котором будут перебираться элементы словаря. Делается это с помощью функции `items()`. Вот так будет выглядеть `index.html`:" 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "execution_count": null, 49 | "metadata": { 50 | "collapsed": true 51 | }, 52 | "outputs": [], 53 | "source": [ 54 | "\n", 55 | "\n", 56 | "\n", 57 | " \n", 58 | " Почтовые адреса\n", 59 | "\n", 60 | "\n", 61 | "

Адреса моих друзей

\n", 62 | "\n", 67 | "\n", 68 | "" 69 | ] 70 | }, 71 | { 72 | "cell_type": "markdown", 73 | "metadata": {}, 74 | "source": [ 75 | "## Перенаправление\n", 76 | "\n", 77 | "Для того, чтобы направить пользователя на другую страницу, используется функция `redirect`. Например, вот приложение, в котором есть страница /time. С помощью функции `redirect` можно, например, реализовать такое:\n", 78 | "\n", 79 | "- если пользователь заходит на страницу /time в рабочее время (с 10 до 18), то он перенаправляется на главную страницу сайта,\n", 80 | "- если пользователь заходит на страницу в другое время, то он перенаправляется на страницу /hi." 81 | ] 82 | }, 83 | { 84 | "cell_type": "code", 85 | "execution_count": null, 86 | "metadata": { 87 | "collapsed": true 88 | }, 89 | "outputs": [], 90 | "source": [ 91 | "import datetime\n", 92 | "\n", 93 | "from flask import Flask\n", 94 | "from flask import url_for, render_template, request, redirect\n", 95 | "\n", 96 | "app = Flask(__name__)\n", 97 | "\n", 98 | "\n", 99 | "@app.route('/')\n", 100 | "def index():\n", 101 | " return '

Привет, мир!

'\n", 102 | "\n", 103 | "\n", 104 | "@app.route('/hi')\n", 105 | "@app.route('/hi/')\n", 106 | "def hi(user=None):\n", 107 | " if user is None:\n", 108 | " user = 'friend'\n", 109 | " return '

Привет, ' + user + '!

'\n", 110 | "\n", 111 | "\n", 112 | "@app.route('/time')\n", 113 | "def time_redirect():\n", 114 | " h = datetime.datetime.today().hour\n", 115 | " if 10 < h < 18:\n", 116 | " return redirect(url_for('index'))\n", 117 | " return redirect(url_for('hi'))\n", 118 | "\n", 119 | "\n", 120 | "if __name__ == '__main__':\n", 121 | " app.run(debug=True)" 122 | ] 123 | }, 124 | { 125 | "cell_type": "markdown", 126 | "metadata": {}, 127 | "source": [ 128 | "Когда вы пишете сайт на фласке у себя на компьютере, можно написать вместо `app.run()` вот так: `app.run(debug=True)` (см. выше последнюю строчку). Это значит, что если на сайте возникнет ошибка, то на странице с ошибкой выведется ее описание, и вы легко сможете понять, в каком месте кода все падает. Но когда вы будете выкладывать сайт в Интернет, нужно убедиться, что `debug` отключен.\n", 129 | "\n", 130 | "## Как вывести на веб-страничку содержимое текстового файла?" 131 | ] 132 | }, 133 | { 134 | "cell_type": "code", 135 | "execution_count": 10, 136 | "metadata": {}, 137 | "outputs": [], 138 | "source": [ 139 | "from flask import Flask\n", 140 | "from flask import url_for, render_template, request, redirect\n", 141 | "\n", 142 | "app = Flask(__name__)\n", 143 | "\n", 144 | "@app.route('/poem')\n", 145 | "def poem():\n", 146 | " with open(\"poem.txt\", \"r\", encoding='utf-8') as f:\n", 147 | " content = f.read().split('\\n')\n", 148 | " return render_template(\"poem.html\", content=content)\n", 149 | "\n", 150 | "if __name__ == '__main__':\n", 151 | " app.run(debug=True)" 152 | ] 153 | }, 154 | { 155 | "cell_type": "code", 156 | "execution_count": 8, 157 | "metadata": {}, 158 | "outputs": [], 159 | "source": [ 160 | "\n", 161 | "\n", 162 | "\n", 163 | " \n", 164 | " Зимнее утро\n", 165 | "\n", 166 | "\n", 167 | "

\n", 168 | " {%for i in content%}\n", 169 | " {{i}}\n", 170 | "
\n", 171 | " {%endfor%}\n", 172 | "

\n", 173 | "\n", 174 | "" 175 | ] 176 | }, 177 | { 178 | "cell_type": "markdown", 179 | "metadata": {}, 180 | "source": [ 181 | "## Задание для тренировки\n", 182 | "\n", 183 | "Скачайте из репозитория [список языковых кодов](https://github.com/elmiram/2016learnpython/blob/master/data/lang_codes.csv). \n", 184 | "После этого нужно создать сайт, в котором:\n", 185 | "1. На главной странице выводится список языков и их кодов (`127.0.0.1:5000`),\n", 186 | "2. Если зайти на страницу вида `127.0.0.1:5000/codes/какие-то_буквы`, то на этой странице выведется список только тех языков, коды которых начинаются с этих букв. Например, если зайти на `127.0.0.1:5000/codes/jp`, то выведется японский и еврейско-персидский, а если зайти на `127.0.0.1:5000/codes/j`, то японский, еврейско-персидский, еврейско-арабский и яванский.\n", 187 | "3. Есть форма на странице `127.0.0.1:5000/form`, в которой есть поле \"Язык\". В это поле пользователь будет вводить название языка, например \"японский\". Когда пользователь нажимает кнопку \"Отправить\", \n", 188 | " * если введенного языка нет в списке, пользователь попадает на страницу `127.0.0.1:5000/not_found` с соответствующим сообщением,\n", 189 | " * если введенный язык есть в списке, пользователь должен попасть на страницу `127.0.0.1:5000/lang/код_языка`. На этой странице должно выводиться следующее: название введенного языка, код введенного языка, названия всех языков, код которых начинается на ту же букву.\n", 190 | "4. На всех страницах есть кликабельная ссылка на главную и на страницу с формой.\n", 191 | "\n", 192 | "Пример сайта на фласке есть в репозитории [вот тут](https://github.com/ancatmara/learnpython2017/tree/master/%D0%A1%D0%B5%D0%BC%D0%B8%D0%BD%D0%B0%D1%80%D1%8B/flask_example). Там есть примеры использования всех функций фласка, которые мы проходили. (*Туда можно подглядывать.*)" 193 | ] 194 | } 195 | ], 196 | "metadata": { 197 | "kernelspec": { 198 | "display_name": "Python 3", 199 | "language": "python", 200 | "name": "python3" 201 | }, 202 | "language_info": { 203 | "codemirror_mode": { 204 | "name": "ipython", 205 | "version": 3 206 | }, 207 | "file_extension": ".py", 208 | "mimetype": "text/x-python", 209 | "name": "python", 210 | "nbconvert_exporter": "python", 211 | "pygments_lexer": "ipython3", 212 | "version": "3.6.6" 213 | } 214 | }, 215 | "nbformat": 4, 216 | "nbformat_minor": 1 217 | } 218 | -------------------------------------------------------------------------------- /Lessons/Flask/9. Flask (1).ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "collapsed": true 7 | }, 8 | "source": [ 9 | "# Пишем сайты на питоне\n", 10 | "\n", 11 | "## Вспоминаем, как работает интернет\n", 12 | "\n", 13 | "__Веб-сервер__\n", 14 | "* устройство vs. программа\n", 15 | "* задача — получать запросы от других компьютеров или программ (клиентов, clients) и отправлять запрошенные данные\n", 16 | "* основная функция — размещение сайтов (website hosting)\n", 17 | "\n", 18 | "__Термины__\n", 19 | "* *Запрос (request)* — сообщение от агента, желающего получить или разместить информацию\n", 20 | "* *Ответ (response)* — ответное сообщение сервера с кодом состояния и информацией (HTML, изображения, загружаемые файлы и т. п.)\n", 21 | "* *Протокол (protocol)* — набор правил, по которым составляются запросы и ответы \n", 22 | "* *Сессия (session)* — установка соединения между агентом и сервером и последующая серия запросов и ответов\n", 23 | "* *Гипертекст* — множество текстов, организованных в виде графа при помощи гиперссылок\n", 24 | "* *Протокол HTTP (HyperText Transfer Protocol)* — протокол для передачи гипертекстовых данных (обычно в виде HTML)\n", 25 | "* *URL (Uniform Resource Locator)*, веб-адрес ресурса — строка, представляющая собой уникальное имя, по которому можно найти в сети этот ресурс\n", 26 | "\n", 27 | "__Адресация__\n", 28 | "\n", 29 | "IP\n", 30 | "* *IP-адрес* — (пока что) набор из 4 байт, присваиваемый каждому подключённому к сети устройству\n", 31 | "* Некоторые IP-адреса уникальны, некоторые — нет (внутренние адреса в локальных сетях)\n", 32 | "* Практически любой ресурс (например, сайт) можно получить по его IP-адресу (например, через браузер)\n", 33 | "* Существуют зарезервированные адреса и диапазоны адресов, например, `127.0.0.1` — адрес данного устройства\n", 34 | "\n", 35 | "Порт\n", 36 | "* Каждый запрос обращается не просто к какому-то IP-адресу, а к некоторому порту на этом адресе\n", 37 | "* Веб-сервер имеет 65 535 портов, пронумерованных начиная с 1\n", 38 | "* Веб-сервер может прослушивать некоторые порты (listen to ports) и по-разному обрабатывать сообщения, поступившие на разные порты\n", 39 | "* Если порт не прослушивается, сообщения на этот порт останутся без ответа\n", 40 | "\n", 41 | "\n", 42 | "__URL__\n", 43 | "\n", 44 | "`http__://__www.example.com__:__1234__/__directory1/file1.html`\n", 45 | "\n", 46 | "`протокол__://__доменное имя или IP-адрес__:__порт__/__адрес файла на сервере`\n", 47 | "\n", 48 | "* Порт указывать не обязательно: используются стандартные порты (HTTP — 80, FTP — 20 и т. п.)\n", 49 | "* *DNS (Domain Name Servers)* — специальные сервера в сети, на которых хранятся таблицы соответствия между доменными именами и IP-адресами их серверов\n", 50 | "\n", 51 | "\n", 52 | "__HTML и скрипты__\n", 53 | "* страницы, содержимое (HTML-код) которых не изменяется, называются *статическими (static)*\n", 54 | "* страницы, содержимое которых может быть разным в зависимости от введённых пользователем данных, времени, IP-адреса и т. п., называются *динамическими (dynamic)*\n", 55 | "* динамические страницы создаются с помощью скриптов *на стороне сервера (server side scripts)*, написанных, например, на PHP или Python\n", 56 | "* скрипт порождает HTML и посылает его пользователю\n", 57 | "* пользователь не видит кода скрипта, выполняющегося на сервере\n", 58 | "* *скрипт на стороне клиента (client side script)* — вставка в HTML на каком-то языке программирования (например, JavaScript), позволяющая странице вести себя интерактивно\n", 59 | "* код клиентских скриптов посылается клиенту сервером вместе с HTML и не выполняется на сервере\n", 60 | "\n", 61 | "__Питон и сайты__\n", 62 | "\n", 63 | "Написать сайт на питоне значит написать такую программу, которая может работать веб-сервером или использоваться веб-сервером для порождения HTML-кода веб-страниц. Для этого существует несколько модулей, например, Django и Flask\n", 64 | "\n", 65 | "## flask\n", 66 | "\n", 67 | "### Intro\n", 68 | "\n", 69 | "* Программа, написанная с помощью flask, работает как веб-сервер\n", 70 | "* За каждую веб-страницу сайта отвечает какая-то функция, которая возвращает HTML- код этой страницы\n", 71 | "* Естественно, писать длинные куски HTML-кода внутри программы на питоне было бы странно, поэтому функции могут загружать HTML из заранее заготовленных файлов\n", 72 | "* Эти файлы могу содержать готовые страницы или шаблоны страниц на специальном языке\n", 73 | "\n", 74 | "Пример готового сайта на flask:" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": null, 80 | "metadata": {}, 81 | "outputs": [ 82 | { 83 | "name": "stderr", 84 | "output_type": "stream", 85 | "text": [ 86 | " * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)\n", 87 | "127.0.0.1 - - [29/May/2018 16:23:17] \"GET / HTTP/1.1\" 200 -\n", 88 | "127.0.0.1 - - [29/May/2018 16:23:17] \"GET /favicon.ico HTTP/1.1\" 404 -\n", 89 | "127.0.0.1 - - [29/May/2018 16:23:17] \"GET /favicon.ico HTTP/1.1\" 404 -\n", 90 | "127.0.0.1 - - [29/May/2018 16:23:17] \"GET / HTTP/1.1\" 200 -\n" 91 | ] 92 | } 93 | ], 94 | "source": [ 95 | "from flask import Flask\n", 96 | "\n", 97 | "app = Flask(__name__)\n", 98 | "\n", 99 | "@app.route('/')\n", 100 | "def index():\n", 101 | " return '

Hello, world!

'\n", 102 | "\n", 103 | "if __name__ == '__main__':\n", 104 | " app.run(debug=False)" 105 | ] 106 | }, 107 | { 108 | "cell_type": "markdown", 109 | "metadata": {}, 110 | "source": [ 111 | "Каждая страница сайта порождается какой-то функцией. Декоратор `@app.route(...)` перед функцией показывает, какой адрес будет у страницы, за которую отвечает эта функция:" 112 | ] 113 | }, 114 | { 115 | "cell_type": "code", 116 | "execution_count": null, 117 | "metadata": { 118 | "collapsed": true 119 | }, 120 | "outputs": [], 121 | "source": [ 122 | "@app.route('/')\n", 123 | "def index():\n", 124 | " return 'Main page'\n", 125 | "\n", 126 | "@app.route('/hi')\n", 127 | "def hi():\n", 128 | " return 'Hi!'" 129 | ] 130 | }, 131 | { 132 | "cell_type": "markdown", 133 | "metadata": {}, 134 | "source": [ 135 | "Одна функция может отвечать за несколько разных страниц:\n", 136 | "* Во-первых, декораторов может стоять несколько подряд.\n", 137 | "* Во-вторых, декораторы могут содержать переменные.\n", 138 | "\n", 139 | "Пример:" 140 | ] 141 | }, 142 | { 143 | "cell_type": "code", 144 | "execution_count": null, 145 | "metadata": { 146 | "collapsed": true 147 | }, 148 | "outputs": [], 149 | "source": [ 150 | "@app.route('/user/')\n", 151 | "def user_index(user):\n", 152 | " return 'This is the page of' + user" 153 | ] 154 | }, 155 | { 156 | "cell_type": "markdown", 157 | "metadata": {}, 158 | "source": [ 159 | "Переменные в адресах могут быть разного типа: `int` — целое число, `float` — действительное число, `path` — строка, которая может содержать слэши. Тип переменной можно указать вот так:" 160 | ] 161 | }, 162 | { 163 | "cell_type": "code", 164 | "execution_count": null, 165 | "metadata": { 166 | "collapsed": true 167 | }, 168 | "outputs": [], 169 | "source": [ 170 | "import datetime\n", 171 | "\n", 172 | "@app.route('/time/')\n", 173 | "def time_page(shift):\n", 174 | " h = datetime.datetime.today().hour\n", 175 | " h += shift\n", 176 | " return 'Time in your country:' + str(h)" 177 | ] 178 | }, 179 | { 180 | "cell_type": "markdown", 181 | "metadata": {}, 182 | "source": [ 183 | "Страницы часто содержат ссылки друг на друга, но чтобы поставить ссылку, нужно знать адрес. Чтобы узнать адрес страницы, которую создаёт какая-то функция, используется функция `url_for`:" 184 | ] 185 | }, 186 | { 187 | "cell_type": "code", 188 | "execution_count": null, 189 | "metadata": { 190 | "collapsed": true 191 | }, 192 | "outputs": [], 193 | "source": [ 194 | "from flask import url_for\n", 195 | "\n", 196 | "@app.route('/functions/')\n", 197 | "def f_address(fname):\n", 198 | " return 'The address is ' + url_for(fname)" 199 | ] 200 | }, 201 | { 202 | "cell_type": "markdown", 203 | "metadata": {}, 204 | "source": [ 205 | "### Обратная связь\n", 206 | "(вспоминаем прошлый семинар)\n", 207 | "\n", 208 | "* Для обратной связи с сервером часто используются HTML-формы\n", 209 | "* Форма должна содержать кнопку `Submit`\n", 210 | "* Формы могут содержать текстовые поля, галочки и т. п.\n", 211 | "* Данные (значения элементов) из формы отправляются на сервер с помощью метода GET или POST\n", 212 | "* При использовании метода GET данные приписываются к URL после знака `?`\n", 213 | "\n", 214 | "__Еще раз про HTML-формы__" 215 | ] 216 | }, 217 | { 218 | "cell_type": "code", 219 | "execution_count": null, 220 | "metadata": { 221 | "collapsed": true 222 | }, 223 | "outputs": [], 224 | "source": [ 225 | "
\n", 226 | " Имя:
\n", 227 | " Возраст:
\n", 228 | " Пароль:
\n", 229 | " студент\n", 230 | " \n", 231 | "
" 232 | ] 233 | }, 234 | { 235 | "cell_type": "markdown", 236 | "metadata": {}, 237 | "source": [ 238 | "При нажатии на кнопку `submit` и использовании GET на сервер отправляется запрос, URL которого содержит все значения параметров после `?`:\n", 239 | "\n", 240 | " www.example.com:5000/some_page.html?name=Petya&age=&student=on\n", 241 | "\n", 242 | "Почти все символы в таком URL, кроме латинских, будут закодированы с помощью percent encoding:\n", 243 | "\n", 244 | " name=%D0%A2%D0%B8%D0%BC%D0%BE%D1%84%D0%B5%D0%B9\n", 245 | "\n", 246 | "Чтобы использовать данные из формы в приложении flask, нужен объект `request`:\n", 247 | "* `request.method` — метод запроса\n", 248 | "* `request.args` — словарь со значениями аргументов из URL" 249 | ] 250 | }, 251 | { 252 | "cell_type": "code", 253 | "execution_count": null, 254 | "metadata": { 255 | "collapsed": true 256 | }, 257 | "outputs": [], 258 | "source": [ 259 | "from flask import request\n", 260 | "@app.route('/login')\n", 261 | "def login():\n", 262 | " if request.args['password'] == '123':\n", 263 | " return 'Name: ' + request.args['login']" 264 | ] 265 | }, 266 | { 267 | "cell_type": "markdown", 268 | "metadata": {}, 269 | "source": [ 270 | "\n", 271 | "### Шаблоны\n", 272 | "\n", 273 | "Динамические веб-страницы собираются из шаблонов: у шаблона есть постоянная часть и изменяющаяся часть. Flask позволяет хранить в файлах такие шаблоны страниц. __(!!!) Все шаблоны страниц должны находиться в папке `templates`.__\n", 274 | "\n", 275 | "Шаблон состоит из обычного html-кода. Но в этот обычный html могут быть вставлены специальные фрагменты кода, способного порождать разный html в зависимости от значений переменных. \n", 276 | "\n", 277 | "Эти специальные фрагменты пишутся внутри `{% ... %}` или `{{ ... }}`. При порождении HTML эти фрагменты заменяются на какой-то HTML-код по определённым правилам.\n", 278 | "\n", 279 | "Чтобы породить HTML по шаблону, используется функция `render_template()`:" 280 | ] 281 | }, 282 | { 283 | "cell_type": "code", 284 | "execution_count": null, 285 | "metadata": { 286 | "collapsed": true 287 | }, 288 | "outputs": [], 289 | "source": [ 290 | "from flask import render_template\n", 291 | "@app.route('/hello/')\n", 292 | "@app.route('/hello/')\n", 293 | "def hello(name=None):\n", 294 | " return render_template('hello.html', name=name)" 295 | ] 296 | }, 297 | { 298 | "cell_type": "markdown", 299 | "metadata": {}, 300 | "source": [ 301 | "* Функция `render_template` заменяет все вставки в фигурных скобках на какой-то HTML.\n", 302 | "* Во вставках можно использовать переменные, которые передаются в шаблон через `render_template`.\n", 303 | "\n", 304 | "Есть два вида вставок: `{{ ... }}` и `{% ... %}`.\n", 305 | "\n", 306 | "Язык, на котором пишутся эти вставки, похож на питон, но многие питоновские функции в шаблонах работать не будут\n", 307 | "\n", 308 | "__Вставки `{{ ... }}`__\n", 309 | "\n", 310 | "* `{{ ... }}` означает «вычислить значение выражения в скобках и заменить им вставку»\n", 311 | "* в скобках может быть переменная, например, `{{ name }}`\n", 312 | "* к переменным в скобках __нельзя__ применять произвольные функции: `{{ f(name) }}`\n", 313 | "* существует набор встроенных операций, которые можно выполнять над переменными\n", 314 | "* эти операции отделяются от переменной знаком | и тогда выражение пишется так `{{ name|length }}`, примеры операций: \n", 315 | " * `length`\n", 316 | " * `lower`, `upper`\n", 317 | " * `e` — автоматически экранировать спецсимволы HTML\n", 318 | " * `random` — взять случайный элемент из массива\n", 319 | " * `urlencode` — закодировать строку с помощью percent encoding\n", 320 | "\n", 321 | "__Вставки `{% ... %}`__\n", 322 | "\n", 323 | "В таких `{% ... %}` скобках пишутся специальные команды, аналогичные питоновским `if` и `for`.\n", 324 | "Примеры:\n", 325 | "\n", 326 | "`{% for i in arr %} ... {% endfor %}`\n", 327 | "\n", 328 | "`{% if ... %} ... {% endif %}`\n", 329 | "\n", 330 | "`{% elif ... %}`\n", 331 | "\n", 332 | "`{% else %}`\n" 333 | ] 334 | }, 335 | { 336 | "cell_type": "code", 337 | "execution_count": null, 338 | "metadata": { 339 | "collapsed": true 340 | }, 341 | "outputs": [], 342 | "source": [ 343 | "{% if username|length > 20 %}\n", 344 | "

Слишком длинное имя!

\n", 345 | "{% else %}\n", 346 | "

{{ username }}

\n", 347 | "{% endif %}" 348 | ] 349 | }, 350 | { 351 | "cell_type": "markdown", 352 | "metadata": {}, 353 | "source": [ 354 | "### Задание\n", 355 | "\n", 356 | "Написать приложение на фласке, которое позволяет узнать длину введенного пользователем слова в символах.\n", 357 | "\n", 358 | "1. На главной странице, index.html, пользователь должен ввести свое имя в форму. Форме должен предшествовать какой-нибудь текст, например *\"На этом сайте можно узнать длину любого слова. Представьтесь, пожалуйста, чтобы продолжить\"*.\n", 359 | "2. После отправки формы должен происходить редирект на страницу с текстом вроде *\"Здравствуйте, %user%! Введите какое-нибудь слово, а я посчитаю его длину\".* Т.е. в этом тексте обязательно должно быть употреблено имя пользователя, введенное в предыдущей форме. После этого текста должна быть еще одна форма, куда можно ввести слово. Страницу можно назвать как угодно -- главное, осмысленно.\n", 360 | "3. После отправки формы из пункта №2 результаты должны появляться на той же странице, текст примерно такой: *\"Вы ввели слово %word%. Его длина в символах -- %length%\".*" 361 | ] 362 | } 363 | ], 364 | "metadata": { 365 | "kernelspec": { 366 | "display_name": "Python 3", 367 | "language": "python", 368 | "name": "python3" 369 | }, 370 | "language_info": { 371 | "codemirror_mode": { 372 | "name": "ipython", 373 | "version": 3 374 | }, 375 | "file_extension": ".py", 376 | "mimetype": "text/x-python", 377 | "name": "python", 378 | "nbconvert_exporter": "python", 379 | "pygments_lexer": "ipython3", 380 | "version": "3.6.6" 381 | } 382 | }, 383 | "nbformat": 4, 384 | "nbformat_minor": 1 385 | } 386 | -------------------------------------------------------------------------------- /Lessons/Flask/flask_example/my_app.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | 3 | from flask import Flask 4 | from flask import url_for, render_template, request, redirect 5 | 6 | app = Flask(__name__) 7 | 8 | 9 | @app.route('/') 10 | def index(): 11 | urls = {'главная (эта страница)': url_for('index'), 12 | 'привет (переменные в url)': url_for('hi'), 13 | 'форма (форма и ответ на одном url)': url_for('form'), 14 | 'форма про книги (просто форма)': url_for('books'), 15 | 'спасибо (попадаем сюда только после формы про книги)': url_for('thanks'), 16 | 'время (используем redirect)': url_for('time_redirect'),} 17 | return render_template('index.html', urls=urls) 18 | 19 | 20 | @app.route('/hi') 21 | @app.route('/hi/') 22 | def hi(user=None): 23 | if user is None: 24 | user = 'друг' 25 | return '

Привет, ' + user + '!

' 26 | 27 | 28 | @app.route('/form') 29 | def form(): 30 | if request.args: 31 | name = request.args['name'] 32 | age = request.args['age'] 33 | st = True if 'student' in request.args else False 34 | return render_template('answer.html', name=name, age=age, student=st) 35 | return render_template('question.html') 36 | 37 | 38 | @app.route('/books') 39 | def books(): 40 | return render_template('books.html') 41 | 42 | 43 | @app.route('/thanks') 44 | def thanks(): 45 | if request.args: 46 | name = request.args['name'] 47 | book = request.args['book'] 48 | return render_template('thanks.html', name=name, book=book) 49 | return redirect(url_for('books')) 50 | 51 | 52 | @app.route('/time') 53 | def time_redirect(): 54 | h = datetime.datetime.today().hour 55 | if 10 < h < 18: 56 | return redirect(url_for('index')) 57 | return redirect(url_for('hi')) 58 | 59 | 60 | if __name__ == '__main__': 61 | app.run(debug=True) -------------------------------------------------------------------------------- /Lessons/Flask/flask_example/templates/answer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | Привет! 20 | 21 | 22 | 23 |
24 |

Привет, {{ name }}!

25 |

Твой возраст: {{ age }}

26 |

27 | Ты 28 | {% if not student %} 29 | не 30 | {% endif %} 31 | студент. 32 |

33 |
34 | 35 | 36 | -------------------------------------------------------------------------------- /Lessons/Flask/flask_example/templates/books.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Книги 19 | 20 | 21 | 22 |
23 |
24 |
25 |
26 | 27 |
28 |
29 | 30 | 31 | -------------------------------------------------------------------------------- /Lessons/Flask/flask_example/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Вот мой сайт 19 | 20 | 21 | 22 |
23 |

Привет, мир!

24 |

Список страниц на этом сайте:

25 |
    26 | {% for name, url in urls.items() %} 27 |
  • {{ name }}
  • 28 | {% endfor %} 29 |
30 |
31 | 32 | 33 | -------------------------------------------------------------------------------- /Lessons/Flask/flask_example/templates/question.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Форма 19 | 20 | 21 | 22 |
23 |
24 |
25 |
26 |
27 | 28 |
29 |
30 | 31 | 32 | -------------------------------------------------------------------------------- /Lessons/Flask/flask_example/templates/thanks.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Спасибо за ответ! 19 | 20 | 21 | 22 | 23 |

Спасибо за ответ, {{ name }}!

24 |

Мы записали, что это ваша любимая книга: {{ book }}.

25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Lessons/Flask/langcodes.csv: -------------------------------------------------------------------------------- 1 | Абазинский,abq 2 | Абхазский,abk 3 | Авадхи,awa 4 | Аварский,ava 5 | Авестийский,ave 6 | Адангме,ada 7 | Адыгейский,ady 8 | Азербайджанский,aze 9 | Аймара,aym 10 | Айну,ain 11 | Акан,aka 12 | Аккадский,akk 13 | Албанский,sqi 14 | Алеутский,ale 15 | Алтайский,alt 16 | Амхарский,amh 17 | Английский,eng 18 | Арабский,ara 19 | Аравакский,arw 20 | Арамейский,arc 21 | Арапахо,arp 22 | Арауканский,arn 23 | Армянский,hye/axm/xcl 24 | Ассамский,asm 25 | Ассирийский,aii 26 | Атапачские,ath 27 | Афарский,aar 28 | Африкаанс,afr 29 | Африхили,afh 30 | Ахвахский,akv 31 | Ацтекский,nah 32 | Ачехский,ace 33 | Ачоли,ach 34 | Балийский,ban 35 | Бамбара,bam 36 | Банда,bad 37 | Баса,bas 38 | Баскский,eus 39 | Башкирский,bak 40 | Беджа,bej 41 | Белорусский,bel 42 | Белуджский,bal 43 | Бемба,bem 44 | Бенгальский,ben 45 | Бикольский,bik 46 | Бини,bin 47 | Бирманский,mya 48 | Бислама,bis 49 | Болгарский,bul 50 | Боснийский,bos 51 | Брауи,brh 52 | Бретонский,bre 53 | Бугийский,bug 54 | Бурятский,bua 55 | Бходжпури,bho 56 | Ваи,vai 57 | Валлийский,cym 58 | Варай,war 59 | Вашо,was 60 | Венгерский,hun 61 | Венда,ven 62 | Вепсский,vep 63 | Воламо,wal 64 | Волапюк,vol 65 | Волоф,wol 66 | Вьетнамский,vie 67 | Га,gaa 68 | Гавайский,haw 69 | Гагаузский,gag 70 | Гайо,gay 71 | Галисийский,glg 72 | Ганда,lug 73 | Гереро,her 74 | Геэз,gez 75 | Гилбертский,gil 76 | Гонди,gon 77 | Готский,got 78 | Гребо,grb 79 | Гренландский,kal 80 | Греческий (новогреческий),ell 81 | Грузинский,kat 82 | Гуарани,grn 83 | Гуджарати,guj 84 | Гэльский,gla 85 | Дакота,dak 86 | Даргинский,dar 87 | Датский,dan 88 | Делавэрский,del 89 | Дзонг-кэ,dzo 90 | Дивехи (Мальдивский),div 91 | Динка,din 92 | Диула (Дьюла),dyu 93 | Догри,doi 94 | Древнегреческий,grc 95 | Древнеегипетский,egy 96 | Древнерусский,orv 97 | Древнесаксонский,osx 98 | Дуала,dua 99 | Дунганский,dng 100 | Еврейско-арабский,jrb 101 | Еврейско-персидский,jpr 102 | Зенагский,zen 103 | Зулу,zul 104 | Зуньи,zun 105 | Ибанский,iba 106 | Иврит,heb 107 | Игбо,ibo 108 | Идиш,yid 109 | Илоко,ilo 110 | Ингушский,inh 111 | Индонезийский,ind 112 | Интерлингва,ina 113 | Интерлингве,ile 114 | Инуктитут,iku 115 | Инупиак,ipk 116 | Ирландский,gle 117 | Исландский,isl 118 | Испанский,spa 119 | Итальянский,ita 120 | Ительменский,itl 121 | Йоруба,yor 122 | Кабардино-черкесский,kbd 123 | Кабильский,kab 124 | Кави,kaw 125 | Каддо,cad 126 | Казахский,kaz 127 | Калмыцкий,xal 128 | Камба,kam 129 | Каннада,kan 130 | Канури,kau 131 | Караимский,kdr 132 | Каракалпакский,kaa 133 | Карачаево-балкарский,krc 134 | Карельский,krl 135 | Кариб,car 136 | Каталанский,cat 137 | Качинский,kac 138 | Кашмири,kas 139 | Кечуа,que 140 | Кикуйю,kik 141 | Киньяма,kua 142 | Киргизский,kir 143 | Китайский,zho 144 | Коми,kom 145 | Коми-пермяцкий,koi 146 | Конго,kon 147 | Конкани,kok 148 | Коптский,cop 149 | Корейский,kor 150 | Корнский,cor 151 | Корсиканский,cos 152 | Корякский,kpy 153 | Коса,xho 154 | Кпелле,kpe 155 | Крик,mus 156 | Крымско-татарский,crh 157 | Кумыкский,kum 158 | Курдский,kur 159 | Курух,kru 160 | Кусайе,kos 161 | Кутенай,kut 162 | Кхаси,kha 163 | Кхмерский,khm 164 | Ладино,lad 165 | Лакский,lbe 166 | Ламба,lam 167 | Лаосский,lao 168 | Латинский,lat 169 | Латышский,lav 170 | Лахнда,lah 171 | Лезгинский,lez 172 | Лингала,lin 173 | Литовский,lit 174 | Лози,loz 175 | Луба-катанга,lub 176 | Луисеньо,lui 177 | Лунда,lun 178 | Луо (Кения и Танзания),luo 179 | Люксембургский,ltz 180 | Магахи,mag 181 | Мадурский,mad 182 | Майтхили,mai 183 | Макассарский,mak 184 | Македонский,mkd 185 | Малагасийский,mlg 186 | Малайский,msa 187 | Малаялам,mal 188 | Мальтийский,mlt 189 | Мандинго,man 190 | Манипури,mni 191 | Мансийский (Вогульский),mns 192 | Маори,mri 193 | Маратхи,mar 194 | Марвари,mwr 195 | Марийский (черемисский),chm 196 | Маршалльский,mah 197 | Масаи,mas 198 | Менде,men 199 | Микмак,mic 200 | Минангкабау,min 201 | Мокшанский,mdf 202 | Молдавский,mol 203 | Монго,lol 204 | Монгольский,mon 205 | Мооре,mos 206 | Мохаук,moh 207 | Мэнский (Мэнкский),glv 208 | Навахо,nav 209 | Нанайский (гольдский),gld 210 | Науру,nau 211 | Ндебеле северный,nde 212 | Ндебеле южный,nbl 213 | Ндунга,ndo 214 | Неварский,new 215 | Неидентифицированный,und 216 | Немецкий,deu 217 | Ненецкий (юрако-самоедский),yrk 218 | Непальский,nep 219 | Нзима,nzi 220 | Нивхский (гиляцкий),niv 221 | Нидерландский (Голландский),nld 222 | Нидерландский средневековый,dum 223 | Ниуэ,niu 224 | Ногайский,nog 225 | Норвежский [Norsk (bokm?l)]?,nor 226 | Ньоро,nyo 227 | Ньямвези,nym 228 | Ньянджа,nya 229 | Ньянколе,nyn 230 | Нюнорск (новонорвежский) [Norsk (nynorsk)]?,nno 231 | Оджибве,oji 232 | Окситанский,oci 233 | Ория,ori 234 | Оромо,orm 235 | Оседжи,osa 236 | Осетинский,oss 237 | Палау,pau 238 | Пали,pli 239 | Пампанга,pam 240 | Пангасинан,pag 241 | Папьяменто,pap 242 | Пенджабский,pan 243 | Персидский,fas 244 | Пехлевийский,pal 245 | Польский,pol 246 | Понапе,pon 247 | Португальский,por 248 | Пушту,pus 249 | Раджастхани,raj 250 | Разных семей языки,mul 251 | Раротонга,rar 252 | Ретороманский,roh 253 | Руанда,kin 254 | Румынский,ron 255 | Рунди,run 256 | Русский,rus 257 | Саамский,smi 258 | Самаритянский арамейский,sam 259 | Самоанский,smo 260 | Санго,sag 261 | Сандаве,sad 262 | Санскрит,san 263 | Сапотекский,zap 264 | Сардинский,srd 265 | Свази,ssw 266 | Себуано,ceb 267 | Селькупский,sel 268 | Сербский,srp 269 | Серер,srr 270 | Сибирскотатарский,sty 271 | Сидама,sid 272 | Сиксика,bla 273 | Сингальский,sin 274 | Синдхи,snd 275 | Сирийский,syr 276 | Словацкий,slk 277 | Словенский,slv 278 | Согдийский,sog 279 | Сомали,som 280 | Сото северный,nso 281 | Сото южный,sot 282 | Среднеанглийский,enm 283 | Средневерхненемецкий,gmh 284 | Среднеирландский,mga 285 | Среднефранцузский,frm 286 | Староанглийский,ang 287 | Староверхненемецкий,goh 288 | Староирландский,sga 289 | Старонорвежский,non 290 | Староперсидский,peo 291 | Старопровансальский,pro 292 | Старотурецкий,ota 293 | Старофранцузский,fro 294 | Суахили,swa 295 | Сукума,suk 296 | Сунданский,sun 297 | Сусу,sus 298 | Табасаранский,tab 299 | Тагальский,tgl 300 | Таджикский,tgk 301 | Таитянский,tah 302 | Тайский,tha 303 | Талышский,tly 304 | Тамашек,tmh 305 | Тамильский,tam 306 | Татарский,tat 307 | Тви,twi 308 | Телугу,tel 309 | Темне,tem 310 | Терено,ter 311 | Тибетский,bod 312 | Тиви,tiw 313 | Тигре,tig 314 | Тигринья,tir 315 | Тлингит,tli 316 | Тонга (Ньяса),tog 317 | Тонганский,ton 318 | Трукский,chk 319 | Тсвана,tsn 320 | Тсонга,tso 321 | Тувинский,tyv 322 | Тумбука,tum 323 | Турецкий,tur 324 | Туркменский,tuk 325 | Угаритский,uga 326 | Удмуртский (вотяцкий),udm 327 | Удэгейский,ude 328 | Узбекский,uzb 329 | Уйгурский,uig 330 | Украинский,ukr 331 | Ульчский,ulc 332 | Умбунду,umb 333 | Урду,urd 334 | Фанг,fan 335 | Фанти,fat 336 | Фарерский,fao 337 | Фиджи,fij 338 | Филиппинский,fil 339 | Финикийский,phn 340 | Финский (Suomi),fin 341 | Фон,fon 342 | Французский,fra 343 | Фризский,fry 344 | Фулах,ful 345 | Хайда,hai 346 | Хакасский,kjh 347 | Хантыйский (остяцкий),kca 348 | Хауса,hau 349 | Хилигайнон,hil 350 | Хинди,hin 351 | Хиримоту,hmo 352 | Хорватский,hrv 353 | Хотанский,kho 354 | Хупа,hup 355 | Цахурский,tkr 356 | Церковнославянский (Старославянский),chu 357 | Цимшиан,tsi 358 | Цыганский,rom 359 | Чагатайский,chg 360 | Чаморро,cha 361 | Чероки,chr 362 | Чеченский,che 363 | Чешский,ces 364 | Чжуанский,zha 365 | Чибча,chb 366 | Чинук жаргон,chn 367 | Чоктав,cho 368 | Чувашский,chv 369 | Чукотский,ckt 370 | Шайенн (Чейенн),chy 371 | Шанский,shn 372 | Шведский,swe 373 | Шона,sna 374 | Шорский,cjs 375 | Шотландский (англо-шотландский),sco 376 | Шугнанский,sgh 377 | Шумерский,sux 378 | Эве,ewe 379 | Эвенкийский (тунгусский),evn 380 | Эвенский,eve 381 | Эвондо,ewo 382 | Экаджук,eka 383 | Эламский,elx 384 | Эрзянский,myv 385 | Эсперанто,epo 386 | Эстонский,est 387 | Эфик,efi 388 | Яванский,jav 389 | Якутский (Саха),sah 390 | Яо,yao 391 | Яп,yap 392 | Японский,jpn 393 | -------------------------------------------------------------------------------- /Lessons/Heroku и командная строка/13a. Heroku.md: -------------------------------------------------------------------------------- 1 | # Heroku 2 | 3 | ## PaaS 4 | 5 | Мы с вами научились выкладывать наши сайты и ботов на Pythonanywhere, но это не единственный вариант. Существуют другие подобные сервисы - [Heroku](https://www.heroku.com/), [Scalingo](https://scalingo.com/), [Openshift](https://www.openshift.com/). 6 | 7 | Все они являются PaaS - Platform-as-a-Service, которые позволяют вам очень просто пользоваться облачным хостингом и быстро выкладывать свои приложения вместо того, чтобы самостоятельно настраивать сервер. 8 | 9 | От Pythonanywhere они отличаются тем, что для них разработчиками не всегда предоставлен такой же удобный веб-интерфейс, в котором многое делается кнопочками в панели управления, и нужный функционал мы получем через командную строку Unix. Но ощее с Pythonanywhere у них то, что там есть возможность делать хотя бы что-то из того, что вам нужно, бесплатно. 10 | 11 | Дело в том, что вслед за компанией Amazon многие другие IT-компании стали предоставлять пользователям (в числе которых и частные лица, и компании поменьше) облачные сервисы, то есть возможность не содержать на свои средства большой парк серверов (это часто неудобно, потому что бесперебойную работу серверов обеспечить не так просто), а покупать место на мощных серверах, которые содержит хозяин облака. Основные конкурирующие на этом поле сервисы -- это [Amazon Web Services](https://aws.amazon.com/ru/), [Google Cloud](https://cloud.google.com/) и [Microsoft Azure](https://azure.microsoft.com/ru-ru/). Все они платные (Google предоставляет на своей платформе условно-бесплатный тестовый период в один месяц), но мощные и надёжные. 12 | 13 | ## Почему еще и Heroku? 14 | 15 | У бесплатных аккаунтов Heroku есть некоторое количество преимуществ перед аналогичными аккаунтами Pythonanywhere: 16 | 17 | |Pythonanywhere | Heroku | 18 | | --- | --- | 19 | |только одно приложение | несколько приложений | 20 | | свой домен - платная функция | позволяет использовать собственное доменое имя | 21 | | ограниченный доступ к внешним ресурсам | доступ к внешним ресурсам не ограничен | 22 | 23 | __Подробнее про ограниченный доступ__: на Pythonanywhere можно обращаться лишь к тем сайтам, которые входят в белый список разрешенных ресурсов. Т.е. например, наш сайт, который регулярно скачивает новости с hse.ru не будет работать на Pythonanywhere, потому что hse.ru не включен в белый список. На Heroku таких ограничений нет. 24 | 25 | __Подробнее про количество бесплатных приложений__: на Heroku можно создавать несколько приложений бесплатно лишь до тех пор, пока у вас есть свободные Dyno (про это будет ниже). 26 | 27 | 28 | ## Подготовка к выкладыванию 29 | 30 | 1) Чтобы наш фласк-сайт или фласк-бот заработал на Heroku, нужно убедиться, что в конце основной программы написан вот такой код: 31 | 32 | ```python 33 | if __name__ == '__main__': 34 | import os 35 | app.debug = True 36 | port = int(os.environ.get("PORT", 5000)) 37 | app.run(host='0.0.0.0', port=port) 38 | ``` 39 | 40 | 41 | 2) В директории с вашим фласк-приложением обязательно должны быть следующие три файла: 42 | * __`requirements.txt`__ - в этом файле нужно перечислить все не стандартные питоновские модули, которые необходимы для вашей программы. В списке нужно указать не только название модуля, но и нужную вам версию. Выглядеть это будет примерно так: 43 | 44 | 45 | Flask==0.12.1 46 | pymorphy2==0.8 47 | pymystem3==0.1.5 48 | requests==2.13.0 49 | 50 | 51 | Обратите внимание, что в этот список НЕ НУЖНО писать setuptools и pip! 52 | 53 | Когда вы будете выкладывать приложение, Heroku прочитает файл `requirements.txt` и установит все перечисленные модули командой `pip install -r requirements.txt`. 54 | 55 | * __`runtime.txt`__ - в этом файле нужно написать одну строчку: 56 | 57 | python-3.6.1 58 | 59 | Если в директории нет `runtime.txt`, то Heroku будет по умолчанию думать, что ваше приложение написано на Python 2.7. 60 | 61 | * __`Procfile`__ - обратите внимание, что у файла нет расширения, иначе heroku не сможет прочитать его содержимое. В этом файле нужно написать одну строчку: 62 | 63 | web: python flask_app.py 64 | 65 | Вместо `flask_app.py` нужно написать название вашего файла с фласк-приложением. `Procfile` - это специальный файл, в котором нужно объяснить Heroku, как именно нужно запускать ваше приложение. `web` значит, что мы написали приложение, которое отвечает на http-запросы, `python flask_app.py` обозначает команду, с помощью которой приложение запускается. 66 | 67 | 68 | 3) Для выкладывания приложений на Heroku используется git. Поэтому если в вашей директории с проектом еще нет git-репозитория, его нужно создать. Открываем терминал (Mac, Linux) или командную строку (Windows) и пишем: 69 | * `cd путь-к-директории` - переходим в директорию с нашим фласк-проектом, 70 | * `git init` - создаем в текущей директории репозиторий, 71 | * `git add *` - говорим гиту следить за всеми файлами в репозитории, 72 | * `git commit -m 'Initial commit'` - делаем первый коммит. 73 | 74 | 75 | ## Как выложить сайт на Heroku? 76 | 77 | 1) Зарегистрироваться на сайте [Heroku](https://www.heroku.com/), ваш email будет логином. Когда вы зарегистрировались, вы попадаете в Dashboard. Сейчас у вас там ничего нет - вам предлагают создать приложение (an app) или пройти туториал по работе с Heroku и выбранного вами языка программирования. Туториал по питону там ориентирован на джанго, мы работаем с фласком, так что наши действия будут слегка отличаться. 78 | 79 | 2) Скачать установщик для вашей ОС и установить Heroku CLI - Command Line Interface - https://devcenter.heroku.com/articles/heroku-cli 80 | 81 | 3) Открыть терминал (Mac, Linux) или командную строку (Windows) и выполнить команды: 82 | 83 | * __`cd путь-к-директории`__ - переходим в директорию с нашим фласк-проектом, 84 | * __`heroku login`__ - логинимся в наш аккаунт Heroku, 85 | * ввести свой емейл и пароль, с которыми мы зарегистрировались, 86 | * __`heroku create`__ - создаем приложение, которое поможет Heroku получить наш код и запустить его. В этот момент Heroku делает сразу несколько вещей. 87 | 88 | Во-первых, он генерирует случайное название для нашего приложения, но можно передать ваше собственное название, например, `heroku create my-app-04062017`. Ваш сайт будет доступен по адресу `имя-приложения.herokuapp.com`. 89 | 90 | Во-вторых, к вашему репозиторию добавляется удаленный репозиторий (git remote), который называется `heroku`. У одного локального репозитория на вашем компьютере может быть несколько удаленных (например, у вас может быть `origin` - это ваш удаленный репозиторий на GitHub, и `heroku` - удаленный репозиторий на Heroku.) 91 | 92 | * __`git push heroku master`__ - эта команда отправляет наш код на облачный хостринг, и Heroku устанавливает нужные модули. 93 | * __`heroku ps:scale web=1`__ - эта команда говорит запустить наш фласк-сайт на одном dyno. 94 | 95 | > A dyno is a lightweight Linux container that runs a single user-specified command. 96 | 97 | То есть ваш сайт или бот будет работать на маленьком виртуальном Линукс-"сервере". Бесплатно вам доступно 550 или 1000 таких dyno. 98 | 99 | * __`heroku open`__ - эта команда открывает ваш сайт в браузере. Ура! Все готово! 100 | * Если по какой-то причине сайт не заработал, то нужно посмотреть логи: 101 | 102 | - __`heroku logs`__ - эта команда распечатает 100 последних строчек логов, т.е. если произошла какая-то ошибка, то информацию об этой ошибке вы увидите в конце логов. 103 | - или __`heroku logs --tail`__ - эта команда показывает логи в реальном времени, т.е. если ваша программа что-то печатает в консоль с помощью `print(...)` или питон печатает сообщение об ошибке, то вы будете в реальном времени видеть, что именно происходит. 104 | - подробнее - https://devcenter.heroku.com/articles/logging 105 | 106 | Когда вы меняете что-то в вашей программе\директории, то изменения нужно отправить на Heroku: 107 | 108 | git add * 109 | git commit -m "Demo" 110 | git push heroku master 111 | heroku ps:scale web=1 112 | 113 | 114 | ## Секретные ключи 115 | 116 | Поскольку мы отправляем все файлы на Heroku через git, возникает небольшая проблема: 117 | 118 | Что если у нас есть секретные файлы (например, API-токены или пароли), которые включены в `.gitignore`? Получается, мы никак не сможем отправить эти секретные файлы на облачный хостинг через git. 119 | 120 | ### Переменные среды 121 | Для работы с секретами рекомендуется использовать [переменные среды](https://en.wikipedia.org/wiki/Environment_variable): ваши ключи будут храниться в текстовых переменных вашей системы и в вашем Heroku-приложении, но при этом они никогда не попадут в открытый git-репозиторий. 122 | 123 | Раньше мы с вами писали секретные ключи в игнорируемый файл (например, `TOKEN = "......"` внутри `conf.py`) и импортировали секретные переменные с помощью `from conf import *`. 124 | 125 | Вместо этого, можно установить переменную среды прямо в терминале\командной строке: 126 | 127 | * Mac, Linux - `export SOME_SECRET_KEY=1c3-cr3am-15-yummy` 128 | * Windows - `set SOME_SECRET_KEY 1c3-cr3am-15-yummy` **(если у вас Windows 10, то `setx`)** 129 | * Heroku - `heroku config:set SOME_SECRET_KEY=1c3-cr3am-15-yummy` 130 | 131 | После этого и на вашем компьютере, и в облачном хостинге Heroku переменную среды можно прочитать с помощью питона: 132 | 133 | ```python 134 | >>> import os 135 | >>> os.environ["SOME_SECRET_KEY"] 136 | "1c3-cr3am-15-yummy" 137 | ``` 138 | 139 | 140 | То есть строчку `from conf import *` вам придется заменить на строчки вида: 141 | 142 | ```python 143 | import os 144 | SOME_SECRET_KEY = os.environ["SOME_SECRET_KEY"] 145 | ``` 146 | 147 | 148 | Кроме того, старые вебхуки с адресом на pythonanywhere уже не действительны, и их надо заменить на адрес вашего приложения. В целом, код очень простого бота из первого конспекта по телеграму, адаптированный под Heroku, будет выглядеть вот так: 149 | 150 | ```python 151 | import flask 152 | import telebot 153 | import os 154 | 155 | TOKEN = os.environ["TOKEN"] 156 | 157 | 158 | bot = telebot.TeleBot(TOKEN, threaded=False) 159 | 160 | 161 | bot.remove_webhook() 162 | bot.set_webhook(url="https://.herokuapp.com/bot") 163 | 164 | app = flask.Flask(__name__) 165 | 166 | @bot.message_handler(commands=['start', 'help']) 167 | def send_welcome(message): 168 | bot.send_message(message.chat.id, "Здравствуйте! Это бот, который считает длину вашего сообщения.") 169 | 170 | 171 | @bot.message_handler(func=lambda m: True) # этот обработчик реагирует все прочие сообщения 172 | def send_len(message): 173 | bot.send_message(message.chat.id, 'В вашем сообщении {} символов.'.format(len(message.text))) 174 | 175 | @app.route("/", methods=['GET', 'HEAD']) 176 | def index(): 177 | return 'ok' 178 | 179 | # страница для нашего бота 180 | @app.route("/bot", methods=['POST']) 181 | def webhook(): 182 | if flask.request.headers.get('content-type') == 'application/json': 183 | json_string = flask.request.get_data().decode('utf-8') 184 | update = telebot.types.Update.de_json(json_string) 185 | bot.process_new_updates([update]) 186 | return '' 187 | else: 188 | flask.abort(403) 189 | 190 | if __name__ == '__main__': 191 | import os 192 | app.debug = True 193 | port = int(os.environ.get("PORT", 5000)) 194 | app.run(host='0.0.0.0', port=port) 195 | ``` 196 | 197 | 198 | ## Как запустить что-то по расписанию? 199 | 200 | Если вы делаете какой-то веб-сервис, который должен обновлять какие-то данные через определённые промежутки времени (например, каждый день в 12:00 или каждый четверг в 17:25), то вы можете настроить стандартную Unix-утилиту cron, которая умеет запускать на сервере какой-то нужный пользователю процесс в тот момент, когда это ему необходимо. 201 | 202 | Утилита cron обычно уже входит в стандартную сборку дистрибутива и устанавливать её не нужно. Она имеет текстовый интерфейс настройки, то есть расписание придётся писать через консоль, в одном из консольных текстовых редакторов. Наиболее популярный из них -- [Vim](https://ru.wikipedia.org/wiki/Vim). Он не очень прост в обращении, потому что неинтуитивен. Перед тем, как его запускать, узнайте, [как его закрыть](https://ru.wikibooks.org/wiki/Vim) (почти как в сказке, нужно помнить про "горшочек, не вари", прежде чем сказать "горшочек, вари"). Недавно крупный сайт подсказок и ответов на вопросы о программировании Stackoverflow опубликовал [новость](https://stackoverflow.blog/2017/05/23/stack-overflow-helping-one-million-developers-exit-vim/), из которой следует, что вопрос "как выйти из Vim" является чуть ли не самым популярным при поиске вопросом. 203 | 204 | Есть и другой консольный редактор, nano, он проще и все команды, которые вы должны выполнить для тех или иных действий, постоянно показываются внизу экрана ("крышечка" означает "Ctrl"): 205 | 206 | ![nano](https://www.howtoforge.com/images/linux_nano_command/nano-editor-window.png) 207 | 208 | Однако он не установлен по умолчанию во всех дистрибутивах, и, возможно, его придётся установить самостоятельно. 209 | 210 | Создать или отредактировать расписание можно вызовом команды `crontab -e`. В открывшемся окне нужно будет описать [в формате cron](http://www.nncron.ru/nncronlt/help/RU/working/cron-format.htm), что вы хотите, чтобы было сделано, и когда это должно быть сделано. Формат cron подразумевает, что вы напишете `минута час день_месяца месяц день_недели команда`, а потом -- то, что должно будет запуститься, в том виде, в котором бы вы сами это запускали вручную в командной строке. 211 | 212 | Примеры расписания в cron: 213 | 214 | ``` 215 | # нечто будет выполняться каждую минуту: 216 | * * * * * python3 /home/user/script.py 217 | 218 | # только по выходным: 219 | * * * * 6,7 python3 /home/user/weekend.py 220 | 221 | # дважды в день: 222 | 20 11,16 * * * python3 /home/user/twice.py 223 | 224 | # один раз в году, в полночь 1-го января: 225 | 0 0 1 1 * python3 /home/user/HappyNewYear.py 226 | 227 | ``` 228 | 229 | Обратите внимание, что к программам нужно писать полный путь, потому что cron ничего не знает про то, какую директорию вы считаете рабочей. 230 | 231 | ## Полезная ссылка 232 | 233 | [Тут](https://tproger.ru/translations/telegram-bot-create-and-deploy/amp/) можно найти ещё одно руководство по запуску бота на хероку. 234 | 235 | 236 | 237 | -------------------------------------------------------------------------------- /Lessons/Heroku и командная строка/13b. Командная строка UNIX, логин на сервере.md: -------------------------------------------------------------------------------- 1 | # Командная строка UNIX, удалённый логин на сервере 2 | ## О чём речь? 3 | 4 | Помимо пользовательских компьютеров, которые мы используем в своей жизни для личных нужд и для работы (они называются "десктопами"), важное место в компьютерной инфраструктуре занимают так называемые "серверы". Это тоже компьютеры, обычно чуть более мощные и надёжные, чем десктопы, они могут располагаться в специальных [ЦОДах или дата-центрах](https://ru.wikipedia.org/wiki/%D0%94%D0%B0%D1%82%D0%B0-%D1%86%D0%B5%D0%BD%D1%82%D1%80) а ещё часто они постоянно подключены к Сети 24/7 и именно они обеспечивают работоспособность сайтов в Интернете и многих других сервисов, может быть, напрямую не связанных именно с Интернетом, например, банковских переводов. 5 | 6 | Когда мы через какой-нибудь браузер *заходим на сайт*, на самом деле за этим процессом стоит соединение по сети нашего компьютера с таким вот сервером (он называется "удалённым", потому что физически удалён от нас, может быть, на тысячи километров), который обрабатывает наш запрос, а одновременно с ним в ту же секунду может так же отвечать ещё тысячам других пользователей. 7 | 8 | Поэтому, чтобы, например, сделать свой собственный сайт, нужно иметь под рукой такой *сервер*, то есть компьютер, который будет, как минимум, постоянно подключён к Интернету, а ещё будет мощным и надёжным. 9 | 10 | ## UNIX и интерфейсы 11 | 12 | Из-за требований к надёжности и по ряду других исторических и коммерческих причин большинство серверов управляется не привычными для десктопа операционными системами семейства Windows или Mac OS, а операционными системами, которые называют UNIX-подобными, то есть воспроизводящими некоторые концептуальные идеи придуманной когда-то давно ОС UNIX (на самом деле, Mac OS X тоже является UNIX-подобной, и многое из того, о чём мы говорим ниже, справедливо и для неё). Прежде всего, это операционные системы (т.н. "дистрибутивы") на основе ядра Linux, а также в последнее время теряющие в популярности ОС семейства BSD. На практике (помимо других важных отличий) это обычно означает, что пользователю во всех этих системах предоставляется более-менее сходный интерфейс управления. И этот интерфейс не графический, то есть в нём нет привычных нам кнопочек и окон. То есть в принципе кнопочки и окошки (GUI -- graphic user interface) для UNIX-подобных систем возможны, но на серверах они не используются. 13 | 14 | Таким образом, те, кто взаимодействует с серверами: выкладывает на них свои сайты или занимается их обслуживанием ("администрирует"), пользуются интерфейсом командной строки, command line interface. Все вы немного имели с ним дело, когда изучали git и Mystem. Но для git есть и графические клиенты. С серверами и Mystem альтернативы командной строке почти нет. 15 | 16 | ## Командная строка 17 | 18 | Командная строка позволяет делать всё то, что пользователь привык делать, щёлкая мышкой: переходить между директориями, создавать и удалять файлы и папки, запускать программы. На самом деле, возможности командной строки даже шире и многообразнее, чем в графическом интерфейсе. 19 | 20 | Все эти возможности предоставляются таким образом. В текстовое поле вводится какая-то команда, представляющая собой зарезервированное слово, а для исполнения нажимается клавиша "Enter". Каждое такое слово -- это имя какой-нибудь маленькой программы, которая таким образом исполняется и делает то, что нам нужно. Например, она в каждый момент времени пользователь находится в каком-то конкретном месте файловой системы (дерева каталогов), и чтобы переместиться по ней вверх или вниз, нужно исполнить программу `cd` ("change directory"), передав ей параметр -- целевой каталог, куда нужно перейти. Например, ввод `cd text` приведёт к переходу пользователя во вложенную в текущую директорию "text" (если та и правда существует). 21 | 22 | ## Пробуем! 23 | 24 | Чтобы попробовать, как это работает, нужно загрузить реальную UNIX-подобную операционную систему. Мы будем тренироваться на дистрибутиве на основе ядра Linux, который называется Ubuntu, он действительно установлен в качестве основной операционки на многих серверах по всему миру. Запускать отдельный компьютер при этом не обязательно, операционную систему можно запустить внутри так называемой "виртуальной машины", то есть программы, которая делает вид, что она настоящий компьютер, а операционная система управляет этой программой и при этом думает, что управляет настоящим компьютером. 25 | 26 | ![Man In Black](https://vignette2.wikia.nocookie.net/aliens/images/4/42/Look_at_the_Reflection.jpg/revision/latest/scale-to-width-down/300?cb=20100729120113) 27 | 28 | 29 | 30 | *Кадр из фильма Man In Black: видна галактика, которая думает, что она находится в настоящей вселенной* 31 | 32 | В этом классе установлен менеджер виртуальных машин VirtualBox. Нужно запустить его и включить там виртуальную машину с Ubuntu. 33 | 34 | Если у вас всё получилось, то нужно щёлкнуть по логотипу Ubuntu в левом верхнем углу и в строке поиска напечатать Terminal (или нажать одновременно `Ctrl + Alt + T`). Здесь можно вводить команды для работы с интерфейсом командной строки. Команд этих существует великое множество, но начать нужно с простого. 35 | 36 | Прежде всего, нужно осмотреться. Слева от курсора написано, какую директорию командная строка считает текущей. Если там содержится символ \~, то это указание на так называемую "домашнюю директорию", то есть "порт приписки" того пользователя, под именем которого вы залогинились в системе. Там же вы увидите символ доллара, который можете помнить по документации к Mystem. 37 | 38 | Для UNIX-систем очень важно, под каким именем вы логинитесь в системе, и одна из центральных идей этой операционной системы резко отличается от того, что можно наблюдать в Windows. В Windows обычно кто угодно может сделать всё, что угодно. В UNIX за каждым пользователем чётко закреплены его права: что он может делать и чего не может. Скажем, пользователь обычно может создавать, изменять и удалять файлы и папки в своей домашней директории, которая располагается по адресу `/home/`, но не может никак изменять или удалять файлы в директориях, созданных другими пользователями. Это помогает сделать систему более безопасной, и надёжной, потому что в такой ситуации гораздо труднее случайно испортить что-нибудь важное. Поэтому не пытайтесь что-то изменять за пределами своей папки `/home/`, всё равно ничего не получится (в принципе, возможности для этого есть, но только при наличии специальных привилегий). 39 | 40 | Попробуем какие-нибудь команды. Выведем на экран список вложенных файлов и каталогов (если там ничего нет, то на экране ничего и не появится): 41 | 42 | ``` 43 | ls 44 | ``` 45 | 46 | (ls -- от "list") 47 | 48 | 49 | Теперь перейдём на уровень вверх и снова посмотрим на все лежащие тут файлы и папки: 50 | 51 | ``` 52 | cd ../ 53 | ls 54 | ``` 55 | 56 | Распечатаем полный путь к текущей директории: 57 | 58 | ``` 59 | pwd 60 | ``` 61 | 62 | Теперь вернёмся в домашнюю директорию, ведь только там мы можем делать что-нибудь законно (то есть не имея каких-то специальных прав): 63 | 64 | ``` 65 | cd 66 | ``` 67 | 68 | Теперь попробуем сделать то, что обычно делаем через графический интерфейс на своих десктопных компьютерах: 69 | 70 | Создадим директорию с именем "dir1": 71 | 72 | ``` 73 | mkdir dir1 74 | ``` 75 | 76 | Перейдём в неё: 77 | 78 | ``` 79 | cd dir1 80 | ``` 81 | Теперь создадим файл `test.txt` и что-нибудь туда запишем. 82 | 83 | ``` 84 | echo "This is my first file" > test.txt 85 | ``` 86 | В примере выше символ > отправляет аутпут команды слева в файл, указанный справа. Если такого файла нет, система автоматически его создаст. Но есть и специальная команда для создания файлов, `touch`. 87 | 88 | ``` 89 | touch test-1.txt 90 | ls 91 | ``` 92 | 93 | Команда `echo`выводит на экран последующую строку или значение переменной. Например, мы можем посмотреть значение системной переменной PATH. 94 | 95 | ``` 96 | echo $PATH 97 | ``` 98 | Теперь поищем что-нибудь в файле `test.txt` командой `grep` -- например, сочетание букв "is". 99 | У этой команды очень много возможностей, и подробнее про нее можно почитать [вот здесь](http://aidalinux.ru/w/Grep). 100 | 101 | ``` 102 | grep is < test.txt 103 | ``` 104 | Можно искать не только внутри файла, но и в названиях файлов и папок. Для этого в качестве аргумента нужно передать команде `grep ` список файлов -- например, это может быть аутпут команды `ls`. Символ | (pipe) передает аутпут одной команды другой команде в качестве инпута. 105 | 106 | ``` 107 | ls | grep test 108 | ``` 109 | 110 | И еще один пример с | -- сортировка (в обратном порядке, чтобы было интереснее). 111 | 112 | ``` 113 | ls | sort -r 114 | ``` 115 | 116 | Теперь скачаем сюда какой-нибудь файл из Интернета (без urllib.request!) и убедимся в том, что он действительно появился и выведем его содержимое на экран: 117 | 118 | ``` 119 | wget http://web-corpora.net/Test1/hello.py 120 | ls 121 | cat 122 | ``` 123 | 124 | Это файл на питоне. Попробуем его запустить из командной строки: 125 | 126 | ``` 127 | python hello.py 128 | ``` 129 | 130 | Получилось! 131 | 132 | Теперь копируем этот файл на уровень выше, а исходный удалим. 133 | 134 | ``` 135 | cp hello.py ../ 136 | rm hello.py 137 | ``` 138 | Файл `test.txt` переместим на уровень выше командой `mv` (по сути это то же самое , что мы сделали выше, только в одно действие), а файл `test-1.txt` просто удалим. 139 | 140 | ``` 141 | mv text.txt ../ 142 | rm test-1.txt 143 | ``` 144 | 145 | Теперь удалим директорию "dir1" (мы сможем это сделать только если она будет пустой): 146 | 147 | ``` 148 | cd ../ 149 | rmdir dir1 150 | ``` 151 | 152 | Что ещё можно сделать из командной строки? [Очень-очень много всего!](http://forum.ubuntu.ru/index.php?topic=14535.15) 153 | 154 | Потренироваться можно даже не имея под рукой виртуальной машины под VirtualBox. На [этом сайте](http://bellard.org/jslinux/) вы найдёте Linux-систему без графической оболочки прямо в своём браузере. Там работает большинство команд, которые используются в интерфейсе командной строки UNIX-подобных систем. 155 | 156 | Если на сервере установлен git, то можно склонировать на него репозиторий с гитхаба. 157 | 158 | ## Удалённый доступ, SSH 159 | 160 | Поскольку UNIX-подобные системы чаще всего установлены на удалённых серверах, а не на компьютерах, которые есть у нас под рукой, нужно уметь соединяться (логиниться) с такими компьютерами удалённо. Для этого нужно знать логин и пароль доступа к удалённому серверу, его адрес (например, IP-адрес) и иметь программу, которая знает специальный протокол, по которому обычно происходит такое соединение. Этот протокол (не единственный, но самый распространённый) называется SSH (secure shell). На юникс-подобных системах такие программы уже установлены по умолчанию, а вот на Windows их нужно специально устанавливать. Самый распространённый инструмент такого рода -- программа PuTTY, она есть на компьютерах в этом классе. 161 | 162 | ![PuTTY](http://www.losergeek.org/tutorials/ssh-proxy/PuTTY1.PNG) 163 | 164 | В поле Host Name нужно ввести IP-адрес сервера, поставить галочку на "SSH" и нажать "Open". Дальше сервер запросит у вас логин и пароль (их, как и IP-адрес сервера вам сообщит преподаватель, писать их в открытом виде на гитхабе небезопасно). Обратите внимание, что когда вы будете печатать пароль, на экране ничего не будет происходить. Ни звёздочек, ни точек появляться не будет. Так и нужно. Пароль всё равно печатается. Введите его и нажмите "Enter". Если всё пройдёт успешно, вы окажетесь в домашней директории пользователя. 165 | 166 | 167 | -------------------------------------------------------------------------------- /Lessons/Heroku и командная строка/cmd cheatsheet.md: -------------------------------------------------------------------------------- 1 | **Командная строка** - это такое окошко, куда можно вписать команду, и компьютер ее выполнит. На Windows она называется cmd, на Linux - Terminal. В командной строке вы увидите свое текущее местоположение (например, `ancatmara@INGEN C:\Users\ancatmara`), а на следующей строке - особый символ, который означает, что можно вводить команду. На Windows это **>**, а на Linux - **$**. 2 | 3 | Стандартный терминал cmd на Windows очень неудобный, так что можно выбрать и установить альтернативный вариант, [прочитав вот эту статью](https://habrahabr.ru/post/164687/). 4 | 5 | ## Самые главные команды в командной строке Windows и Linux 6 | 7 | | Значение | Windows | Linux / MacOS | 8 | | ------------- |-------------:| -----:| 9 | | Переход в другую директорию | cd | cd | 10 | | Создание файла | copy con | touch| 11 | | Создание папки | mkdir | mkdir | 12 | | Удаление файла | del, erase | rm; rm -rf -- удалить папку и все файлы в ней | 13 | | Удаление папки | rmdir | rmdir | 14 | | Вывод на экран сообщения | echo | echo | 15 | | Вывод на экран содержимого файла | type | cat| 16 | | Копирование файлов | copy, xcopy | cp | 17 | | Переименование файлов | ren, rename | mv | 18 | | Перемещение файлов | move | mv | 19 | | Поиск файлов | where | find, locate | 20 | | Вывод списка файлов и каталогов| dir | ls, dir | 21 | | Помощь | help | apropos, man, whatis | 22 | 23 | 24 | **Циркумфлекс** (вот этот знак "^") означает нажатие клавиши с Ctrl (^C = Ctrl + C). 25 | 26 | ^C — Прерывает команду, ну это все знают. 27 | 28 | ^S — Приостанавливает выполнение команды, а потом запускает. 29 | 30 | ^I — Аналог Tab, перебирает папки и файлы. 31 | 32 | ^M — Аналог Enter. 33 | 34 | ^H — Аналог Backspace. 35 | 36 | ## Работа с Python 37 | 38 | |Команда| Значение| 39 | |-------| -------:| 40 | |python| Запустить питон в терминале | 41 | |python --version| Посмотреть версию питона| 42 | |pip freeze| Посмотреть список установленных пакетов| 43 | |pip install| Установить пакет| 44 | |pip uninstall| Удалить пакет| 45 | |pip show| Показать информацию о конкретном пакете| 46 | |pip search| Найти пакет (если вы хотите установить что-то новое, но точно не помните название)| 47 | 48 | Подробнее про работу с pip можно почитать [на официальном сайте с документацией](https://pip.pypa.io/en/stable/). 49 | 50 | Если у вас установлена Анаконда, то вы можете пользоваться аналогом pip, который называется conda. Для него есть свой собсвенный [cheatsheet](https://conda.io/docs/_downloads/conda-cheatsheet.pdf) и [сайт с документацией](https://conda.io/docs/index.html). 51 | 52 | **NB!** Если команды python и pip не работают, вернитесь к семинару №8 и почитайте про настройку окружения. 53 | 54 | ## Работа с Git 55 | 56 | У git очень много возможностей, и про работу с ним написаны толстые книжки. Здесь перечислены только самые часто употребляемые команды. 57 | 58 | |Команда| Значение| 59 | |-------| -------:| 60 | |git clone| Склонировать репозиторий по указанной ссылке| 61 | |git pull| Скачать изменения из удаленного репозитория| 62 | |git init| Создать репозиторий | 63 | |git status| Посмотреть статус изменений| 64 | |git add| Добавить указанные файлы в список отслеживаемых| 65 | |git add \*| Добавить все файлы| 66 | |git rm| Удалить файлы| 67 | |git commit -m| Закоммитить изменения; после -m в кавычках пишется сообщение о том, что изменено| 68 | |git push| Отправить изменения в удаленный репозиторий| 69 | |git log| Посмотреть журнал действий| 70 | 71 | Более продвинутые вещи -- например, как исправлять ошибки или как работать с разными ветками -- можно почитать в [пошаговом тьюториале](https://git-scm.com/book/en/v1/Git-Basics-Undoing-Things) на официальном сайте. 72 | -------------------------------------------------------------------------------- /Lessons/JSON/data.json: -------------------------------------------------------------------------------- 1 | { 2 | "абв": 1, 3 | "где": 2, 4 | "ёжз": 3 5 | } -------------------------------------------------------------------------------- /Lessons/Markdown и git/DS_Store-gitignore.md: -------------------------------------------------------------------------------- 1 | # Про .DS_Store 2 | Специально для счастливых обладателей машин на Mac OS X :) 3 | 4 | ## Что это такое? 5 | Возможно, когда вы коммитили ваши файлы и папки через командную строку, вместе с тем, что вы _ожидали_ увидеть (папки и файлы), в репозитории вы увидели странный файл, который называется ```.DS_Store```. Не исключено, что вы уже начали нервничать по этому поводу. 6 | 7 | ```.DS_Store``` — это **системный** файл, в котором лежат пользовательские настройки текущей папки в духе "какие иконки использовать" и "как сортировать файлы в папке" (а сам DS_Store расшифровывается как _Desktop Service Store_). Его создаёт система, чтобы папка каждый раз выглядела именно так, как вы хотите. 8 | 9 | Обычно вы не видите этот файл. Это происходит, потому что Mac OS X скрывает от пользователя все файлы и директории, которые начинаются с точки (а это как раз про DS_Store). Такие файлы называются **скрытыми**. 10 | 11 | Когда мы создаём коммит, мы используем строку типа ```git add *``` или ```git add .```, то есть добавляем в коммит _все_ файлы (и подпапки текущей папки, если используем вариант со звёздочкой), включая скрытые. Поэтому в репозитории и отображается ```.DS_Store```. 12 | 13 | ## Как убрать .DS_Store из репозитория? 14 | Для этого воспользуемся удобной штукой, которая называется _gitignore_. Она позволяет указать файлы и папки, которые не нужно коммитить (что, на самом деле, вытекает из её названия: _git_ + _ignore_ :) 15 | 16 | ### Своими руками 17 | Откройте любой текстовый редактор и пропишите в нём **пути** к файлам и папкам, которые вы не хотите коммитить. Один файл/папка = одна строка. Это должно выглядеть примерно так: 18 | 19 | ![Прописываем путь](https://pp.userapi.com/c831109/v831109092/54c38/MTK3Yidf8yA.jpg "Прописываем путь") 20 | _Я использую Sublime Text_ 21 | 22 | После этого сохраните этот файл в папке, из которой коммитите в репозиторий. Дайте ему имя ```.gitignore``` (да-да, именно так, начиная с точки!). 23 | 24 | ![Называем файл](https://pp.userapi.com/c831109/v831109092/54c41/j5RJhd09p3M.jpg "Называем файл") 25 | 26 | Система предупредит вас о том, что вы собираетесь создать скрытый файл, который не будет видно. Мы теперь прошаренные и знаем, что так бывает, поэтому уверенно (принимаем условия данного лицензионного соглашения) нажимаем, что хотим начать с точки. 27 | 28 | ![Предупреждение](https://pp.userapi.com/c831109/v831109092/54c48/8dVqoil85cI.jpg "Предупреждение") 29 | 30 | Создайте коммит (```git add```, ```git commit```, всё как всегда) и запушьте (```git push```) его в ваш репозиторий. Не забудьте дать коммиту осмысленное сообщение. 31 | 32 | Готово, вы восхитительны! 33 | 34 | ### Автоматически (при создании репозитория) 35 | При создании репозитория вы можете использовать ```.gitignore```, который заранее собран усилиями тех, кто уже кодил на том или ином языке программирования. Это поможет не коммитить лишний "мусор", который возникает при запуске программ. 36 | 37 | При создании репозитория найдите в списке нужный вам язык и кликните по нему (можно использовать поиск). 38 | 39 | ![Авто-гитигнор](https://pp.userapi.com/c831109/v831109092/54c50/oe2IIKp6mmw.jpg "Авто-гитигнор") 40 | 41 | _Внимание на левый нижний угол_ 42 | 43 | Готово, вы восхитительны! 44 | 45 | > Важно: уже созданный gitignore можно и нужно редактировать, если вам это нужно. 46 | 47 | ## Как настроить систему так, чтобы скрытые файлы отображались? 48 | 49 | Следуйте [инструкции](https://ochprosto.com/kak-pokazat-skrytye-fajly-na-mac-os/). Если она вам не нравится, загуглите "отображение скрытых файлов mac os x" :) 50 | 51 | *Дарья Максимова* -------------------------------------------------------------------------------- /Lessons/Markdown и git/Markdown.md: -------------------------------------------------------------------------------- 1 | ## Markdown 2 | 3 | **Markdown** -- это упрощенный язык разметки, который преобразует \(почти\) обычный текст в html-страницу. Создан в 2004 году Джоном Грубером и Аароном Шварцем, затем был дополнен и адаптирован для различных приложений. 4 | 5 | Markdown-файлы имеют расширение .md или .markdown 6 | 7 | Ниже в серых блоках содержится то, как выглядит текст на стадии разметки, сразу после блока находится результат. 8 | 9 | #### 1. Форматирование в Markdown 10 | 11 | Заголовки в Markdown выделяются решетками \#: 12 | 13 | \# заголовок 1 уровня 14 | \#\# заголовок 2 уровня 15 | ... 16 | \#\#\#\#\#\# заголовок 6 уровня 17 | 18 | Чтобы выделить текст курсивом, нужно поставить в начале и в конце фрагмента текста \* или \_ \(не отделяя пробелом\): 19 | 20 | ``` 21 | *звезды* или _нижние подчеркивания_ 22 | ``` 23 | 24 | _звезды_ или _нижние подчеркивания_ 25 | 26 | Чтобы сделать текст жирным, нужно поставить в начале и в конце фрагмента текста \*\* или \_\_ \(не отделяя пробелом\): 27 | 28 | ``` 29 | **две звезды** или __два нижних подчеркивания__ 30 | ``` 31 | 32 | **две звезды** или **два нижних подчеркивания** 33 | 34 | Чтобы перечеркнуть текст, используйте ~~ в начале и в конце \(не отделяя пробелом\): 35 | 36 | ``` 37 | ~~две тильды~~ 38 | ``` 39 | 40 | ~~две тильды~~ 41 | 42 | ###### Списки 43 | 44 | Нумерованные списки задаются так \(уровни можно задать отступами\): 45 | 46 | ``` 47 | 1. первый элемент 48 | 2. второй элемент 49 | 3. третий элемент 50 | 4. четвертый элемент 51 | 1. пятый элемент 52 | ``` 53 | 54 | 1. первый элемент 55 | 2. второй элемент 56 | 3. третий элемент 57 | 4. четвертый элемент 58 | 5. пятый элемент 59 | 60 | Маркированные списки задаются с помощью дефисов, астерисков или плюсов \(уровни можно задать отступами\): 61 | 62 | ``` 63 | + первый элемент 64 | - второй элемент 65 | + третий элемент 66 | - четвертый элемент 67 | * пятый элемент 68 | ``` 69 | 70 | * первый элемент 71 | * второй элемент 72 | * третий элемент 73 | * четвертый элемент 74 | * пятый элемент 75 | 76 | #### 2. Объекты 77 | 78 | ###### Ссылки 79 | 80 | Ссылки и адреса электронной почты можно вставить без всего или в угловых скобках: 81 | 82 | ``` 83 | 84 | https://www.markdownguide.org 85 | 86 | 87 | eee@mail.ru 88 | ``` 89 | 90 | [https://www.markdownguide.org](https://www.markdownguide.org) 91 | [https://www.markdownguide.org](https://www.markdownguide.org) 92 | 93 | [eee@mail.ru](mailto:eee@mail.ru) 94 | eee@mail.ru 95 | 96 | Если нужно сделать гиперссылку, то она оформляется так: 97 | 98 | ``` 99 | [текст](https://www.markdownguide.org) 100 | ``` 101 | 102 | [текст](https://www.markdownguide.org) 103 | 104 | Можно добавить всплывающий при наведении комментарий: 105 | 106 | ``` 107 | [текст](https://www.markdownguide.org "это поможет") 108 | ``` 109 | 110 | [текст](https://www.markdownguide.org "это поможет") 111 | 112 | ###### Картинки 113 | 114 | Чтобы вставить картинку, нужно написать следующую строку \(без пробелов\): 115 | 116 | !\[\]\(ссылка на картинку\) 117 | 118 | Например: 119 | 120 | ``` 121 | ![](http://3.bp.blogspot.com/-_DLc3qDxsNA/VenIznBsK7I/AAAAAAAAB0A/GHjI_97B364/s1600/TheFunk.jpg) 122 | ``` 123 | 124 | ![](http://3.bp.blogspot.com/-_DLc3qDxsNA/VenIznBsK7I/AAAAAAAAB0A/GHjI_97B364/s1600/TheFunk.jpg) 125 | 126 | ###### Таблицы 127 | 128 | Строки в таблице разделяются переходом на новую строку, столбцы вертикальной чертой \(\|\) 129 | Между заголовком и телом таблицы вставляется строка с --- в каждой ячейке. Выравнивание задается положением двоеточия: 130 | 131 | ``` 132 | 1|2|3 133 | ---|:---:|---: 134 | да|нет|не знаю 135 | не знаю|нет|да 136 | нет|не знаю|да 137 | нет|да|не знаю 138 | да|не знаю|нет 139 | не знаю|да|нет 140 | ``` 141 | 142 | | 1 | 2 | 3 | 143 | | :--- | :---: | ---: | 144 | | да | нет | не знаю | 145 | | не знаю | нет | да | 146 | | нет | не знаю | да | 147 | | нет | да | не знаю | 148 | | да | не знаю | нет | 149 | | не знаю | да | нет | 150 | 151 | #### 3. Где можно использовать Markdown? 152 | 153 | * GitHub 154 | * Telegram 155 | * Tumblr 156 | * R, Python ... 157 | 158 | #### 4. Полезные \(и не очень\) ссылки 159 | 160 | [Изначальная страница проекта](https://daringfireball.net/projects/markdown/syntax) \(сейчас неактивна\) 161 | [Наиболее полное руководство](https://www.markdownguide.org) 162 | [Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Here-Cheatsheet) \(сжатый конспект\) 163 | [Help от гитхаба](https://help.github.com/categories/writing-on-github/) 164 | [Фичи для продвинутых от гитхаба](https://guides.github.com/features/mastering-markdown/) 165 | [Вдохновляющий набор расширений и приложений, где используется Markdown](https://github.com/mundimark/awesome-markdown) \(там есть, в том числе, про то, как делать презентации и документы, а также писать красивые письма\) 166 | [Курс на codeacademy](https://www.codecademy.com/en/courses/web-intermediate-en-Bw3bg/0/1) 167 | 168 | -------------------------------------------------------------------------------- /Lessons/Markdown и git/cmd cheatsheet.md: -------------------------------------------------------------------------------- 1 | **Командная строка** - это такое окошко, куда можно вписать команду, и компьютер ее выполнит. На Windows она называется cmd, на Linux - Terminal. В командной строке вы увидите свое текущее местоположение (например, `ancatmara@INGEN C:\Users\ancatmara`), а на следующей строке - особый символ, который означает, что можно вводить команду. На Windows это **>**, а на Linux - **$**. 2 | 3 | Стандартный терминал cmd на Windows очень неудобный, так что можно выбрать и установить альтернативный вариант, [прочитав вот эту статью](https://habrahabr.ru/post/164687/). 4 | 5 | ## Самые главные команды в командной строке Windows и Linux 6 | 7 | | Значение | Windows | Linux / MacOS | 8 | | ------------- |-------------:| -----:| 9 | | Переход в другую директорию | cd | cd | 10 | | Создание файла | copy con | touch| 11 | | Создание папки | mkdir | mkdir | 12 | | Удаление файла | del, erase | rm; rm -rf -- удалить папку и все файлы в ней | 13 | | Удаление папки | rmdir | rmdir | 14 | | Вывод на экран сообщения | echo | echo | 15 | | Вывод на экран содержимого файла | type | cat| 16 | | Копирование файлов | copy, xcopy | cp | 17 | | Переименование файлов | ren, rename | mv | 18 | | Перемещение файлов | move | mv | 19 | | Поиск файлов | where | find, locate | 20 | | Вывод списка файлов и каталогов| dir | ls, dir | 21 | | Помощь | help | apropos, man, whatis | 22 | 23 | 24 | **Циркумфлекс** (вот этот знак "^") означает нажатие клавиши с Ctrl (^C = Ctrl + C). 25 | 26 | ^C — Прерывает команду, ну это все знают. 27 | 28 | ^S — Приостанавливает выполнение команды, а потом запускает. 29 | 30 | ^I — Аналог Tab, перебирает папки и файлы. 31 | 32 | ^M — Аналог Enter. 33 | 34 | ^H — Аналог Backspace. 35 | 36 | ## Работа с Python 37 | 38 | |Команда| Значение| 39 | |-------| -------:| 40 | |python| Запустить питон в терминале | 41 | |python --version| Посмотреть версию питона| 42 | |pip freeze| Посмотреть список установленных пакетов| 43 | |pip install| Установить пакет| 44 | |pip uninstall| Удалить пакет| 45 | |pip show| Показать информацию о конкретном пакете| 46 | |pip search| Найти пакет (если вы хотите установить что-то новое, но точно не помните название)| 47 | 48 | Подробнее про работу с pip можно почитать [на официальном сайте с документацией](https://pip.pypa.io/en/stable/). 49 | 50 | Если у вас установлена Анаконда, то вы можете пользоваться аналогом pip, который называется conda. Для него есть свой собсвенный [cheatsheet](https://conda.io/docs/_downloads/conda-cheatsheet.pdf) и [сайт с документацией](https://conda.io/docs/index.html). 51 | 52 | **NB!** Если команды python и pip не работают, вернитесь к [семинару про настройку окружения](https://github.com/ancatmara/learnpython2018/blob/master/Lessons/1/1.%20Intro.ipynb). 53 | 54 | ## Работа с Git 55 | 56 | У git очень много возможностей, и про работу с ним написаны толстые книжки (см. пример ниже :D). Здесь перечислены только самые часто употребляемые команды. 57 | 58 | |Команда| Значение| 59 | |-------| -------:| 60 | |git clone| Склонировать репозиторий по указанной ссылке| 61 | |git pull| Скачать изменения из удаленного репозитория| 62 | |git init| Создать репозиторий | 63 | |git status| Посмотреть статус изменений| 64 | |git add| Добавить указанные файлы в список отслеживаемых| 65 | |git add \*| Добавить все файлы| 66 | |git rm| Удалить файлы| 67 | |git commit -m| Закоммитить изменения; после -m в кавычках пишется сообщение о том, что изменено| 68 | |git push| Отправить изменения в удаленный репозиторий| 69 | |git log| Посмотреть журнал действий| 70 | 71 | Более продвинутые вещи -- например, как исправлять ошибки или как работать с разными ветками -- можно почитать в [пошаговом тьюториале](https://git-scm.com/book/en/v1/Git-Basics-Undoing-Things) на официальном сайте. 72 | 73 | **NB!** Чтобы не печатать длинные пути целиком, существует *автозаполнение*: набираете 1-2 первые буквы, нажимаете tab и вуаля! 74 | 75 | ### Как настроить авторизацию в Git? 76 | 77 | После установки git необходимо его настроить, это делается с помощью двух команд: 78 | 79 | `git config --global user.name "ваш логин на github"` 80 | 81 | `git config --global user.email "почту, которую указали при регистрации на GitHub.com"` 82 | 83 | ### Vim 84 | 85 | В некоторых случаях -- например, если напишете просто `git commit`, а не `git commit -m`, вы попадете в страшное место под названием `vim`, из которого очень сложно выбраться. Да-да, один из самых популярных запросов на Stackoverflow -- ["How to exit the Vim editor"](https://stackoverflow.com/questions/11828270/how-to-exit-the-vim-editor). 86 | 87 | 88 | 89 | ![](https://zgab33vy595fw5zq-zippykid.netdna-ssl.com/wp-content/uploads/2017/05/meme.jpeg) 90 | 91 | Vim -- это текстовый редактор внутри командной строки. При попадании в него вы увидите пустой файл или файл, где строки начинаются с #. Нажатие на i (язык раскаладки клавиатуры имеет значение) переводит в режим редактирования (внизу появилось --INSERT--), теперь вы можете написать подпись, когда закончили писать, нажимайте клавишу Esc [полное название - Escape] (--INSERT-- пропадет), теперь надо написать :wq (w - write, q - quit, эти три символа должны отобращзиться там же, где было --INSERT--) и нажать Enter. Поздравляю, вы выбрались из тюрьмы! (:w - сохраняет файл, но не выходит из редактора; :q - выходит из файла, если он не изменился с последнего сохранения; :q! - отменить изменения после последнего сохранения;` [http://vim.wikia.com/wiki/Undo_and_Redo](http://vim.wikia.com/wiki/Undo_and_Redo/) `)` 92 | 93 | ![](https://i.imgflip.com/1pw00c.jpg) 94 | 95 | Vim – сложный, но предалагается по умолчанию (а на MacOS и Linux выбрать иное не дают), да и на компьютерах на Старой Басманной он используется. 96 | -------------------------------------------------------------------------------- /Lessons/Markdown и git/deadline.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ancatmara/learnpython2018/eec59d8a9d05ca80783d39963189cbd80ac661f3/Lessons/Markdown и git/deadline.jpg -------------------------------------------------------------------------------- /Lessons/Telegram-боты/bot_example/bot.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import telebot 3 | import conf 4 | import random 5 | import shelve 6 | from telebot import types 7 | 8 | bot = telebot.TeleBot(conf.TOKEN, threaded=False) 9 | 10 | with open('reviews.csv', 'r', encoding='utf-8') as f: 11 | reviews = {} 12 | for line in f: 13 | num, text = line.strip().split('\t') 14 | reviews[num] = text 15 | review_keys = list(reviews.keys()) 16 | 17 | keyboard = types.ReplyKeyboardMarkup(row_width=3) 18 | btn1 = types.KeyboardButton('+') 19 | btn2 = types.KeyboardButton('-') 20 | btn3 = types.KeyboardButton('=') 21 | keyboard.add(btn1, btn2, btn3) 22 | 23 | shelve_name = 'shelve.db' # Файл с хранилищем 24 | 25 | 26 | def set_user_review(chat_id, review): 27 | """ 28 | Записываем юзера в игроки и запоминаем, что он должен ответить. 29 | :param chat_id: id юзера 30 | :param estimated_answer: правильный ответ (из БД) 31 | """ 32 | with shelve.open(shelve_name) as storage: 33 | storage[str(chat_id)] = review 34 | 35 | 36 | def finish_user_review(chat_id): 37 | """ 38 | Заканчиваем игру текущего пользователя и удаляем правильный ответ из хранилища 39 | :param chat_id: id юзера 40 | """ 41 | with shelve.open(shelve_name) as storage: 42 | del storage[str(chat_id)] 43 | 44 | 45 | def get_user_review(chat_id): 46 | """ 47 | Получаем правильный ответ для текущего юзера. 48 | В случае, если человек просто ввёл какие-то символы, не начав игру, возвращаем None 49 | :param chat_id: id юзера 50 | :return: (str) Правильный ответ / None 51 | """ 52 | with shelve.open(shelve_name) as storage: 53 | try: 54 | review = storage[str(chat_id)] 55 | return review 56 | # Если человек не играет, ничего не возвращаем 57 | except KeyError: 58 | return None 59 | 60 | 61 | # этот обработчик запускает функцию send_welcome, когда пользователь отправляет команды /start или /help 62 | @bot.message_handler(commands=['help']) 63 | def send_welcome(message): 64 | bot.send_message(message.chat.id, 65 | "Здравствуйте! Это бот для разметки отзывов на кинофильмы.\n Положительные отзывы отмечаются плюсом +, отрицательные минусом -, а нейтральные знаком равно =.") 66 | 67 | 68 | @bot.message_handler(commands=['start']) 69 | def send_first_review(message): 70 | review_num = random.choice(review_keys) 71 | bot.send_message(message.chat.id, reviews[review_num], reply_markup=keyboard) 72 | set_user_review(message.chat.id, review_num) 73 | 74 | 75 | @bot.message_handler(regexp='[-+=]') # этот обработчик реагирует на символы разметки 76 | def get_answer(message): 77 | review_num = get_user_review(message.chat.id) 78 | if review_num: 79 | with open('results.csv', 'a', encoding='utf-8') as results: 80 | results.write(review_num + '\t' + message.text + '\n') 81 | review_num = random.choice(review_keys) 82 | bot.send_message(message.chat.id, reviews[review_num], reply_markup=keyboard) 83 | set_user_review(message.chat.id, review_num) 84 | else: 85 | bot.send_message(message.chat.id, 'Вы не разметили отзыв.') 86 | 87 | 88 | if __name__ == '__main__': 89 | bot.polling(none_stop=True) -------------------------------------------------------------------------------- /Lessons/Telegram-боты/bot_example/results.csv: -------------------------------------------------------------------------------- 1 | 5 + 2 | 3 = 3 | 4 - 4 | 5 + 5 | 10 - 6 | 4 - 7 | 1 - 8 | 3 - 9 | 5 + 10 | 4 - 11 | 8 = 12 | 8 = 13 | 3 - 14 | 9 + 15 | 9 + 16 | 4 - 17 | 8 + 18 | 7 = 19 | 3 - 20 | 7 = 21 | 3 = 22 | 4 - 23 | 5 + 24 | 10 - 25 | 8 + 26 | 2 + 27 | 4 - 28 | 9 + 29 | 7 = 30 | 2 + 31 | 4 - 32 | 5 + 33 | 9 + 34 | 4 - 35 | 4 - 36 | 7 - 37 | 2 + 38 | 6 + 39 | 8 + 40 | 3 = 41 | 7 + 42 | 10 - 43 | 4 - 44 | -------------------------------------------------------------------------------- /Lessons/Telegram-боты/bot_example/reviews.csv: -------------------------------------------------------------------------------- 1 | 1 Скучно и примитивно... 2 | 2 Зря так пугают !Мне мультик был мил и даже приятен. Для двд дома сойдёт!Есть фильмы попустее ))... 3 | 3 В детстве была фанатом серии книг Волкова о девочке Элли. Ожидала чего-то ближе к тексту. Поэтому и разочаровалась, наверное, в "современной" версии. Обычный , ничем не примечательный детский мульт, коих штампуется множество ежедневно.... 4 | 4 Плохо... 5 | 5 Супер! Мне показалось что он даже лучше первой части, сами съемки широкоформатные просто как в жизни , 3D эффект тоже хорошо сделан правда в динамических сценах не до него , юмор простой , фильм смотрится легко и не жаль ни времени ни денег, буду рекомендовать всем друзьям. Вот почему его не реклами... 6 | 6 Отличный фильм, сильнее первой части. Юмор, экшн, игра актеров - все на высшем уровне.... 7 | 7 Да уж, такого трешака от Марвел я еще не видел... В целом, конечно, графика космическая (в прямом и переносном смысле), бабла на нее не пожалели, да и технологии видно шагают вперед, все уже как настоящее. Плюс в фильме неплохое 3д. Но.. что это было??? Весь фильм они друг с другом рубятся, юморят, ... 8 | 8 Нормуль. Своеобразная трактовка легенды. Запомнился побег в лондиниуме. Музыка норм. Спец. Эффекты супер. Юмор присутствует.... 9 | 9 Здравствуйте!Фильм "Дом летающих кинжалов " понравился. Несравненная актриса Чжан Цзыи, чьи роли замечательные.Спасибо.Порадовали.... 10 | 10 не тратте своё время... -------------------------------------------------------------------------------- /Lessons/Telegram-боты/reviews.csv: -------------------------------------------------------------------------------- 1 | 1 Скучно и примитивно... 2 | 2 Зря так пугают !Мне мультик был мил и даже приятен. Для двд дома сойдёт!Есть фильмы попустее ))... 3 | 3 В детстве была фанатом серии книг Волкова о девочке Элли. Ожидала чего-то ближе к тексту. Поэтому и разочаровалась, наверное, в "современной" версии. Обычный , ничем не примечательный детский мульт, коих штампуется множество ежедневно.... 4 | 4 Плохо... 5 | 5 Супер! Мне показалось что он даже лучше первой части, сами съемки широкоформатные просто как в жизни , 3D эффект тоже хорошо сделан правда в динамических сценах не до него , юмор простой , фильм смотрится легко и не жаль ни времени ни денег, буду рекомендовать всем друзьям. Вот почему его не реклами... 6 | 6 Отличный фильм, сильнее первой части. Юмор, экшн, игра актеров - все на высшем уровне.... 7 | 7 Да уж, такого трешака от Марвел я еще не видел... В целом, конечно, графика космическая (в прямом и переносном смысле), бабла на нее не пожалели, да и технологии видно шагают вперед, все уже как настоящее. Плюс в фильме неплохое 3д. Но.. что это было??? Весь фильм они друг с другом рубятся, юморят, ... 8 | 8 Нормуль. Своеобразная трактовка легенды. Запомнился побег в лондиниуме. Музыка норм. Спец. Эффекты супер. Юмор присутствует.... 9 | 9 Здравствуйте!Фильм "Дом летающих кинжалов " понравился. Несравненная актриса Чжан Цзыи, чьи роли замечательные.Спасибо.Порадовали.... 10 | 10 не тратте своё время... -------------------------------------------------------------------------------- /Lessons/VK API/comment.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ancatmara/learnpython2018/eec59d8a9d05ca80783d39963189cbd80ac661f3/Lessons/VK API/comment.jpg -------------------------------------------------------------------------------- /Lessons/VK API/post_cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ancatmara/learnpython2018/eec59d8a9d05ca80783d39963189cbd80ac661f3/Lessons/VK API/post_cloud.png -------------------------------------------------------------------------------- /Lessons/Базы данных/12. Базы данных.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## Базы данных\n", 8 | "\n", 9 | "**Реляционная база данных** - это набор взаимосвязанных таблиц, в которых хранятся различные данные. **Строка** таблицы (row) содержит данные об одном объекте (например, о студенте), а **столбцы** таблицы (columns) описывают различные характеристики этих объектов — атрибутов (например, имя, курс, специальность, номер группы). Каждый столбец описывает только одну характеристику объекта и имеет *строго определенный тип данных*. Все стоки (записи) имеют одни и те же поля, только в них отображаются различная информация в зависимости от объекта. Вот так:\n", 10 | "\n", 11 | "|ФИО (строка)| Специальность (строка)| Курс (число)|\n", 12 | "| ------------- |-------------:| -----:|\n", 13 | "|Петя Иванов| филология| 1|\n", 14 | "|Вася Петров| физика| 2|\n", 15 | "|Маша Сидорова| биология| 3|\n", 16 | "\n", 17 | "В реляционной базе данных каждая таблица должна иметь **первичный ключ** (primary key) — поле или комбинацию полей, которые единственным образом идентифицируют каждую строку таблицы. Если ключ состоит из нескольких полей, он называется составным. Ключ должен быть уникальным и однозначно определять запись. По значению ключа можно отыскать единственную запись. Ключи служат также для упорядочивания информации в БД. По умолчанию это по умолчанию создающееся пое Id с порядковой нумерацией.\n", 18 | "\n", 19 | "Таблицы реляционной БД должны отвечать требованиям нормализации отношений. Нормализация отношений — это формальный аппарат ограничений на формирование таблиц, который позволяет устранить дублирование, обеспечивает непротиворечивость хранимых в базе данных, уменьшает трудозатраты на ведение базы данных.\n", 20 | "\n", 21 | "*Реляционные таблицы могут быть связаны друг с другом*, следовательно, данные могут извлекаться одновременно из нескольких таблиц. Таблицы связываются между собой для того, чтобы в конечном счете уменьшить объем БД. Связь каждой пары таблиц обеспечивается при наличии в них одинаковых столбцов.\n", 22 | "\n", 23 | "Существуют следующие типы информационных связей:\n", 24 | "* один-к-одному (one-to-one)\n", 25 | "* один-ко-многим (one-to-many)\n", 26 | "* многие-ко-многим (many-to-many)\n", 27 | "\n", 28 | "Связь **один-к-одному** предполагает, что одному атрибуту первой таблицы соответствует только один атрибут второй таблицы и наоборот. Связь **один-ко-многим** - это когда одному атрибуту первой таблицы соответствует несколько атрибутов второй таблицы. Связь **многие-ко-многим** - это когда одному атрибуту первой таблицы соответствует несколько атрибутов второй таблицы и наоборот. \n", 29 | "\n", 30 | "Для работы с БД используются специальные программы - они называются **Системами управления базами данных**, или **СУБД** (англ. *Database Management System, DBMS*). Существует множество СУБД, вот некоторые из них:\n", 31 | "\n", 32 | "* SQLite\n", 33 | "* MySQL\n", 34 | "* PostgreSQL\n", 35 | "* MongoDB\n", 36 | "* ...\n", 37 | "\n", 38 | "## SQL\n", 39 | "\n", 40 | "В названии нескольких СУБД встретилось сочетание SQL. Что это такое?\n", 41 | "\n", 42 | "**SQL** *(Structured Query Language)* - это особый язык для управления данными в БД. С помощью него можно добавлять, удалять, изменять и выбирать данные в таблицах. **Любое** обращение к базе данных называется **запросом**.\n", 43 | "\n", 44 | "SQL - очень простой язык. Нам потребуется лишь несколько команд для операций с данными (CREATE, DELETE, DROP, SELECT, INSERT, UPDATE) и команд-ограничителей для создания более точных запросов (WHERE, IN, AND, OR, NOT, BETWEEN, LIKE, LIMIT, OFFSET). Стоит обратить внимание, что порядок слов в запросе фиксирован: сначала идет \"что\", затем \"где\" и, наконец, \"с каким условием\".\n", 45 | "\n", 46 | "Для тренировки мы будем использовать интерактивный тьюториал SQLBolt.\n", 47 | "\n", 48 | "SELECT упражнения\n", 49 | "\n", 50 | "* https://sqlbolt.com/lesson/select_queries_introduction - основы (уроки 1-5, 8)\n", 51 | "* https://sqlbolt.com/lesson/select_queries_with_joins - выбор данных из нескольких таблиц (уроки 6-7)\n", 52 | "* https://sqlbolt.com/lesson/select_queries_with_expressions - работа с математическими выражениями\n", 53 | "\n", 54 | "\n", 55 | "DML упражнения\n", 56 | "\n", 57 | "* https://sqlbolt.com/lesson/inserting_rows\n", 58 | "* https://sqlbolt.com/lesson/updating_rows\n", 59 | "* https://sqlbolt.com/lesson/deleting_rows\n", 60 | "\n", 61 | "Создание и удаление таблиц (там же описаны типы данных)\n", 62 | "\n", 63 | "* https://sqlbolt.com/lesson/creating_tables (уроки 16-18)\n", 64 | "\n", 65 | "\n", 66 | "## Программы для работы с базами данных\n", 67 | "\n", 68 | "База данных -- это не текстовый формат, так что просто открыть его в блокноте и посмотреть, что внутри, не получится. Для этого существуют специальные программы.\n", 69 | "\n", 70 | "* [MySQL](https://www.mysql.com/)\n", 71 | "* [PostgreSQL](https://www.postgresql.org/)\n", 72 | "* [MongoDB](https://www.mongodb.com/)\n", 73 | "* [Firebird](https://firebirdsql.org/)\n", 74 | "\n", 75 | "[Вот тут](https://blog.capterra.com/free-database-software/) есть неплохое описание плюсов и минусов всего вышеперечисленного. \n", 76 | "\n", 77 | "\n", 78 | "## Базы данных и Python\n", 79 | "\n", 80 | "Питон позволяет работать с различными СУБД, но проще всего использовать встроенную библиотеку [SQLite](https://docs.python.org/3.5/library/sqlite3.html). Важно также запомнить, что файлы баз данных имеют расширение `.db`." 81 | ] 82 | }, 83 | { 84 | "cell_type": "code", 85 | "execution_count": 31, 86 | "metadata": {}, 87 | "outputs": [], 88 | "source": [ 89 | "import sqlite3\n", 90 | "\n", 91 | "# подключаемся к базе данных\n", 92 | "conn = sqlite3.connect('example.db')\n", 93 | "\n", 94 | "# создаем объект \"курсор\", которому будем передавать запросы\n", 95 | "c = conn.cursor()\n", 96 | "\n", 97 | "# создаем таблицу\n", 98 | "c.execute(\"CREATE TABLE IF NOT EXISTS students(name text, major text, year integer)\")\n", 99 | "\n", 100 | "# вставляем строку\n", 101 | "c.execute(\"INSERT INTO students VALUES ('Петя Иванов','филология',1), ('Маша Петрова','история',4)\")\n", 102 | "\n", 103 | "# сохраняем изменения\n", 104 | "conn.commit()\n", 105 | "\n", 106 | "# отключаемся от БД\n", 107 | "#conn.close()" 108 | ] 109 | }, 110 | { 111 | "cell_type": "markdown", 112 | "metadata": {}, 113 | "source": [ 114 | "**Важная вещь №1**: после подключения к БД нужно обязательно инициализировать курсор, иначе вы не сможете делать к ней запросы!\n", 115 | "\n", 116 | "**Важная вещь №2**: если вы что-то изменили, нужно обязательно закоммитить изменения, иначе они не сохранятся в файле БД!\n", 117 | "\n", 118 | "И немного о безопасности: при создании запроса нельзя использовать конкатенацию строк и форматирование строк, как в питоне. Это сделает ваше приложение уязвимым для SQL-инъекций - особых хакерских атак, которые заключаются в подставлении в запрос нежелательных комманд - например, DROP TABLE. Поподробнее об этом можно почитать [вот здесь](https://habrahabr.ru/post/148151/).\n", 119 | "\n", 120 | "![](https://imgs.xkcd.com/comics/exploits_of_a_mom.png)" 121 | ] 122 | }, 123 | { 124 | "cell_type": "code", 125 | "execution_count": 18, 126 | "metadata": {}, 127 | "outputs": [ 128 | { 129 | "name": "stdout", 130 | "output_type": "stream", 131 | "text": [ 132 | "('Петя Иванов', 'филология', 1)\n" 133 | ] 134 | } 135 | ], 136 | "source": [ 137 | "# Так нельзя!\n", 138 | "name = 'Петя'\n", 139 | "c.execute(\"SELECT * FROM students WHERE name = '%s'\" % name)\n", 140 | "\n", 141 | "# Вот как надо\n", 142 | "x = ('Петя Иванов',)\n", 143 | "c.execute('SELECT * FROM students WHERE name=?', x)\n", 144 | "print(c.fetchone())" 145 | ] 146 | }, 147 | { 148 | "cell_type": "code", 149 | "execution_count": 53, 150 | "metadata": {}, 151 | "outputs": [ 152 | { 153 | "name": "stdout", 154 | "output_type": "stream", 155 | "text": [ 156 | "('a', 1234.56, 4567.8)\n", 157 | "('u', 1111.1, 3333.3)\n", 158 | "('a', 1234.56, 4567.8)\n", 159 | "('u', 1111.1, 3333.3)\n" 160 | ] 161 | } 162 | ], 163 | "source": [ 164 | "# Если результатом запроса является несколько строк, можно по ним итерировать\n", 165 | "\n", 166 | "for row in c.execute('SELECT * FROM students ORDER BY year'):\n", 167 | " print(row)" 168 | ] 169 | }, 170 | { 171 | "cell_type": "code", 172 | "execution_count": 32, 173 | "metadata": {}, 174 | "outputs": [], 175 | "source": [ 176 | "# как подставить несколько переменных в sql-запрос\n", 177 | "\n", 178 | "x = 'Вася Пупкин'\n", 179 | "y = 'математика'\n", 180 | "z = 3\n", 181 | "\n", 182 | "c.execute('INSERT INTO students VALUES (?, ?, ?)', (x, y, z))\n", 183 | "conn.commit()" 184 | ] 185 | }, 186 | { 187 | "cell_type": "markdown", 188 | "metadata": {}, 189 | "source": [ 190 | "#### Форматирование строк\n", 191 | "\n", 192 | "Если нужно подставить переменные в качестве названия таблицы или колонок, то придется использовать форматирование строк." 193 | ] 194 | }, 195 | { 196 | "cell_type": "code", 197 | "execution_count": 48, 198 | "metadata": {}, 199 | "outputs": [ 200 | { 201 | "data": { 202 | "text/plain": [ 203 | "" 204 | ] 205 | }, 206 | "execution_count": 48, 207 | "metadata": {}, 208 | "output_type": "execute_result" 209 | } 210 | ], 211 | "source": [ 212 | "params = ['vowel', 'f1', 'f2']\n", 213 | "c.execute('CREATE TABLE vowels({}, {}, {})'.format(params[0], params[1], params[2]))" 214 | ] 215 | }, 216 | { 217 | "cell_type": "code", 218 | "execution_count": 51, 219 | "metadata": {}, 220 | "outputs": [], 221 | "source": [ 222 | "# как написать длинный запрос посимпатичнее\n", 223 | "c.execute('''\n", 224 | "INSERT INTO vowels \n", 225 | "VALUES \n", 226 | "('a', 1234.56, 4567.8), \n", 227 | "('u', 1111.1, 3333.3)'''\n", 228 | ")" 229 | ] 230 | }, 231 | { 232 | "cell_type": "code", 233 | "execution_count": 54, 234 | "metadata": {}, 235 | "outputs": [ 236 | { 237 | "name": "stdout", 238 | "output_type": "stream", 239 | "text": [ 240 | "('a', 1234.56, 4567.8)\n", 241 | "('u', 1111.1, 3333.3)\n", 242 | "('a', 1234.56, 4567.8)\n", 243 | "('u', 1111.1, 3333.3)\n" 244 | ] 245 | } 246 | ], 247 | "source": [ 248 | "for row in c.execute('SELECT * FROM vowels'):\n", 249 | " print(row)" 250 | ] 251 | }, 252 | { 253 | "cell_type": "markdown", 254 | "metadata": {}, 255 | "source": [ 256 | "#### Функции курсора\n", 257 | "\n", 258 | "* **fetchone()** -- возвращает следующий элемент из результата запроса (т.е. одну строку из бд). Результат -- кортеж, где элементом является значение каждой из колонок или None\n", 259 | "* **fetchall()** -- возвращает все результаты запроса в виде списка\n", 260 | "* **fetchmany()** -- взвращает заданное количество строк из результатов запроса" 261 | ] 262 | }, 263 | { 264 | "cell_type": "code", 265 | "execution_count": 35, 266 | "metadata": {}, 267 | "outputs": [ 268 | { 269 | "name": "stdout", 270 | "output_type": "stream", 271 | "text": [ 272 | "('Петя Иванов', 'филология', 1)\n", 273 | "('Вася Пупкин', 'математика', 3)\n", 274 | "('Маша Петрова', 'история', 4)\n" 275 | ] 276 | } 277 | ], 278 | "source": [ 279 | "# извлекаем строки по одной\n", 280 | "# обратите внимание, что после каждого вызова fetchone возвращает следующую строку!\n", 281 | "c.execute('SELECT * FROM students ORDER BY year')\n", 282 | "print(c.fetchone())\n", 283 | "print(c.fetchone())\n", 284 | "print(c.fetchone())" 285 | ] 286 | }, 287 | { 288 | "cell_type": "code", 289 | "execution_count": 36, 290 | "metadata": {}, 291 | "outputs": [ 292 | { 293 | "name": "stdout", 294 | "output_type": "stream", 295 | "text": [ 296 | "[('Петя Иванов', 'филология', 1), ('Вася Пупкин', 'математика', 3)]\n" 297 | ] 298 | } 299 | ], 300 | "source": [ 301 | "# извлекаем две строки\n", 302 | "c.execute('SELECT * FROM students ORDER BY year')\n", 303 | "print(c.fetchmany(2))" 304 | ] 305 | }, 306 | { 307 | "cell_type": "code", 308 | "execution_count": 37, 309 | "metadata": {}, 310 | "outputs": [ 311 | { 312 | "name": "stdout", 313 | "output_type": "stream", 314 | "text": [ 315 | "[('Петя Иванов', 'филология', 1), ('Вася Пупкин', 'математика', 3), ('Маша Петрова', 'история', 4)]\n" 316 | ] 317 | } 318 | ], 319 | "source": [ 320 | "# извлекаем все строки\n", 321 | "c.execute('SELECT * FROM students ORDER BY year')\n", 322 | "print(c.fetchall())" 323 | ] 324 | }, 325 | { 326 | "cell_type": "markdown", 327 | "metadata": {}, 328 | "source": [ 329 | "### Задание\n", 330 | "\n", 331 | "1. Помните [таблицу с нанайскими гласными](https://github.com/ancatmara/learnpython2018/blob/master/Lessons/11/nanai-vowels.csv)? Давайте сделаем из не базу данных с помощью `sqlite3`.\n", 332 | "2. Теперь более реальная задача: возьмите за основу код сайта-анкеты из последнего домашнего задания и перепишите обработку данных. Ответы пользователя должны сохраняться не в сsv-таблицу, в базу данных и извлекаться из нее для отображения." 333 | ] 334 | } 335 | ], 336 | "metadata": { 337 | "kernelspec": { 338 | "display_name": "Python 3", 339 | "language": "python", 340 | "name": "python3" 341 | }, 342 | "language_info": { 343 | "codemirror_mode": { 344 | "name": "ipython", 345 | "version": 3 346 | }, 347 | "file_extension": ".py", 348 | "mimetype": "text/x-python", 349 | "name": "python", 350 | "nbconvert_exporter": "python", 351 | "pygments_lexer": "ipython3", 352 | "version": "3.6.7" 353 | } 354 | }, 355 | "nbformat": 4, 356 | "nbformat_minor": 1 357 | } 358 | -------------------------------------------------------------------------------- /Lessons/Веб-запросы и формы/8. Запросы и формы.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Запросы и формы\n", 8 | "\n", 9 | "## HTTP-запросы\n", 10 | "\n", 11 | "Вспомним первый семинар:\n", 12 | "\n", 13 | "> На самом деле, когда мы хотим открыть какую-то страницу в интернете, наш браузер отправляет на сервер запрос (\"Привет, сервер! я хочу код страницы по вот такому адресу!\"), а сервер затем отправляет ответ (\"Привет! Вот код страницы: ...\"). \n", 14 | "\n", 15 | "Такие запросы мы обычно отправляем по протоколу HTTP (протокол - просто набор правил отправки запроса). При отправке запроса нужно сказать серверу, как ему стоит обаботать наш запрос -- каким __методом__. Методы бывают разные, а сейчас мы разберем два основных: GET и POST.\n", 16 | "\n", 17 | "**GET**\n", 18 | "\n", 19 | "Этот метод является одним из самых распространенных и предназначен для получения требуемой информации и передачи данных в адресной строке. Пары «имя=значение» присоединяются в этом случае к адресу после вопросительного знака и разделяются между собой амперсандом (символ &). Удобство использования метода get заключается в том, что адрес со всеми параметрами можно использовать неоднократно, сохранив его, например, в закладки браузера, а также менять значения параметров прямо в адресной строке.\n", 20 | "\n", 21 | "**POST**\n", 22 | "\n", 23 | "Метод post посылает на сервер данные в запросе браузера. Это позволяет отправлять большее количество данных, чем доступно методу get, плюс эти данные можно скрывать. Большие объемы данных используются в форумах, почтовых службах, заполнении базы данных, при пересылке файлов и др.\n", 24 | "\n", 25 | "\n", 26 | "## HTML-формы\n", 27 | "\n", 28 | "В коде HTML-страницы можно написать веб-формы, которые генерируют запросы к какому-то ресурсу и отправляют их, используя какой-то метод.\n", 29 | "\n", 30 | "Чтобы создать форму используется тэг `
`. У тэга `` есть атрибуты:\n", 31 | "\n", 32 | "* `action` - кому (какой программе) мы отправляем запрос\n", 33 | "* `method` - какой метод мы используем - GET|POST\n", 34 | "\n", 35 | "Для того, чтобы пользователь мог ввести в форму какие-то данные, используется тэг ``. У тэга `` есть атрибуты:\n", 36 | "\n", 37 | "* `name` - имя поля,\n", 38 | "* `value` - значение поля,\n", 39 | "* `type` - какой тип ввода мы используем. Тип может быть такой:\n", 40 | " * `text` - короткое текстовое поле.\n", 41 | " * `textarea` - большое текстовое поле.\n", 42 | " * `checkbox` - выбор с чекбоксами, которые можно отмечать галочками (можно все или несколько)\n", 43 | " * `radio` - выбор с радио-кнопками, из которых можно выбрать только одну.\n", 44 | " * `submit` - кнопка для отправки формы на сервер.\n", 45 | "\n", 46 | "\n", 47 | "## Примеры\n", 48 | "\n", 49 | "__Вот минимальный пример:__\n", 50 | "\n", 51 | " \n", 52 | " Как вас зовут? \n", 53 | " \n", 54 | "
\n", 55 | " \n", 56 | "\n", 57 | "Когда форма отправляется на сервер, управление данными передается программе, заданной атрибутом `action` тега `
`. Предварительно браузер подготавливает информацию в виде пары «имя=значение», где имя определяется атрибутом `name` тега ``, а значение введено пользователем или установлено в поле формы по умолчанию. Если для отправки данных используется метод GET, то адресная строка будет выглядеть примерно так:\n", 58 | "\n", 59 | "https://github.com/elmiram/2016learnpython/6%20Seminar.ipynb?username=Petya\n", 60 | "\n", 61 | "\n", 62 | "__Вот пример c радио-кнопками:__\n", 63 | "\n", 64 | " \n", 65 | " \n", 66 | " \n", 67 | " Кого вы больше любите?\n", 68 | " \n", 69 | " \n", 70 | "\n", 71 | " \n", 72 | "

Как вас зовут?

\n", 73 | "

Кого вы больше любите?

\n", 74 | " Котиков
\n", 75 | " Собачек
\n", 76 | " Птичек
\n", 77 | " Слоников
\n", 78 | "

\n", 79 | "
\n", 80 | "\n", 81 | " \n", 82 | " \n", 83 | "
\n" 84 | ] 85 | }, 86 | { 87 | "cell_type": "markdown", 88 | "metadata": {}, 89 | "source": [ 90 | " \n", 91 | "__Вот пример c чекбоксами:__\n", 92 | "\n", 93 | " \n", 94 | " \n", 95 | " \n", 96 | " Чем вы любите заниматься\n", 97 | " \n", 98 | " \n", 99 | "\n", 100 | "
\n", 101 | "

Как вас зовут?

\n", 102 | "

Сколько вам лет?

\n", 103 | "

Чем вы любите заниматься?

\n", 104 | " Спать
\n", 105 | " Читать книжки
\n", 106 | " Программировать
\n", 107 | " Гамать
\n", 108 | " Писать научные статьи
\n", 109 | " Придумывать лингвистические эксперименты
\n", 110 | " Кушать вкусняшки
\n", 111 | "

\n", 112 | "
\n", 113 | " \n", 114 | " \n", 115 | " \n", 116 | "Поподробнее про формы можно почитать [тут](https://www.w3schools.com/html/html_forms.asp). Ну и вообще на этом сайте есть тьюториалы по HTML, CSS и Bootstrap на все случаи жизни. :)" 117 | ] 118 | }, 119 | { 120 | "cell_type": "markdown", 121 | "metadata": {}, 122 | "source": [ 123 | "## Percent encoding\n", 124 | "\n", 125 | "Мы уже говорили об особом способе кодирования символов в ссылках, когда обсуждали проект. Напомню, он называется percent encoding (потому что многие символы кодируются с использованием знака %), или URL encoding и подробно описан [вот тут](https://en.wikipedia.org/wiki/Percent-encoding). А [вот тут](https://www.w3schools.com/tags/ref_urlencode.asp) лежит таблица кодировки ASCII-символов. Есть специальные сайты, которые позволяют кодировать/декодировать текст с помощью percent encoding -- например, вот этот: https://www.url-encode-decode.com/ " 126 | ] 127 | }, 128 | { 129 | "cell_type": "markdown", 130 | "metadata": {}, 131 | "source": [ 132 | "## Задания\n", 133 | "\n", 134 | "Посмотреть, как работает поиск в Google'e, Яндексе и Яндекс.Картах. Написать веб-страницу, с помощью которой можно искать слово там, там или там. Подсказка: сначала надо погуглить, что нужно прописать в \"action\", чтобы сделать редирект из формы на какую-то внешнюю веб-страницу.\n", 135 | "\n", 136 | "**Бонусное задание**\n", 137 | "\n", 138 | "Посмотреть, какие запросы отправляет какой-нибудь поисковик, когда ищет подсказки к введённым пользователем буквам, какие ответы он получает (там будет json), и написать программу, которая сама будет выдавать такие подсказки." 139 | ] 140 | }, 141 | { 142 | "cell_type": "markdown", 143 | "metadata": {}, 144 | "source": [ 145 | "### Подсказка\n", 146 | "\n", 147 | "Самая простая форма, из которой напрямую делается редирект на какой-нибудь сайт -- например, поисковик -- будет выглядеть вот так. В `action` пишем адрес сайта, а в кажестве имени тега `` указываем то, как называется необходимый get-параметр. В Google'e параметр, через который передается поисковый запрос, называется `q`, а в Яндексе и Яндекс.Картах -- `text`." 148 | ] 149 | }, 150 | { 151 | "cell_type": "markdown", 152 | "metadata": {}, 153 | "source": [ 154 | " \n", 155 | " \n", 156 | " \n", 157 | " Что ищем?\n", 158 | " \n", 159 | " \n", 160 | "
\n", 161 | "

Введите поисковый запрос

\n", 162 | " \n", 163 | "

\n", 164 | "
\n", 165 | " \n", 166 | " \n" 167 | ] 168 | } 169 | ], 170 | "metadata": { 171 | "kernelspec": { 172 | "display_name": "Python 3", 173 | "language": "python", 174 | "name": "python3" 175 | }, 176 | "language_info": { 177 | "codemirror_mode": { 178 | "name": "ipython", 179 | "version": 3 180 | }, 181 | "file_extension": ".py", 182 | "mimetype": "text/x-python", 183 | "name": "python", 184 | "nbconvert_exporter": "python", 185 | "pygments_lexer": "ipython3", 186 | "version": "3.6.6" 187 | } 188 | }, 189 | "nbformat": 4, 190 | "nbformat_minor": 1 191 | } 192 | -------------------------------------------------------------------------------- /Lessons/Интерактивные визуализации/Интерактивные графики и карты в вебе.md: -------------------------------------------------------------------------------- 1 | # Интерактивные графики и карты в вебе, Google Charts, D3, geojson 2 | 3 | ## Введение 4 | 5 | Мы уже умеем строить статические графики с помощью matplotlib. Но если мы делаем веб-сервис, гораздо удобнее было бы представлять на сайте интерактивные графики, которые отзывались бы на жесты пользователя, то есть чтобы при наведении мыши появлялся бы какой-то дополнительный текст, линии подсвечивались, части графиков можно было бы перетаскивать. Со статическими картинками в форматах .png или .jpg это невозможно. 6 | 7 | Интерактивными элементы на веб-страницы делает специальный язык -- JavaScript, который мы в нашем курсе программирования не изучаем (потому что он не так хорошо умеет обрабатывать языковые массивы, как Python), но если мы хотим сделать веб-страницу красивой и функциональной, без JavaScript совсем нам не обойтись. 8 | 9 | Делать интерактивный график на чистом JavaScript (особенно без предварительного изучения языка) довольно сложно. Но у нас в руках есть инструменты, которые оказывают в этом существенную помощь -- это специальные подключаемые библиотеки для работы с графиками, прежде всего, Google Chart и d3. 10 | 11 | ## Google Chart 12 | 13 | [Здесь](https://developers.google.com/chart/interactive/docs/gallery) можно посмотреть на то, какие типы графиков можно встроить в интернет-страницу, используя Google Chart. [На самом деле таких типов гораздо больше](https://developers.google.com/chart/interactive/docs/more_charts). 14 | 15 | График встраивается в HTML довольно просто. Нужно всего лишь: 16 | 17 | 1. внутри тега `` поместить код подгрузки библиотеки: `` 18 | 2. внутри тега `` в нужном месте поместить код того слоя, в котором будет отображаться график. Размеры слоя можно регулировать: 19 | `
` 20 | 3. выдать библиотеке данные, которые мы хотим отобразить на графике. Сделать это можно разными способами. Самое простое -- это зашить данные в коде JavaScript. Данные в нём представляется в очень похожем на питоновский синтаксисе: 21 | 22 | ``` 23 | [ 24 | ['Year', 'Sales', 'Expenses'], 25 | ['2004', 1000, 400], 26 | ['2005', 1170, 460], 27 | ['2006', 660, 1120], 28 | ['2007', 1030, 540] 29 | ] 30 | ``` 31 | Знающий питон легко узнаёт в этом коде 5 массивов, вложенных в ещё один массив. 32 | 33 | Если поместить эту структуру внутрь JavaScript-функции, даже не очень разбираясь в принципах её действия, можно получить желаемый результат: 34 | 35 | ``` 36 | function drawChart() { 37 | var data = google.visualization.arrayToDataTable([ 38 | ['Year', 'Sales', 'Expenses'], 39 | ['2004', 1000, 400], 40 | ['2005', 1170, 460], 41 | ['2006', 660, 1120], 42 | ['2007', 1030, 540] 43 | ]); 44 | ``` 45 | 46 | Получить из питона строку, которую можно было бы вставить внутрь JavaScript-кода, можно с помощью функции json.dumps() (вспомните, что и сам формат данных JSON появился благодаря языку JavaScript). 47 | 48 | ``` 49 | import json 50 | 51 | js_function = 'function drawChart() { var data = google.visualization.arrayToDataTable({{data_to_display}});' 52 | 53 | data = [['Year', 'Sales', 'Expenses'], ['2004', 1000, 400], ['2005', 1170, 460], ['2006', 660, 1120], ['2007', 1030, 540]] 54 | 55 | data_for_visualization = json.dumps(data) 56 | js_function = js_function.replace('{{data_to_display}}', data_for_visualization) 57 | 58 | ``` 59 | ## d3 60 | 61 | Другой способ создавать разнообразные интерактивные графики на веб-странице -- это библиотека d3.js. Галерея примеров того, что можно сделать с её помощью, [лежит здесь](https://github.com/d3/d3/wiki/Gallery). Как видно, возможности здесь практически безграничны, нужно только выбрать подходящий способ визуализации. 62 | 63 | [Здесь можно](https://www.jasondavies.com/wordcloud/) заранее сделать статическую картинку облака слов в svg (удобный для веба формат) и вставить её на ваш сайт. А [здесь](https://bl.ocks.org/mbostock/4062006) можно подсмотреть, как рисовать хордовую диаграмму, отражающую связи между группами объектов. 64 | 65 | Вообще-то d3 -- это очень мощный инструмент, с помощью которого можно создавать [свои достаточно сложные визуализации](https://github.com/d3/d3/blob/master/API.md), для этого просто нужно достаточно подробно [изучить устройство](https://github.com/d3/d3/wiki/Tutorials) библиотеки. Но если вам хватает уже существующих инструментов, можно воспользоваться ими в том же духе, как мы работали с Google Chart: взять готовый образец и подставить в него свои данные. 66 | 67 | ### Географические данные, GIS 68 | 69 | В d3 и Google Chart есть много способов отобразить географические данные и построить на них карту (интерактивную и отображаемую на интернет-странице). Более сложный (но в чём-то и более простой) и настраиваемый способ -- это использовать формат geojson. 70 | 71 | Для питона и этого формата есть [специальная библиотека](https://pypi.python.org/pypi/geojson), но она нужна в том случае, если работа с данными автоматизирована. Если же вы работаете с обозримым объёмом данных вручную, их можно сформировать на сайте [geojson.io](http://geojson.io/), он представляет собой простой визуальный редактор, в котором слева вы видите карту, а справа -- geojson. Когда вы отмечаете что-то слева, оно тут же автоматически появляется в этом самом формате справа. 72 | 73 | Например, мы можем поставить на карте какой-то маркер или нарисовать полигон, а щелчок по тому объекту, который мы добавили на карту, вызывает облачко с табличкой дополнительных признаков, которые можно прикрепить к маркеру. Например, в левой колонке таблички можно вписать слово `title`, а в той же строке справа название объекта ("метро Автозаводская" или что-то другое). Точно так же можно написать слева слово `description`, а справа что-то содержательное: "Лучшее место на свете!" 74 | 75 | Когда вы сделали таким образом свою карту в http://geojson.io/, нужно сохранить получившийся результат в виде файла с расширением .geojson 76 | Это можно сделать с помощью меню "Save" в левой верхней части экрана. Из предложенных вариантов нужно выбрать "GeoJSON". 77 | 78 | Если вы загрузите этот файл на github, то сайт по умолчанию будет не отображать содержимое файла, а сразу отрисовывать карту, как [вот тут](https://github.com/nevmenandr/DigitalHumanitiesMinorFeatures/blob/master/MoskowPetushkiWay.geojson). Правда, это работает только если geojson-файл не больше 10 мегабайт. Кроме того, такую карту можно вставить и на вашу страницу в Интернете, если в html-код вставить строку: 79 | 80 | ``` 81 | 82 | 83 | ``` 84 | 85 | Для примера выше эта строка будет выглядеть так: 86 | 87 | ``` 88 | 89 | ``` 90 | 91 | ## Задания 92 | 93 | 1. Нарисуйте с помощью Google Charts график, который мы рисовали с [matplotlib](https://github.com/ancatmara/learnpython2017/blob/master/%D0%A1%D0%B5%D0%BC%D0%B8%D0%BD%D0%B0%D1%80%D1%8B/13.%20Matplotlib.ipynb). 94 | 2. Нарисуйте карту, взяв данные из [WALS](http://wals.info/feature) 95 | -------------------------------------------------------------------------------- /Lessons/Краулеры и парсинг веб-документов/4a. Urllib.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Семинар 1. Выкачиваем Интернет.\n", 8 | "\n", 9 | "## Введение\n", 10 | "Современный Интернет предоставляет лингвистам большое количество языковых данных: электронные газеты и журналы, блоги, форумы, социальные сети и т.д. Например, можно найти в сети много-много текстов и собрать корпус, или найти все газетные статьи и блог-посты про какую-нибудь корпорацию и проанализировать тональность сообщений. Сейчас мы научимся заниматься выкачиванием страниц из интернета с помощью Python.\n", 11 | "\n", 12 | "Для скачивания HTML-страниц в питоне есть специальный модуль **urllib.request**. \n", 13 | "\n", 14 | "## Минимальный пример\n", 15 | "Допустим, мы хотим скачать главную страницу Хабрахабра. \n", 16 | "На самом деле, когда мы хотим открыть какую-то страницу в интернете, наш браузер отправляет на сервер запрос (\"Привет, сервер! я хочу код страницы по вот такому адресу!\"), а сервер затем отправляет ответ (\"Привет! Вот код страницы: ...\").\n", 17 | "Чтобы получить страницу через питон, нужно сформировать запрос на сервер так же, как это делает браузер:" 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": 1, 23 | "metadata": {}, 24 | "outputs": [], 25 | "source": [ 26 | "import urllib.request # импортируем модуль \n", 27 | "req = urllib.request.Request('https://habrahabr.ru/')\n", 28 | "with urllib.request.urlopen(req) as response:\n", 29 | " html = response.read().decode('utf-8')" 30 | ] 31 | }, 32 | { 33 | "cell_type": "markdown", 34 | "metadata": {}, 35 | "source": [ 36 | "В переменной **req** у нас как раз находится запрос.\n", 37 | "Функция **urlopen** получает ответ сервера и скачивает страницу по ссылке https://habrahabr.ru/ в переменную **response**. **response** ведет себя как файл: например мы можем прочитать его содержимое с помощью **.read()** в другую переменную. \n", 38 | "Вот так просто мы сохранили код страницы в переменной **html**. Убедимся, что в там лежит html-код:" 39 | ] 40 | }, 41 | { 42 | "cell_type": "code", 43 | "execution_count": 2, 44 | "metadata": {}, 45 | "outputs": [ 46 | { 47 | "name": "stdout", 48 | "output_type": "stream", 49 | "text": [ 50 | "\n", 51 | "\n", 52 | " \n", 53 | " \n", 54 | "\n", 55 | "Лучшие публикации за сутки / \n" 56 | ] 57 | } 58 | ], 59 | "source": [ 60 | "print(html[:210])" 61 | ] 62 | }, 63 | { 64 | "cell_type": "markdown", 65 | "metadata": {}, 66 | "source": [ 67 | "Иногда сайт блокирует запросы, если их посылает не настоящий браузер с пользователем, а какой-то бот (например, так делает Гугл или Википедия). Иногда сайты присылают разные версии страниц, разным браузерам. \n", 68 | "По этим причинам полезно бывает писать скрипт, который умеет притворяться то одним, то другим браузером.\n", 69 | "Когда мы пытаемся получить страницу с помощью **urllib**, наш код по умолчанию честно сообщает серверу, что он является программой на питоне. Он говорит что-то вроде \"Привет, я Python-urllib/3.5\". \n", 70 | "Но можно, например, представиться Мозиллой:" 71 | ] 72 | }, 73 | { 74 | "cell_type": "code", 75 | "execution_count": 3, 76 | "metadata": {}, 77 | "outputs": [], 78 | "source": [ 79 | "url = 'https://habrahabr.ru/' # адрес страницы, которую мы хотим скачать\n", 80 | "user_agent = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64)' # хотим притворяться браузером\n", 81 | "\n", 82 | "req = urllib.request.Request(url, headers={'User-Agent':user_agent}) \n", 83 | "# добавили в запрос информацию о том, что мы браузер Мозилла\n", 84 | "\n", 85 | "with urllib.request.urlopen(req) as response:\n", 86 | " html = response.read().decode('utf-8')" 87 | ] 88 | }, 89 | { 90 | "cell_type": "markdown", 91 | "metadata": {}, 92 | "source": [ 93 | "## Напоминание: как найти на странице что-нибудь\n", 94 | "Теперь предположим, что мы хотим выкачивать заголовки статей с главной страницы Хабрахабра. Код страницы у нас уже есть, но как из него что-то вытащить. Для начала нужно посмотреть в [исходник](view-source:https://habrahabr.ru/) и заметить, что заголовки хранятся в тэге **h2** с классом **post__title**. Заголовок выглядит примерно так:\n", 95 | "\n", 96 | "<h2 class=\"post__title\">\n", 97 | " <a href=\"https://habrahabr.ru/flows/admin/\" class=\"post__flow\" onclick=\"if (typeof ga === 'function') { ga('send', 'event', 'flow', 'feed page', 'Администрирование'); }\">Администрирование</a><span class=\"post__title-arrow\"> →</span>\n", 98 | " <a href=\"https://habrahabr.ru/company/okmeter/blog/309600/\" class=\"post__title_link\">Мониторинг сетевого стэка linux</a>\n", 99 | " </h2>\n", 100 | " \n", 101 | "А код у него такой:" 102 | ] 103 | }, 104 | { 105 | "cell_type": "code", 106 | "execution_count": 5, 107 | "metadata": {}, 108 | "outputs": [], 109 | "source": [ 110 | "<h2 class=\"post__title\">\n", 111 | " <a href=\"https://habrahabr.ru/flows/admin/\" class=\"post__flow\" onclick=\"if (typeof ga === 'function') { ga('send', 'event', 'flow', 'feed page', 'Администрирование'); }\">Администрирование</a><span class=\"post__title-arrow\"> →</span>\n", 112 | " <a href=\"https://habrahabr.ru/company/okmeter/blog/309600/\" class=\"post__title_link\">Мониторинг сетевого стэка linux</a>\n", 113 | " </h2>" 114 | ] 115 | }, 116 | { 117 | "cell_type": "markdown", 118 | "metadata": {}, 119 | "source": [ 120 | "Чтобы вытащить все такие заголовки, воспользуемся регулярным выражением." 121 | ] 122 | }, 123 | { 124 | "cell_type": "code", 125 | "execution_count": 7, 126 | "metadata": {}, 127 | "outputs": [], 128 | "source": [ 129 | "import re\n", 130 | "regPostTitle = re.compile('<h2 class=\"post__title\">.*?</h2>', flags= re.DOTALL)\n", 131 | "titles = regPostTitle.findall(html)" 132 | ] 133 | }, 134 | { 135 | "cell_type": "markdown", 136 | "metadata": {}, 137 | "source": [ 138 | "Посмотрим, сколько там заголовков. И взглянем, например, на первые три." 139 | ] 140 | }, 141 | { 142 | "cell_type": "code", 143 | "execution_count": 8, 144 | "metadata": {}, 145 | "outputs": [ 146 | { 147 | "name": "stdout", 148 | "output_type": "stream", 149 | "text": [ 150 | "18\n" 151 | ] 152 | } 153 | ], 154 | "source": [ 155 | "print(len(titles))" 156 | ] 157 | }, 158 | { 159 | "cell_type": "code", 160 | "execution_count": 9, 161 | "metadata": {}, 162 | "outputs": [ 163 | { 164 | "name": "stdout", 165 | "output_type": "stream", 166 | "text": [ 167 | "['<h2 class=\"post__title\">\\n <a href=\"https://habr.com/company/crossover/blog/424701/\" class=\"post__title_link\">Невыдуманные IT-истории о самозванцах и почему появились эти непонятные практики на собеседованиях</a>\\n </h2>', '<h2 class=\"post__title\">\\n <a href=\"https://habr.com/company/mosigra/blog/424675/\" class=\"post__title_link\">Что происходит в рознице</a>\\n </h2>', '<h2 class=\"post__title\">\\n <a href=\"https://habr.com/post/424767/\" class=\"post__title_link\">Делаем из Хабра торт. Снова</a>\\n </h2>']\n" 168 | ] 169 | } 170 | ], 171 | "source": [ 172 | "print(titles[:3])" 173 | ] 174 | }, 175 | { 176 | "cell_type": "markdown", 177 | "metadata": {}, 178 | "source": [ 179 | "Теперь давайте очистим заголовки от лишних переносов строк, лишних тэгов и распечатаем их подряд." 180 | ] 181 | }, 182 | { 183 | "cell_type": "code", 184 | "execution_count": 10, 185 | "metadata": {}, 186 | "outputs": [ 187 | { 188 | "name": "stdout", 189 | "output_type": "stream", 190 | "text": [ 191 | "Невыдуманные IT-истории о самозванцах и почему появились эти непонятные практики на собеседованиях\n", 192 | "Что происходит в рознице\n", 193 | "Делаем из Хабра торт. Снова\n", 194 | "Как поступить на PhD программу по машинному обучению\n", 195 | "Краткая история цифровой клавиатуры\n", 196 | "Frontend Conf — с заботой о пользователе\n", 197 | "Все люди не умеют писать код\n", 198 | "42-й протокол жизни, вселенной и всего такого: «напутственная речь»\n", 199 | "«У нас есть идеи для Maven 4 и даже Maven 5» — интервью с Robert Scholte, ключевым участником проекта Maven\n", 200 | "Деньги любят счёт: как машины сортируют купюры\n", 201 | "Использование Consul для масштабирования stateful-сервисов\n", 202 | "Топ-10 докладов Mobius 2018 Piter\n", 203 | "Антенна из пульверизатора: миниатюрность, гибкость и производительность\n", 204 | "Как расширять Kubernetes\n", 205 | "Горячая история техподдержки, или Почему AutoCAD удаляет прокси-объекты?\n", 206 | "Почему компилятор превратил мой цикл с условием в бесконечный?\n", 207 | "Дайджест событий для HR-специалистов в сфере IT на октябрь 2018\n", 208 | "ДНК. Механизмы хранения и обработки информации. Часть I\n" 209 | ] 210 | } 211 | ], 212 | "source": [ 213 | "new_titles = []\n", 214 | "regTag = re.compile('<.*?>', re.DOTALL)\n", 215 | "regSpace = re.compile('\\s{2,}', re.DOTALL)\n", 216 | "for t in titles:\n", 217 | " clean_t = regSpace.sub(\"\", t)\n", 218 | " clean_t = regTag.sub(\"\", clean_t)\n", 219 | " new_titles.append(clean_t)\n", 220 | "for t in new_titles:\n", 221 | " print(t)" 222 | ] 223 | }, 224 | { 225 | "cell_type": "markdown", 226 | "metadata": {}, 227 | "source": [ 228 | "Ну и осталось убрать некрасивые кусочки html, а именно заменить специальные html-последовательности nbsp и rarr на стрелочку, например." 229 | ] 230 | }, 231 | { 232 | "cell_type": "code", 233 | "execution_count": 11, 234 | "metadata": {}, 235 | "outputs": [ 236 | { 237 | "name": "stdout", 238 | "output_type": "stream", 239 | "text": [ 240 | "Невыдуманные IT-истории о самозванцах и почему появились эти непонятные практики на собеседованиях\n", 241 | "Что происходит в рознице\n", 242 | "Делаем из Хабра торт. Снова\n", 243 | "Как поступить на PhD программу по машинному обучению\n", 244 | "Краткая история цифровой клавиатуры\n", 245 | "Frontend Conf — с заботой о пользователе\n", 246 | "Все люди не умеют писать код\n", 247 | "42-й протокол жизни, вселенной и всего такого: «напутственная речь»\n", 248 | "«У нас есть идеи для Maven 4 и даже Maven 5» — интервью с Robert Scholte, ключевым участником проекта Maven\n", 249 | "Деньги любят счёт: как машины сортируют купюры\n", 250 | "Использование Consul для масштабирования stateful-сервисов\n", 251 | "Топ-10 докладов Mobius 2018 Piter\n", 252 | "Антенна из пульверизатора: миниатюрность, гибкость и производительность\n", 253 | "Как расширять Kubernetes\n", 254 | "Горячая история техподдержки, или Почему AutoCAD удаляет прокси-объекты?\n", 255 | "Почему компилятор превратил мой цикл с условием в бесконечный?\n", 256 | "Дайджест событий для HR-специалистов в сфере IT на октябрь 2018\n", 257 | "ДНК. Механизмы хранения и обработки информации. Часть I\n" 258 | ] 259 | } 260 | ], 261 | "source": [ 262 | "for t in new_titles:\n", 263 | " print(t.replace(\" →\", \" -> \"))" 264 | ] 265 | }, 266 | { 267 | "cell_type": "markdown", 268 | "metadata": {}, 269 | "source": [ 270 | "## Некоторые объяснения про регулярные выражения\n", 271 | "\n", 272 | "* Что такое `re.compile`? <br><br>\n", 273 | "Грубо говоря, `compile()` позволяет запомнить регулярное выражение и использовать его несколько раз. Суть в том, что перед тем как прогнать регулярку через строку, питон должен ее \"скомпилировать\" - превратить **строку** с регулярным выражением в специальный **объект**.<br>\n", 274 | "Строчка `re.search(..., ...)` сначала компилирует регулярное выражение, а потом выполняет поиск. Если нужно поискать что-то один раз, то такая строчка очень удобна. А если нужно поискать что-то много раз, то получится что одно и то же выражение мы компилируем много раз. А хочется один раз скомпилировать и потом много раз пользоваться. Поэтому пишут так:" 275 | ] 276 | }, 277 | { 278 | "cell_type": "code", 279 | "execution_count": null, 280 | "metadata": { 281 | "collapsed": true 282 | }, 283 | "outputs": [], 284 | "source": [ 285 | "text = 'тут текст, внутри которого мы что-то ищем'\n", 286 | "regName = re.compile('тут регулярное выражение') # скомпилировали\n", 287 | "toSearch = regName.search(text) # теперь можно искать в тексте\n", 288 | "toFindAll = regName.findall(text) # можно использовать скомпилированное выражение много раз\n", 289 | "toSub = regName.sub('на.что.заменить', text) # и так тоже можно использовать" 290 | ] 291 | }, 292 | { 293 | "cell_type": "markdown", 294 | "metadata": {}, 295 | "source": [ 296 | "* Что делает `regName.sub(..., ...)`?<br><br>\n", 297 | "Выражение `regName.sub('на_что_заменить', text)` значит: возьми скомпилированное выражение из переменной `regName`, и замени все, что соответствует этому выражению в переменной `text`, на строку `'на_что_заменить'`. Если первый аргумент в этом случае - пустая строка, то все найденные регуляркой куски заменятся на пустую строку, короче говоря, удалятся.<br><br>\n", 298 | "\n", 299 | "* Что такое `re.DOTALL`?<br><br>\n", 300 | "Обычно точка в регулярном выражении означает любой символ КРОМЕ символа новой строки. Чтобы изменить такое поведение, в компиляцию регулярки можно добавить параметры-флаги вот так: `flags = re.DOTALL`, и тогда точка будет ловить вообще любой символ, включая новую строку. Эти флаги слегка меняют поведение функции, вот и все.<br><br>\n", 301 | "\n", 302 | "* Что такое `re.U`?<br><br>\n", 303 | "Про эту штуку нужно знать, если вы работаете с регулярками на втором питоне. Дело в том, что во втором питоне по умолчанию выражения типа `\\w`, `\\W`, `\\s` и подобные работают только на строках ASCII, и чтобы они работали на юникодных строках нужно поставить флаг re.U. В третьем питоне все строки и так юникодные, поэтому необходимости в таком флаге нет.\n" 304 | ] 305 | }, 306 | { 307 | "cell_type": "markdown", 308 | "metadata": {}, 309 | "source": [ 310 | "## Задания\n", 311 | "\n", 312 | "1. Скачать главную страницу Яндекс.Погоды и <br>\n", 313 | " \n", 314 | "     а) распечатать сегодняшнюю температуру и облачность<br>\n", 315 | " \n", 316 | "     б) распечатать время восхода и заката<br>\n", 317 | " \n", 318 | "     в) погоду на завтра<br>\n", 319 | " \n", 320 | "2. Скачать главную страницу waitbutwhy.com. Распечатать заголовки популярных постов (которые в колонке справа с надписью Popular Posts) и колличество комментариев у каждого из них." 321 | ] 322 | } 323 | ], 324 | "metadata": { 325 | "celltoolbar": "Raw Cell Format", 326 | "kernelspec": { 327 | "display_name": "Python 3", 328 | "language": "python", 329 | "name": "python3" 330 | }, 331 | "language_info": { 332 | "codemirror_mode": { 333 | "name": "ipython", 334 | "version": 3 335 | }, 336 | "file_extension": ".py", 337 | "mimetype": "text/x-python", 338 | "name": "python", 339 | "nbconvert_exporter": "python", 340 | "pygments_lexer": "ipython3", 341 | "version": "3.6.6" 342 | } 343 | }, 344 | "nbformat": 4, 345 | "nbformat_minor": 1 346 | } 347 | -------------------------------------------------------------------------------- /Lessons/Краулеры и парсинг веб-документов/4b. Краулеры.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## Семинар 2. Выкачиваем Интернет (продолжение).\n", 8 | "\n", 9 | "Эпиграф: *У меня есть дома интернет. Можно я его скачаю на флешку и с собой принесу?*\n", 10 | "## Введение\n", 11 | "\n", 12 | "Мы научились скачивать из Интернета HTML-код страницы с заданным адресом. Это здорово, но на практике обычно приходится выкачивать содержимое не одной страницы, а целого сайта или даже многих сайтов --- тысячи или миллионы страниц. Понятно, что перечислить все интересующие нас адреса вручную, чтобы выкачать их по отдельности, в таком случае не получится. На этом семинаре мы выясним, как можно выкачивать страницы оптом, а также научимся получше их чистить от ненужных вещей.\n", 13 | "\n", 14 | "Основной проблемой, которую нужно решить при выкачивании большого количества страниц, --- как узнать адреса всех этих страниц. Мы рассмотрим два подхода.\n", 15 | "\n", 16 | "*Первый подход* обычно применяется, когда нужно загрузить все страницы какого-нибудь крупного ресурса --- например, газеты или форума. Адреса страниц на таких сайтах нередко устроены довольно просто: начинаются они все одинаково, а заканчиваются разными числами. Если внимательно посмотреть на адреса нескольких произвольных страниц, можно довольно быстро выяснить, так ли это и каков допустимый диапазон номеров страниц. В этом случае закачка всех страниц будет представлять собой простой цикл, в котором будут перебираться все номера страниц из этого диапазона.\n", 17 | "\n", 18 | "*Второй подход* обычно применяется в **краулерах** --- программах, которые обходят какой-то фрагмент интернета, собирая информацию с разных сайтов. Краулерами, например, пользуются поисковые системы, чтобы индексировать содержимое сайтов. Краулер начинает работу с одной или нескольких страниц, адреса которых задаются вручную, а затем переходит по всем ссылкам из этих страниц. Каждый раз, когда краулер загружает очередную страницу, он находит на ней не только нужную ему информацию, но и все ссылки, которые добавляются в очередь. Важно при этом помнить, где краулер уже побывал, чтобы не переходить по нескольку раз на одни и те же страницы. В настоящих краулерах применяют и другие ухищрения, например, чтобы выяснить, по каким ссылкам лучше переходить сначала, но мы этого касаться не будем.\n", 19 | "\n", 20 | "\n", 21 | "## Напоминание\n", 22 | "\n", 23 | "Ссылки в HTML задаются тэгом `a`, а сам адрес находится в атрибуте `href`. Ссылка обязательно должна начинаться с протокола (`http://`); если это не так, это означает, что ссылка указывает на другую страницу на том же сайте. При поиске ссылок в HTML нужно помнить, что между тэгом (`a`) и атрибутом (`href`) могут находиться другие атрибуты и любое количество пробелов.\n", 24 | "\n", 25 | "## Пример\n", 26 | "\n", 27 | "Чтобы было не так скучно, в этот раз мы будем тренироваться не на русском сайте, а на ирландском. Допустим, мы хотим скачать все статьи с http://dil.ie/ --- словаря древнеирландского языка. Если мы зайдем в Search и что-нибудь поищем, то словарь выдаст нам список статей с нашим запросом. В колонке слева будет заголовочное слово, а под ним --- прямая ссылка на словарную статью.\n", 28 | "\n", 29 | "Видно, что у них общее начало и у каждой страницы есть свой номер. Это значит, что мы можем пользоваться перебором номеров. Для этого нам достаточно узнать диапазон --- номера самой первой и самой последней страницы, в данном случае --- от 1 до 43345. Это мы оставляем в качестве упражнения читателю. В результате должно получиться что-то такое:\n" 30 | ] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": 2, 35 | "metadata": {}, 36 | "outputs": [], 37 | "source": [ 38 | "import urllib.request\n", 39 | "\n", 40 | "def download_page(pageUrl):\n", 41 | " try:\n", 42 | " page = urllib.request.urlopen(pageUrl)\n", 43 | " text = page.read().decode('utf-8')\n", 44 | " except:\n", 45 | " print('Error at', pageUrl)\n", 46 | " return\n", 47 | " # do something with the downloaded text\n", 48 | "\n", 49 | "commonUrl = 'http://dil.ie/'\n", 50 | "for i in range(1, 10):\n", 51 | " pageUrl = commonUrl + str(i)\n", 52 | " download_page(pageUrl)" 53 | ] 54 | }, 55 | { 56 | "cell_type": "markdown", 57 | "metadata": {}, 58 | "source": [ 59 | "В функции, отвечающей за загрузку, мы поместили собственно загрузку HTML в блок `try-except`. Это было сделано потому, что зачастую не всем номерам из допустимого диапазона соответствуют реальные страницы. Если страницы с таким адресом не существует, функция `urlopen` вызовет ошибку, которая благодаря `try-except` не вызовет падения всей программы.\n", 60 | "\n", 61 | "#### Замечание про кодировки\n", 62 | "\n", 63 | "Открывая веб-страницу, мы получаем всего лишь последовательность байт - чтобы увидеть текст, ее еще нужно расшифровать. За это отвечает метод `decode`, которому в качестве аргумента передается необходимая кодировка. Аргументом этой функции по умолчанию является \"utf-8\", но на многих русскоязычных сайтах, особенно старых, вы можете встретить кодировку \"cp1251\". \n", 64 | "\n", 65 | "## Важный комментарий\n", 66 | "\n", 67 | "Когда Ваша программа выкачивает много страниц сразу, она создаёт нагрузку на сервер выкачиваемого сайта --- и эта нагрузка намного больше, чем нагрузка от обычного посещения сайта людьми. Если Вы выкачиваете содержимое крупного сайта с одного компьютера, то ничего страшного в этом, скорее всего, нет. Но если это не какой-то крупный ресурс, который владеет мощными серверами, и тем более если страницы с него скачивают несколько человек одновременно, это может создать реальные проблемы владельцам выкачиваемого ресурса. Поэтому, во-первых, нужно всегда выяснять, не доступно ли всё содержимое нужного Вам ресурса по отдельной ссылке (например, так обстоит дело с Википедией), а во-вторых, ставить между обращениями к серверу искуственный временной интервал хотя бы в пару секунд:\n" 68 | ] 69 | }, 70 | { 71 | "cell_type": "code", 72 | "execution_count": 3, 73 | "metadata": {}, 74 | "outputs": [], 75 | "source": [ 76 | "import time\n", 77 | "\n", 78 | "time.sleep(2)" 79 | ] 80 | }, 81 | { 82 | "cell_type": "markdown", 83 | "metadata": {}, 84 | "source": [ 85 | "## Как почистить текст\n", 86 | "\n", 87 | "В html странице, конечно, всегда много тэгов, скриптов и комментариев. А нам обычно бывает нужен только текст.\n", 88 | "Чтобы вытащить из html только текст, можно воспользоваться регулярными выражениями: " 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": null, 94 | "metadata": { 95 | "collapsed": true 96 | }, 97 | "outputs": [], 98 | "source": [ 99 | "html_content = '<html>....</html>' # тут какой-то html\n", 100 | "\n", 101 | "regTag = re.compile('<.*?>', re.DOTALL) # это рег. выражение находит все тэги\n", 102 | "regScript = re.compile('<script>.*?</script>', re.DOTALL) # все скрипты\n", 103 | "regComment = re.compile('<!--.*?-->', re.DOTALL) # все комментарии\n", 104 | "\n", 105 | "\n", 106 | "# а дальше заменяем ненужные куски на пустую строку\n", 107 | "clean_t = regScript.sub(\"\", t)\n", 108 | "clean_t = regComment.sub(\"\", clean_t)\n", 109 | "clean_t = regTag.sub(\"\", clean_t)" 110 | ] 111 | }, 112 | { 113 | "cell_type": "markdown", 114 | "metadata": {}, 115 | "source": [ 116 | "Нужно не забывать, что для отображения на html-странице символов, которых нет на клавиатуре, применяются специальные последовательности символов, начинающиеся с амперсанда (&) и заканчивающиеся точкой с запятой (;). Чтобы получить текст не с такими последовательностями, а с нормальными символами, используется специальная функция в питоне `unescape`:" 117 | ] 118 | }, 119 | { 120 | "cell_type": "code", 121 | "execution_count": 4, 122 | "metadata": {}, 123 | "outputs": [ 124 | { 125 | "name": "stdout", 126 | "output_type": "stream", 127 | "text": [ 128 | "Петя & Вася\n" 129 | ] 130 | } 131 | ], 132 | "source": [ 133 | "# если у вас Python3.4+\n", 134 | "import html\n", 135 | "test_string = 'Петя & Вася'\n", 136 | "print( html.unescape(test_string) )" 137 | ] 138 | }, 139 | { 140 | "cell_type": "code", 141 | "execution_count": 10, 142 | "metadata": {}, 143 | "outputs": [ 144 | { 145 | "name": "stdout", 146 | "output_type": "stream", 147 | "text": [ 148 | "Специальные символы: \" « » ♠ ♥ ♣ ♦ и так далее\n" 149 | ] 150 | } 151 | ], 152 | "source": [ 153 | "print( html.unescape('Специальные символы: " « » ♠ ♥ ♣ ♦ и так далее') )" 154 | ] 155 | }, 156 | { 157 | "cell_type": "code", 158 | "execution_count": null, 159 | "metadata": { 160 | "collapsed": true 161 | }, 162 | "outputs": [], 163 | "source": [ 164 | "# если у вас Python3.3 или более ранняя версия \n", 165 | "import html.parser \n", 166 | "html.parser.HTMLParser().unescape('Петя & Вася')" 167 | ] 168 | } 169 | ], 170 | "metadata": { 171 | "celltoolbar": "Raw Cell Format", 172 | "kernelspec": { 173 | "display_name": "Python 3", 174 | "language": "python", 175 | "name": "python3" 176 | }, 177 | "language_info": { 178 | "codemirror_mode": { 179 | "name": "ipython", 180 | "version": 3 181 | }, 182 | "file_extension": ".py", 183 | "mimetype": "text/x-python", 184 | "name": "python", 185 | "nbconvert_exporter": "python", 186 | "pygments_lexer": "ipython3", 187 | "version": "3.6.6" 188 | } 189 | }, 190 | "nbformat": 4, 191 | "nbformat_minor": 1 192 | } 193 | -------------------------------------------------------------------------------- /Lessons/Краулеры и парсинг веб-документов/lxml_bs4.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "There are existing modules for parsing HTML. These are also not perfect, but they can often be a lot more perfect that you or I might have patience for;)" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "One very common solution in Python is **Beautiful Soup**, a free open-source module for Python for parsing and manipulating HTML. You have to install it yourself, but once installed, it can be called like any other module. The module is called **bs4** and the relevant function is `BeautifulSoup()`. What that does is parse the HTML and build a document model. This is a treelike representation of the HTML document and you can extract elements from it easily. The following code exemplifies:" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": null, 20 | "metadata": {}, 21 | "outputs": [], 22 | "source": [ 23 | "#import for reading urls\n", 24 | "import urllib.request\n", 25 | "#import for parsing html\n", 26 | "from bs4 import BeautifulSoup\n", 27 | "#non-local page this time\n", 28 | "link = \"https://habr.com/\"\n", 29 | "#connect to that page\n", 30 | "f = urllib.request.urlopen(link)\n", 31 | "#read it all in\n", 32 | "myfile = f.read()\n", 33 | "#build a document model\n", 34 | "soup = BeautifulSoup(myfile,'html.parser')\n", 35 | "#print the page verbatim\n", 36 | "print(myfile)" 37 | ] 38 | }, 39 | { 40 | "cell_type": "markdown", 41 | "metadata": {}, 42 | "source": [ 43 | "Here we read in a web page and then parse it with `BeautifulSoup()`. We can then print a pretty version of it with `prettify()`, extract the text with `get_text()`, or find all instances of a tag with `find_all()`. Each tag found\n", 44 | "is its own treelike representation, so we can continue to call methods on them. In the example at hand, we call the `get()` method to extract the text of the `href` attribute for the `a` tags." 45 | ] 46 | }, 47 | { 48 | "cell_type": "code", 49 | "execution_count": null, 50 | "metadata": {}, 51 | "outputs": [], 52 | "source": [ 53 | "#pretty-print the html\n", 54 | "print(soup.prettify())" 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": null, 60 | "metadata": {}, 61 | "outputs": [], 62 | "source": [ 63 | "#extract the text\n", 64 | "print(soup.get_text())" 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": null, 70 | "metadata": {}, 71 | "outputs": [], 72 | "source": [ 73 | "#got through all the hyperlinks...\n", 74 | "for link in soup.find_all('a'):\n", 75 | "#...and print them\n", 76 | " print(link.get('href'))" 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": null, 82 | "metadata": {}, 83 | "outputs": [], 84 | "source": [ 85 | "import requests\n", 86 | "from bs4 import BeautifulSoup\n", 87 | "\n", 88 | "result = requests.get('https://habr.com/')\n", 89 | "html = result.text\n", 90 | "\n", 91 | "soup = BeautifulSoup(html,'html.parser')\n", 92 | "\n", 93 | "for post in soup.find_all('article', {'class': 'post'}):\n", 94 | " print(post.find('a', {'class': 'post__title_link'}).get_text())\n", 95 | " print(post.find('div', {'class': 'post__text'}).prettify())\n", 96 | "\n", 97 | " print('-- '*10)" 98 | ] 99 | }, 100 | { 101 | "cell_type": "markdown", 102 | "metadata": {}, 103 | "source": [ 104 | "An alternative module for parsing HTML is **lxml**. It is quite easy to parse the HTML code extracted with the help of lxml. As soon as we trasformed our data into a tree, we can use XPath to extract them." 105 | ] 106 | }, 107 | { 108 | "cell_type": "code", 109 | "execution_count": 1, 110 | "metadata": {}, 111 | "outputs": [ 112 | { 113 | "name": "stdout", 114 | "output_type": "stream", 115 | "text": [ 116 | "Яндекс\n", 117 | "['https://mail.yandex.ru', '//yandex.ru']\n" 118 | ] 119 | } 120 | ], 121 | "source": [ 122 | "import requests\n", 123 | "from lxml import html\n", 124 | "\n", 125 | "response = requests.get('http://ya.ru')\n", 126 | "\n", 127 | "# Преобразование тела документа в дерево элементов (DOM)\n", 128 | "parsed_body = html.fromstring(response.text)\n", 129 | "\n", 130 | "# Выполнение xpath в дереве элементов\n", 131 | "print(parsed_body.xpath('//title/text()')[0]) # Получить title страницы\n", 132 | "print(parsed_body.xpath('//a/@href')) # Получить аттрибут href для всех ссылок" 133 | ] 134 | } 135 | ], 136 | "metadata": { 137 | "kernelspec": { 138 | "display_name": "Python 3", 139 | "language": "python", 140 | "name": "python3" 141 | }, 142 | "language_info": { 143 | "codemirror_mode": { 144 | "name": "ipython", 145 | "version": 3 146 | }, 147 | "file_extension": ".py", 148 | "mimetype": "text/x-python", 149 | "name": "python", 150 | "nbconvert_exporter": "python", 151 | "pygments_lexer": "ipython3", 152 | "version": "3.6.5" 153 | } 154 | }, 155 | "nbformat": 4, 156 | "nbformat_minor": 2 157 | } 158 | -------------------------------------------------------------------------------- /Lessons/Морфологический анализ/6. Mystem.md: -------------------------------------------------------------------------------- 1 | # Семинар 3: Mystem 2 | 3 | ![Mystem](https://github.com/elmiram/2016learnpython/blob/master/img/one_does_not_mystem.jpg) 4 | 5 | ## Запуск программ из командной строки 6 | 7 | Кроме программ, которые имеют GUI (графический, оконный интерфейс), часто приходится использовать такие программы, которые управляются из командной строки. Ещё она называется *терминалом* или *консолью*. 8 | 9 | Для того, чтобы запустить командную строку, в Windows нужно найти среди других программу **cmd**. 10 | 11 | В начале того, что показывает интерфейс командной строки, обычно написано, какое место в системе программа считает рабочим. Например, `C:\Users\student`. После этого обычно мы видим знак т.н. *приглашения* командной строки, то есть сигнал того, что программа готова к работе и ждёт действий от пользователя. В Windows это обычно знак *больше*, `>`. 12 | 13 | С помощью набора команд, которые отправляются на исполнение с помощью клавиши `Enter`, можно передвигаться по диску и запускать другие программы. 14 | 15 | Запуск программ обычно выглядит так. Сначала нужно написать путь к запускаемой программе: `C:\some_prog.exe`. Путь может быть и абсолютным, и относительным. Считается он относительно того места, которое показывается перед приглашением. 16 | 17 | Иногда программы нужно запускать не сами по себе, а с определёнными *аргументами* или ещё их называют *параметрами* (похоже на аргументы функции в питоне). Тогда эти аргументы пишутся после пути к программе через пробел. Если сам аргумент тоже содержит пробел, его нужно обернуть в кавычки: `C:\some_prog.exe argument1 "argument 2"` 18 | 19 | Кроме того, среди таких аргументов есть такие, которые принято называть *опциями* или *ключами*, они начинаются с символа дефиса: `C:\some_prog.exe -a -b`. Их можно "склеивать": `C:\some_prog.exe -ab`. 20 | 21 | Какие у программы возможны аргументы и опции, в каком порядке они должны идти при запуске из командной строки, обычно описано в документации к программам. 22 | 23 | Через командную строку можно, например, запускать скрипты на питоне. Тогда запускаемой программой будет интерпретатор питона, а аргументом -- путь к собственно скрипту: `C:\Python34\python.exe C:\myscript.py` 24 | 25 | ## Mystem 26 | 27 | Mystem - это свободно распространяемый морфологический анализатор для русского языка с закрытым исходным кодом. То есть мы можем его бесплатно скачать с сайта и пользоваться им, но не можем посмотреть, что у него внутри и как оно работает. 28 | 29 | Mystem был придуман одним из создателей Яндекса Ильёй Сегаловичем. Некоторый потомок mystem'а до сих пор работает внутри большого поисковика Яндекса, анализируя слова при поиске. 30 | 31 | My-stem значит my stemmer, стемминг -- это разбиение формы на основу и флексию. Но на самом деле Mystem может гораздо больше: устанавливать словарную форму слова, определять часть речи и грамматическую форму слова. В последних версиях Mystem умеет и выбирать из нескольких возможных грамматических разборов один, наиболее верный. 32 | 33 | У Mystem нет графического оконного интерфейса, запустить его можно только из командной строки. 34 | 35 | Скачать Mystem можно [отсюда](https://tech.yandex.ru/mystem/), а [тут](https://tech.yandex.ru/mystem/doc/index-docpage/) лежит его документация. 36 | 37 | Mystem не требует специальной инсталляции в систему. Достаточно, чтобы исполняемый файл с программой, подходящей для вашей версии операционной системы, находился на вашем компьютере. 38 | 39 | ## Как читать документацию Mystem 40 | 41 | [На странице документации](https://tech.yandex.ru/mystem/doc/index-docpage/) описаны разные возможности вызова Mystem из командной строки. В зависимости от параметров, с которыми мы вызовем программу, мы получим разный результат. 42 | 43 | Примеры, которые там приведены, рассчитаны на пользователя Unix-подобной операционной системы. То есть не Windows. 44 | 45 | В начале примеров вызова стоит знак доллара, $. Это не значит, что его вам тоже нужно набирать, если вы хотите воспроизвести эти примеры. Доллар -- это аналог приглашения командной строки, просто не в Windows, а в Unix-подобных системах. Если вы берете примеры вызова со страницы документации за основу, игнорируйте знак доллара. 46 | 47 | В документации написано: `$ mystem input`. На практике для пользователей Windows это будет значить что-то вроде `C:\mystem.exe input.txt`. 48 | 49 | В документации написано "стандартный ввод" и "стандартный вывод", это значит то, что вводится в командной строке или выводится в тот же терминал. Если не используются стандартный ввод и вывод, то используются файлы (выводной файл Mystem способен создать сам). 50 | 51 | В 3-й версии Mystem кодировка по умолчанию -- utf-8. В первых версиях -- cp1251. Кодировка по умолчанию в командной строке Windows -- cp866. Из-за этого Mystem может не понимать слова, которые попадают к нему из стандартного ввода. 52 | 53 | ## Как запускать Mystem 54 | 55 | Об этом довольно хорошо и подробно написано [на странице документации](https://tech.yandex.ru/mystem/doc/index-docpage/), её нужно внимательно изучить и попробовать разные вариант опций. 56 | 57 | Особое внимание нужно уделить опции `-d`, она заставляет анализатор выбирать только один разбор из возможных. При этом выбор происходит только между разными частями речи. Если у одной части речи возможны разные разборы (например, разные падежи одного и того же существительного), то эти разборы не отбрасываются. Иначе говоря, Mystem снимает только частеречную омонимию. Омонимию форм он не снимает. 58 | 59 | ## Как запускать Mystem из питона? 60 | 61 | Для запуска сторонних программ, имеющих интерфейс командной строки, в питоне есть system, предоставляемая модулем os: `os.system("C:\mystem.exe input.txt output.txt")`. Перед добавлением такой конструкции в код, необходимо импортировать модуль os. 62 | 63 | Это нужно, чтобы, например, обработать много файлов циклом: 64 | 65 | ```python 66 | import os 67 | inp = "input_texts" 68 | lst = os.listdir(inp) 69 | for fl in lst: 70 | os.system(r"C:\mystem.exe " + inp + os.sep + fl + " output_texts" + os.sep + fl) 71 | ``` 72 | 73 | Этот код берёт из директории *input_texts* все лежащие в ней файлы, отдаёт на разметку майстему и кладёт результат в соседнюю директорию *output_texts*. 74 | 75 | Есть возможность запускать mystem и с помощью специального модуля, **pymystem3** (и некоторых других), который нужно специально установить (его нет в стандартной сборке питона). Исходники pymystem3 и вся документация лежат [вот тут](https://github.com/Digsolab/pymystem3). Это проще и удобнее, потому что с тем, что выдаёт mystem, можно сразу работать как с питоновскими структурами данных. Но медленнее. Иногда гораздо-гораздо медленнее, чем разметить один файл mystem'ом сразу. 76 | 77 | ## Задание 78 | 79 | Скачать mystem и попробовать разные опции его запуска на практике. Посмотреть, чем результат вызова с одними опциями отличается от результата вызова с другими опциями. 80 | 81 | -------------------------------------------------------------------------------- /Lessons/Морфологический анализ/rus_stopwords.txt: -------------------------------------------------------------------------------- 1 | а 2 | ах 3 | б 4 | без 5 | безо 6 | будем 7 | будет 8 | будете 9 | будешь 10 | буду 11 | будут 12 | будучи 13 | будь 14 | будьте 15 | бы 16 | был 17 | была 18 | были 19 | было 20 | быть 21 | в 22 | вам 23 | вами 24 | вас 25 | ваше 26 | вдруг 27 | ведь 28 | весь 29 | весьма 30 | видеть 31 | видит 32 | вместе 33 | во 34 | вот 35 | все 36 | всего 37 | всей 38 | всем 39 | всеми 40 | всему 41 | всех 42 | всею 43 | всея 44 | вскоре 45 | всю 46 | вся 47 | всё 48 | всём 49 | вы 50 | где 51 | говорил 52 | говорила 53 | говорили 54 | говорит 55 | говорит 56 | говорить 57 | да 58 | даже 59 | делал 60 | делала 61 | делали 62 | делать 63 | для 64 | до 65 | думает 66 | думал 67 | думала 68 | думали 69 | думать 70 | его 71 | едим 72 | едят 73 | ее 74 | ей 75 | ел 76 | ела 77 | ем 78 | ему 79 | емъ 80 | если 81 | ест 82 | есть 83 | ешь 84 | еще 85 | ещё 86 | ею 87 | её 88 | ж 89 | же 90 | за 91 | зачем 92 | здесь 93 | и 94 | из 95 | или 96 | им 97 | ими 98 | имъ 99 | их 100 | к 101 | ка 102 | как 103 | кем 104 | ко 105 | ко 106 | когда 107 | кого 108 | коли 109 | коль 110 | ком 111 | кому 112 | комья 113 | которая 114 | которого 115 | которое 116 | которой 117 | котором 118 | которому 119 | которою 120 | которую 121 | которые 122 | который 123 | которым 124 | которыми 125 | которых 126 | кто 127 | куда 128 | ли 129 | между 130 | меня 131 | мені 132 | мне 133 | мной 134 | мною 135 | мог 136 | моги 137 | могите 138 | могла 139 | могли 140 | могло 141 | могу 142 | могут 143 | мое 144 | моего 145 | моей 146 | моем 147 | моему 148 | моею 149 | можем 150 | может 151 | может 152 | можете 153 | можешь 154 | можно 155 | мои 156 | моим 157 | моими 158 | моих 159 | мой 160 | мочь 161 | мою 162 | моя 163 | моё 164 | моём 165 | мы 166 | на 167 | на 168 | над 169 | надо 170 | наконец 171 | нам 172 | нами 173 | нас 174 | наса 175 | наш 176 | наша 177 | наше 178 | нашего 179 | нашей 180 | нашем 181 | нашему 182 | нашею 183 | наши 184 | нашим 185 | нашими 186 | наших 187 | нашою 188 | нашої 189 | нашу 190 | наші 191 | нашій 192 | нашім 193 | не 194 | него 195 | нее 196 | ней 197 | нем 198 | нему 199 | несколько 200 | нет 201 | нечего 202 | нею 203 | неё 204 | ни 205 | ним 206 | ними 207 | них 208 | ничего 209 | но 210 | ну 211 | нужно 212 | нём 213 | о 214 | об 215 | один 216 | одна 217 | однако 218 | одни 219 | одним 220 | одними 221 | одних 222 | одно 223 | одного 224 | одной 225 | одном 226 | одному 227 | одною 228 | одну 229 | около 230 | он 231 | она 232 | оне 233 | они 234 | оно 235 | опять 236 | от 237 | ответил 238 | ответил 239 | ответила 240 | ответила 241 | ответили 242 | ответили 243 | отвечает 244 | отвечал 245 | отвечала 246 | отвечали 247 | отвечать 248 | ох 249 | очень 250 | перед 251 | перед 252 | по 253 | под 254 | после 255 | потом 256 | почему 257 | при 258 | про 259 | раз 260 | с 261 | сам 262 | сама 263 | сами 264 | самим 265 | самими 266 | самих 267 | само 268 | самого 269 | самом 270 | самому 271 | саму 272 | свое 273 | своего 274 | своей 275 | своем 276 | своему 277 | своею 278 | свои 279 | своим 280 | своими 281 | своих 282 | свой 283 | свою 284 | своя 285 | своё 286 | своём 287 | себе 288 | себя 289 | сказал 290 | сказала 291 | сказали 292 | сказать 293 | скоро 294 | со 295 | собой 296 | собою 297 | спросил 298 | спросила 299 | спросили 300 | стал 301 | стала 302 | стали 303 | та 304 | так 305 | такая 306 | такие 307 | таким 308 | такими 309 | таких 310 | такого 311 | такое 312 | такой 313 | таком 314 | такому 315 | такою 316 | такую 317 | там 318 | те 319 | тебе 320 | тебя 321 | тем 322 | теми 323 | теперь 324 | тех 325 | теє 326 | то 327 | тобой 328 | тобою 329 | тогда 330 | того 331 | той 332 | только 333 | том 334 | томах 335 | тому 336 | тот 337 | тотчас 338 | тою 339 | ту 340 | тут 341 | ты 342 | ті 343 | тією 344 | тієї 345 | тії 346 | у 347 | увидел 348 | увидела 349 | увидели 350 | уж 351 | уже 352 | уже 353 | уже 354 | хотел 355 | хотела 356 | хотели 357 | хотеть 358 | хоть 359 | хотя 360 | хочет 361 | чего 362 | чем 363 | чему 364 | через 365 | что 366 | чтоб 367 | чтобы 368 | чуть 369 | чём 370 | эта 371 | эти 372 | этим 373 | этими 374 | этих 375 | это 376 | этого 377 | этой 378 | этом 379 | этому 380 | этот 381 | этою 382 | эту 383 | я -------------------------------------------------------------------------------- /Lessons/Структуры данных/KILI_seminar2_datatypes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ancatmara/learnpython2018/eec59d8a9d05ca80783d39963189cbd80ac661f3/Lessons/Структуры данных/KILI_seminar2_datatypes.pdf -------------------------------------------------------------------------------- /Lessons/Структуры данных/kilipractice.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | 4 | """ 5 | KILI: Programming for Linguists 6 | HSE Linguistics, Fall 2018 7 | Daria Popova 8 | 9 | Practice 2 10 | 11 | Distributed 2018-09-14 12 | 13 | NOTE: Please submit a modified version of this file, including 14 | comments. Python should be able to run through your file without 15 | errors. 16 | """ 17 | 18 | import math 19 | import pprint 20 | 21 | """=================================================================== 22 | 1 [1 point] 23 | 24 | Complete the function mean for calculating the mean (average) of a 25 | list of numeric values. Your function should take a list vals as its 26 | argument and return a float. Keep in mind that vals might contain int 27 | values. 28 | 29 | Consider doing it with the in-line function sum, which facilitates a fast and readable one-line version of the function. 30 | """ 31 | 32 | def mean(vals): 33 | """Return the mean of the values in vals, presupposed to be 34 | numeric (float, int, or long).""" 35 | 36 | """=================================================================== 37 | 2 [1 point] 38 | 39 | Complete the function sd for calculating the standard deviation of a 40 | list of numeric values. Your function should take a list vals as its 41 | value and return a float. Keep in mind that vals might contain int 42 | values. 43 | 44 | For details on calculating the standard deviation, see 45 | http://en.wikipedia.org/wiki/Standard_deviation 46 | 47 | I suggest using float(len(vals)-1) for the denominator, but 48 | float(len(vals)) is fine. 49 | 50 | To get the square root of a float x, using math.sqrt(x) 51 | """ 52 | 53 | def sd(vals): 54 | """Return the standard deviation of the values in vals, 55 | presupposed to be numeric (float, int, or long).""" 56 | 57 | """=================================================================== 58 | 3 [1 point] 59 | 60 | Complete the function zscore for computing the z-score (normal score) 61 | of a list of numeric values. Your function should take a list vals as 62 | its value and return a list of z-score normed values. Use mean and sd, 63 | as defined above, for this calculation. 64 | 65 | For details on calculating the z-score, see 66 | http://en.wikipedia.org/wiki/Z_score 67 | """ 68 | 69 | """def zscore(vals): 70 | This function is radical: it will replace vals with zscored vals. 71 | m = mean(vals) 72 | s = sd(vals) 73 | if sd(vals) > 0: 74 | for x in range(0,len(vals)): 75 | vals[x] = (vals[x] - m) / s 76 | return vals 77 | else: 78 | return 'n/a'""" 79 | 80 | def zscore(vals): 81 | """Return the z-scored version of vals.""" 82 | 83 | """=================================================================== 84 | 4 85 | 86 | Intro to comma-separated values. The string myspreadsheet stores 11 87 | lines of comma-separated values, with the first line giving the column 88 | names and the other lines giving the data on 10 imaginary subjects. 89 | Below are some questions that ask you to write functions for working 90 | with this data. 91 | """ 92 | 93 | myspreadsheet ="""Subject,Height,Occupation 94 | 1,74.37000326528938,Psychologist 95 | 2,67.49686206937491,Psychologist 96 | 3,74.92356434760966,Psychologist 97 | 4,64.62372198999978,Psychologist 98 | 5,67.76787900026083,Linguist 99 | 6,61.50397707923559,Psychologist 100 | 7,62.73680961908566,Psychologist 101 | 8,68.60803984763902,Linguist 102 | 9,70.16090500135535,Psychologist 103 | 10,76.81144438287173,Linguist""" 104 | 105 | """-------------------------------------------------- 106 | Random facts: The column of heights, presumably in 107 | inches, was generated with 108 | 109 | import random 110 | 111 | and then repeated runs of 112 | 113 | random.uniform(60,77) 114 | 115 | The column of occupations was generated with 116 | 117 | d = {0:'Psychologist',1:'Linguist'} 118 | 119 | and then repeated runs of 120 | 121 | d[random.randint(0,1)] 122 | --------------------------------------------------""" 123 | 124 | """=================================================================== 125 | 4.1 [3 points] 126 | 127 | Basic CSV parser. Complete the following function for turning the str 128 | myspreadsheet into a 10x3 matrix of data. I should emphasize that the 129 | top line of myspreadsheet is not part of the data. It's just there to 130 | help us out. 131 | 132 | Column 0 of your data should be int values. 133 | 134 | Column 1 of your data should be float values. 135 | 136 | To test your parser, call csv_parser_test, which will work with 137 | no modifications. 138 | """ 139 | 140 | def csv_parser(s): 141 | """Parses the string s into lines, and then parses those lines by 142 | splitting on the comma and converting the numerical data to int. 143 | The output is a list of lists of subject data.""" 144 | 145 | # Data is our output. It will be a list of lists. 146 | 147 | # Split csv into lines and store them in a list called 'lines'. 148 | 149 | # Remove the first element from lines, so that you have only the data lines left. 150 | 151 | # At this stage, we loop through the list called lines. 152 | # As you loop 153 | # i. split each line on the commas; 154 | # ii. convert the Subject variable to int. 155 | # iii. convert the Height variable to float. 156 | # iv. add to data a list consisting of this line's Subject, Height, and Occupation values 157 | 158 | def csv_parser_test(): 159 | """Display the output of csv_parser(myspreadsheet) and 160 | test it a little bit.""" 161 | data = csv_parser(myspreadsheet) 162 | print 'Your data object:' 163 | pp = pprint.PrettyPrinter(indent=4) 164 | pp.pprint(data) 165 | # Did your parser work? 166 | for row_num, row in enumerate(data): 167 | try: 168 | assert len(row) == 3 169 | except AssertionError: 170 | print "Row %s seems to be misparsed; its length is %s" % (row_num, len(row)) 171 | # Check on one of the values: 172 | try: 173 | assert data[4][2] == 'Linguist' 174 | except AssertionError: 175 | print "Error: data[4][2] should equal 'Linguist'; actual value is %s" % data[4][2] 176 | # Did you remember your int conversions? 177 | try: 178 | assert isinstance(data[0][0], int) 179 | except AssertionError: 180 | print "Error: data[0][0] should be an int" 181 | # Did you remember your float conversions? 182 | try: 183 | assert isinstance(data[6][1], float) 184 | except AssertionError: 185 | print "Error: data[6][1] should be a float" 186 | 187 | """=================================================================== 188 | 4.2 [1 point] 189 | 190 | Complete the following function for computing the mean height of the 191 | subjects in this data set, using your mean function from above. 192 | """ 193 | 194 | def mean_height(data): 195 | """Return the mean numerical value of column 1 in an list of lists. 196 | data is the output of csv_parser(myspreadsheet)""" 197 | 198 | """=================================================================== 199 | 4.3 [2 points] 200 | 201 | Occupation distribution. Complete the following function so that it 202 | returns a dictionary mapping occupation names into the number of times 203 | they occur in the data. 204 | """ 205 | 206 | def occupation_distribution(data): 207 | """Returns the list of occupations given in column 2 of data. 208 | data is the output of csv_parser(myspreadsheet)""" 209 | 210 | """===================================================================""" 211 | 212 | def proper_title_case(s): 213 | """ 214 | Try to do a better job of getting title case. For example, 215 | "the cat in the hat".title() ==> "The Cat In The Hat", 216 | but we want "The Cat in the Hat" 217 | """ 218 | nocaps = ["the"] # This needs to be extended. 219 | 220 | """=================================================================== 221 | 222 | 5. Fillers, making nonsense items [1 point] 223 | 224 | 5.1 225 | A frequent task for psycholinguists is finding items for experiments, either items that directly exemplify some property we want to test or items that fill out an experiment and can be used to distract subjects from the true goal of the experiment. 226 | Imagine what we want are CV monosyllables. We could just try to think of all possible monosyllables with a CV shape, but another way to go is to generate these programmatically. If we know what the possible consonants are and what the possible vowels are, we can generate a list of possible CV monosyllables quite simply. 227 | 228 | """ 229 | #define vowels and consonants 230 | #for every vowel 231 | #choose a consonant 232 | #now print them together 233 | """===== 234 | 5.2 235 | The same kind of logic can be used to construct nonsense sentences. Imagine we want every possible SVO sentence in some (nonsense) language. We have a set of 236 | nouns and transitive verbs. We can combine them straightforwardly. 237 | """ 238 | 239 | #define nouns and verbs 240 | #combine them 241 | 242 | ###################################################################### 243 | 244 | if __name__ == '__main__': 245 | 246 | #print proper_title_case("the cat in the hat") 247 | #print proper_title_case("an ant on a table") 248 | #print mean([1,2,3,4,5,6,7,8,9,10]) 249 | #print sd([0,1,2]) 250 | #print zscore([0,2,4]) 251 | #print csv_parser_test() 252 | #print mean_height(myspreadsheet) 253 | #print occupation_distribution(myspreadsheet) 254 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python for Linguists 2018 2 | 3 | Семинары по программированию на Python для 2 курса Школы Лингвистики НИУ ВШЭ, 2018-2019 гг. 4 | 5 | ### Преподаватели 6 | * Оксана Владимировна Дереза ([почта](mailto:oksana.dereza@gmail.com), [telegram](https://t.me/ancatmara)) 7 | * Дарья Павловна Попова ([почта](mailto:daschapopowa@gmail.com)) 8 | * Ростислав Алексеевич Бородин ([почта](mailto:roctbb@gmail.com), [telegram](https://t.me/roctbb)) 9 | 10 | ### Ассистенты 11 | * Валерия Алексеевна Морозова ([почта](mailto:tito_alba@mail.ru), [telegram](https://t.me/eternal_phobia)) 12 | 13 | ### Информация 14 | * Вот [эту форму](https://goo.gl/forms/WAVZWtjpyoRDcgm22) нужно обязательно заполнить, иначе мы не сможем проверять ваши домашки. :) 15 | * А [это](https://docs.google.com/spreadsheets/d/1MRWqsqtRnsgMb5c2ywL1LKUlDvpD8G0EzG05cPQ7jc4/edit?usp=sharing) ведомости по курсу. 16 | 17 | ### Telegram 18 | * [Чат 2-ой группы](https://t.me/joinchat/ADMP3VFYTP7EoizUYT2frg) 19 | * [Чат 4-ой группы](https://t.me/joinchat/BSwQA0nY3ueMOZ8gFhe-kQ) 20 | 21 | 22 | ### План курса: 1-2 модуль 23 | <table> 24 | <tr> 25 | <th>№</th> 26 | <th>Семинар</th> 27 | <th>Домашнее задание</th> 28 | <th>Дедлайн</th> 29 | <th>Комментарий</th> 30 | </tr> 31 | <tr> 32 | <td>1.</td> 33 | <td>1. <a href="https://github.com/ancatmara/learnpython2018/blob/master/Lessons/Markdown%20%D0%B8%20git/1.%20Intro.ipynb">Настройка окружения. Оформление кода по PEP8. Jupyter notebook.</a> <br> 34 | 2. <a href="https://github.com/ancatmara/learnpython2018/blob/master/Lessons/Markdown%20%D0%B8%20git/cmd%20cheatsheet.md">Консольный git.</a><br> 35 | 3. <a href="https://github.com/ancatmara/learnpython2018/blob/master/Lessons/Markdown%20%D0%B8%20git/Markdown.md">Оформление репозитория и Markdown.</a></td> 36 | <td><a href="./Homeworks/HW1.md">Виселица</a></td> 37 | <td>22 сентября, 9:00</td> 38 | <td></td> 39 | </tr> 40 | <tr> 41 | <td>2.</td> 42 | <td><a href="https://github.com/ancatmara/learnpython2018/blob/master/Lessons/%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D1%8B%20%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85/2.%20%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D1%8B%20%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85.ipynb">Структуры данных.</a></td> 43 | <td></td> 44 | <td></td> 45 | <td></td> 46 | </tr> 47 | <tr> 48 | <td>3.</td> 49 | <td><a href="https://github.com/ancatmara/learnpython2018/blob/master/Lessons/JSON/3.%20JSON.ipynb">JSON</a></td> 50 | <td><a href="./Homeworks/HW2.md">GitHub Users</a></td> 51 | <td>6 октября, 9:00 </td> 52 | <td></td> 53 | </tr> 54 | <tr> 55 | <td>4.</td> 56 | <td><a href="https://github.com/ancatmara/learnpython2018/blob/master/Lessons/%D0%9A%D1%80%D0%B0%D1%83%D0%BB%D0%B5%D1%80%D1%8B%20%D0%B8%20%D0%BF%D0%B0%D1%80%D1%81%D0%B8%D0%BD%D0%B3%20%D0%B2%D0%B5%D0%B1-%D0%B4%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2/4a.%20Urllib.ipynb">urllib</a> 57 | и <a href="https://github.com/ancatmara/learnpython2018/blob/master/Lessons/%D0%9A%D1%80%D0%B0%D1%83%D0%BB%D0%B5%D1%80%D1%8B%20%D0%B8%20%D0%BF%D0%B0%D1%80%D1%81%D0%B8%D0%BD%D0%B3%20%D0%B2%D0%B5%D0%B1-%D0%B4%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2/4b.%20%D0%9A%D1%80%D0%B0%D1%83%D0%BB%D0%B5%D1%80%D1%8B.ipynb">Краулеры</a></td> 58 | <td></td> 59 | <td></td> 60 | <td></td> 61 | </tr> 62 | <tr> 63 | <td>5.</td> 64 | <td><a href="https://github.com/ancatmara/learnpython2018/blob/master/Lessons/%D0%9A%D1%80%D0%B0%D1%83%D0%BB%D0%B5%D1%80%D1%8B%20%D0%B8%20%D0%BF%D0%B0%D1%80%D1%81%D0%B8%D0%BD%D0%B3%20%D0%B2%D0%B5%D0%B1-%D0%B4%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2/lxml_bs4.ipynb">Парсинг HTML и XML-документов: lxml, bs4</a></td> 65 | <td></td> 66 | <td></td> 67 | <td><a href='https://docs.google.com/spreadsheets/d/1kC9aK4j5PvoPNVY5NY2DY_H1Pbv398RC2LAP6W0z1yQ/edit?usp=sharing'>Газеты</a></td> 68 | </tr> 69 | <tr> 70 | <td>6.</td> 71 | <td><a href='https://github.com/ancatmara/learnpython2018/blob/master/Lessons/%D0%9C%D0%BE%D1%80%D1%84%D0%BE%D0%BB%D0%BE%D0%B3%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B9%20%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7/6.%20Mystem.md'>Лемматизация и POS-tagging: Mystem</a></td> 72 | <td><a href='https://github.com/ancatmara/learnpython2018/blob/master/Homeworks/Project.ipynb'>Собираем газетный корпус </a></td> 73 | <td>29 октября, 10:00</td> 74 | <td></td> 75 | </tr> 76 | <tr> 77 | <td>8.</td> 78 | <td><a href="https://github.com/ancatmara/learnpython2018/blob/master/Lessons/%D0%92%D0%B5%D0%B1-%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D1%8B%20%D0%B8%20%D1%84%D0%BE%D1%80%D0%BC%D1%8B/8.%20%D0%97%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D1%8B%20%D0%B8%20%D1%84%D0%BE%D1%80%D0%BC%D1%8B.ipynb">Веб: запросы и формы</a></td> 79 | <td></td> 80 | <td></td> 81 | <td></td> 82 | </tr> 83 | <tr> 84 | <td>9.</td> 85 | <td><a href="https://github.com/ancatmara/learnpython2018/blob/master/Lessons/Flask/9.%20Flask%20(1).ipynb">Веб-приложения: flask (1)</a></td> 86 | <td></td> 87 | <td></td> 88 | <td></td> 89 | </tr> 90 | <tr> 91 | <td>10.</td> 92 | <td><a href="https://github.com/ancatmara/learnpython2018/blob/master/Lessons/Flask/10.%20Flask%20(2)%20.ipynb">Веб-приложения: flask (2)</a></td> 93 | <td><a href="https://github.com/ancatmara/learnpython2018/blob/master/Homeworks/QuestionnaireHW.md"> Сайт-анкета </a></td> 94 | <td>2 декабря, 10:00</td> 95 | <td></td> 96 | </tr> 97 | <tr> 98 | <td>11.</td> 99 | <td><a href="https://github.com/ancatmara/learnpython2018/blob/master/Lessons/Matplotlib/11.%20Matplotlib.ipynb">Визуализация данных: matplotlib, ggplot, seaborn</a></td> 100 | <td></td> 101 | <td></td> 102 | <td></td> 103 | </tr> 104 | <tr> 105 | <td>12.</td> 106 | <td><a href="https://github.com/ancatmara/learnpython2018/blob/master/Lessons/%D0%91%D0%B0%D0%B7%D1%8B%20%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85/12.%20%D0%91%D0%B0%D0%B7%D1%8B%20%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85.ipynb">Базы данных: sqlite3</a></td> 107 | <td><a href="https://github.com/ancatmara/learnpython2018/blob/master/Homeworks/HW5.md">Поисковик для корпуса</a></td> 108 | <td>28 декабря, 10:00</td> 109 | <td></td> 110 | </tr> 111 | </table> 112 | 113 | 114 | ### План курса: 4 модуль 115 | №|Семинар|Домашнее задание|Дедлайн|Комментарий 116 | ---|---|---|---|--- 117 | 1.|[VK API (1)](./Lessons/VK%20API/14.%20VK%20API%20(1).ipynb)||| 118 | 2.|[VK API (2)](./Lessons/VK%20API/15.%20VK%20API%20(2).ipynb)|[HW6](./Homeworks/HW6.md)|См. в описании домашки| 119 | 3.|[word2vec](./Lessons/Word2vec)||| 120 | 4.|—|Необязательное домашнее задание: [flask & pymorphy](./Homeworks/AdditionalHW.md)|См. в описании домашки| 121 | 5.|[Сетевой анализ, NetworkX](./Lessons/%D0%93%D1%80%D0%B0%D1%84%D1%8B/%D0%93%D1%80%D0%B0%D1%84%D1%8B,%20networkx.ipynb)||| 122 | 6.||[NetworkX](./Homeworks/HW7.md)|| 123 | 7.|[Heroku](./Lessons/Heroku%20%D0%B8%20%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D0%BD%D0%B0%D1%8F%20%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B0/13a.%20Heroku.md)||| 124 | 8.|[Telegram-боты (1)](./Lessons/Telegram-%D0%B1%D0%BE%D1%82%D1%8B/TelegramBot1.ipynb)||| 125 | 9.|[Telegram-боты (2)](./Lessons/Telegram-%D0%B1%D0%BE%D1%82%D1%8B/TelegramBot2.ipynb)||| 126 | 127 | 128 | --------------------------------------------------------------------------------