{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Основы программирования в Python\n", "\n", "*Алла Тамбовцева, НИУ ВШЭ*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Работа с API: пример с API ВКонтакте" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Сегодня мы немного поработаем с API. API ‒ программный интерфейс приложения, сокращение от *Application Programming Interface*. Этот интерфейс позволяет выполнять различные операции автоматически, через приложение. Если API нам нужен исключительно как источник данных, можно писать запросы, позволяющие обратиться к хранилищу информации внутри API. Если мы хотим управлять приложением, которое будет выполнять какие-то действия, удаленно, можно написать код, который будет, например, автоматически отвечать на сообщения, когда мы не онлайн, лайкать новый пост друга через 30 секунд после его появления, пересылать на почту фотографии, которые выложили участники диалога и прочее.\n", "\n", "Мы будем работать с API социальной сети ВКонтакте. Использовать API для написания и приема сообщений средствами Python мы не будем, а рассмотрим API как источник данных, позволяющий выгрузить все посты со стены пользователя или сообщества. Для работы нам понадобится библиотека `vk`, ее нужно установить через `pip install vk` в *Anaconda Command Prompt* (см. пример с `selenium` [здесь](https://nbviewer.jupyter.org/github/allatambov/Py-programming-3/blob/master/11-06/lect-selenium1.ipynb)).\n", "\n", "Импортируем библиотеку:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import vk" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Теперь нужно авторизоваться: создать приложение и получить токен доступа к нему." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Для авторизации:\n", " \n", "1. [Создать](https://vk.com/apps?act=manage) приложение ВКонтакте (пройти по ссылке). Дать название, выбрать *Standalone-приложение*.\n", "2. Включить приложение, сделать публичным (*Настройки - Состояние* и выбрать в выпадающем меню *Приложение включено и видно всем*).\n", "3. Авторизоваться: скопировать строку ниже в браузер, в `client id` вместо 1 выставить `id` своего приложения (первая строка в настроках ‒ *ID приложения*). Если не хочется ни в чем ограничивать свое приложение, можно оставить `scope=all` (у приложения будет доступ ко всему, к чему есть доступ у пользователя).\n", "\n", " > ```https://oauth.vk.com/authorize?client_id=1&display=page&redirect_uri=http://oauth.vk.com/blank.html&scope=all&response_type=token```\n", "\n", "4. Скопировать `access token` из обновленной адресной строки (все после `access_token=` и до `&expires_in`, без `&`). Никому не показывать! По этому токену можно получить доступ ко всему аккаунту." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "# скопировать свой access token без пробелов вместо 1234\n", "token = '1234'" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "session = vk.Session(access_token = token) # открыть сессию для работы\n", "api = vk.API(session) # подключиться к API" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Попробуем сгрузить первые 100 постов со [стены](https://vk.com/hseofficial) неофициального сообщества ВШЭ. Сохраним ссылку на сообщество в переменную `group`:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "group = 'hseofficial'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Обратите внимание: ссылка должна быть относительной, то есть без части с `https:/vk.com/`. Python и так будет знать, что мы работаем с сетью ВКонтакте." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Теперь получим доступ к стене этого сообщества:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "# wall.get - \"подключаемся\" к стене\n", "# count - сколько постов выгрузить (максимум)\n", "# v - версия API, можно обойтись без нее, но Python может выдать warning\n", "\n", "res = api.wall.get(domain = group, count = 100, v = 5.73)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "res" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Результат, сохраненный в `res`, очень похож на словарь. На самом деле, многие API возвращают результаты в формате JSON (JavaScript Object Notation), который тоже может быть представлен в виде набора пар ключ-значение." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "dict_keys(['count', 'items'])" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "res.keys()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ключами являются `count` и `items`. Нужные нам объекты (текст постов, id автора, дата и время публикации и проч.) находятся в `items`." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'comments': {'can_post': 0, 'count': 0, 'groups_can_post': True},\n", " 'copy_history': [{'attachments': [{'photo': {'access_key': 'dd5969ed596f9c609c',\n", " 'album_id': -7,\n", " 'date': 1527671074,\n", " 'height': 1067,\n", " 'id': 456239082,\n", " 'owner_id': -40176496,\n", " 'photo_1280': 'https://pp.userapi.com/c834402/v834402946/14ed99/Yx1LEJ8gOIo.jpg',\n", " 'photo_130': 'https://pp.userapi.com/c834402/v834402946/14ed96/F2wCFaAhPkI.jpg',\n", " 'photo_2560': 'https://pp.userapi.com/c834402/v834402946/14ed9a/-aMToQjO9XI.jpg',\n", " 'photo_604': 'https://pp.userapi.com/c834402/v834402946/14ed97/OfYh831fPiU.jpg',\n", " 'photo_75': 'https://pp.userapi.com/c834402/v834402946/14ed95/ilhUXWnEe18.jpg',\n", " 'photo_807': 'https://pp.userapi.com/c834402/v834402946/14ed98/z7mHcsrn1jI.jpg',\n", " 'post_id': 386,\n", " 'text': '',\n", " 'user_id': 100,\n", " 'width': 1600},\n", " 'type': 'photo'},\n", " {'link': {'description': 'Национальный исследовательский университет «Высшая школа экономики» (НИУ ВШЭ) — один из крупнейших университетов России. Федеральное государственное высшее учебное заведение, созданное в 1992 году',\n", " 'photo': {'album_id': -2,\n", " 'date': 1527568906,\n", " 'height': 78,\n", " 'id': 456240905,\n", " 'owner_id': 100,\n", " 'photo_130': 'https://pp.userapi.com/c831208/v831208779/110e52/V-2J6_6FP5A.jpg',\n", " 'photo_604': 'https://pp.userapi.com/c831208/v831208779/110e53/sSIzzE8-EVY.jpg',\n", " 'photo_75': 'https://pp.userapi.com/c831208/v831208779/110e51/0rOCJV3_gwY.jpg',\n", " 'text': '',\n", " 'width': 150},\n", " 'target': 'internal',\n", " 'title': 'Национальный исследовательский университет «Высшая школа экономики»',\n", " 'url': 'http://hse.ru/#rec47720192'},\n", " 'type': 'link'}],\n", " 'date': 1527671074,\n", " 'from_id': -40176496,\n", " 'id': 386,\n", " 'owner_id': -40176496,\n", " 'post_source': {'type': 'vk'},\n", " 'post_type': 'post',\n", " 'text': '#ДеньОткрытыхДверей в #ModaHSE!☺📣 \\n👍Fashion show ради лайка? Правда? \\n31 мая приходите на нашу открытую лекцию про инсайды мировых подиумов и узнайте, зачем модные бренды до сих пор делают дорогие показы. \\n \\n\\U0001f5a4Полина Никонова, продюсер специальных модных событий в Нью-Йорке, поделится инсайдами индустрии модных показов: \\n✅Зачем дизайнеры до сих пор проводят показы и откажутся ли они от них в будущем \\n✅Как технологии изменили традиционные недели моды, а яркое шоу стало важнее самой коллекции \\n✅Сколько времени уходит на подготовку 15-минутного показа и сколько это стоит \\n \\n📝В числе проектов Полины: Yeezy Kanye West, Philipp Plein, \\nMoncler, Thom Browne, Tiffany,Scotch&Soda,Prabal Gurung,Adidas, \\nOpenning Ceremony,Four Seasons и др. \\n \\n☺☕После лекции вы также сможете познакомиться с руководителями образовательных программ ModaHSE и разузнать все подробности об учебе у нас.. \\n \\n🕢Начало лекции в 18.30 \\n📍Ждем вас 31 мая по адресу метро Тверская/Пушкинская, \\n Малый Гнездниковский переулок, 4, ауд 101. \\n \\nРегистрация на лекцию 👉http://moda.hse.ru/#rec47720192'}],\n", " 'date': 1527716601,\n", " 'from_id': -132,\n", " 'id': 32053,\n", " 'likes': {'can_like': 1, 'can_publish': 1, 'count': 7, 'user_likes': 0},\n", " 'marked_as_ads': 0,\n", " 'owner_id': -132,\n", " 'post_source': {'type': 'vk'},\n", " 'post_type': 'post',\n", " 'reposts': {'count': 0, 'user_reposted': 0},\n", " 'text': '',\n", " 'views': {'count': 5579}}" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "res['items'][0] # первый элемент items - первый пост со всей информацией о нем" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Помимо текста поста можно найти много всего интересного. Например, тип поста (`post_type`), дата (`date`), id поста (`id`), лайки (`likes`, которые включают информацию о том, могут ли пользователи лайкать пост и публиковать его, а также собственно число лайков), репосты (`reposts`, которые включают число репостов), число просмотров (`views`), комментарии (`comments`, которые включают информацию о том, могут ли пользователи комментировать пост, и число комментариев), и так далее." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Давайте остановимся на тексте поста, id автора, id поста и дате публикации. Чтобы извлечь соответствующую информацию, сохраним `items` и извлечем из них нужные поля:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "items = res['items']" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "full_list = []\n", "\n", "for item in items:\n", " l = [item['from_id'], item['id'], item['text'], item['date']] # нужные поля\n", " full_list.append(l) # добавляем в список списков full_list" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[[-132, 32053, '', 1527716601],\n", " [-132, 32052, '', 1527716594],\n", " [-132,\n", " 32051,\n", " 'Компания КРОК приглашает:\\nПривет! Этим летом тебя ждёт IT-жара! \\nУспей подать заявку в «Летние школы» КРОК, чтобы не пропустить полезный нетворкинг, получить новые знания и опыт работы с одной из крупнейших IT-компаний в России. \\nНаправления подготовки: \\n• разработка программного обеспечения с 9 по 20 июля \\n• телекоммуникации с 2 по 13 июля \\n• построение IT-инфраструктуры современных компаний с 16 по 27 июля \\n• разработка многомерного хранилища данных с 15 по 29 июля, с 6 по 20 августа \\nКто может принять участие? Студенты 2-6 курсов технических вузов. \\nСрок обучения: 2-3 недели (в июле – августе). \\nГде? В офисе КРОК в Москве (м. Площадь Ильича/ Римская, ул. Волочаевская, д. 5, корп. 1) \\nПрием заявок: до 20 июня 2018 г. \\nВажно! Участие бесплатное. \\nУзнать более детальную информацию о программе и зарегистрироваться ты можешь по ссылке. http://www.croc.ru/vacancy/students/detail/79855/\\nДо встречи!',\n", " 1527538730]]" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# несколько элементов списка\n", "full_list[0:3]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Видно, что в двух первых постах текста не обнаружено, там только картинки и перепосты. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Из этого списка списков можно легко сделать датафрейм `pandas`. Но прежде посмотрим, как сгрузить следующие 100 (и не только 100) постов со стены. Обычно при работе с API нужно принимать во внимание две вещи: 1) какое ограничение стоит на число запросов за один раз (число постов в нашем случае); 2) какое ограничение стоит на число запросов в минуту. Чтобы действовать в соответствии с этими ограничениями, поступим так: будем грузить каждые следующие 100 постов, добавлять их к нашему списку, потом немного ждать, и грузить еще 100 постов, и так до тех пор, пока не сгрузим желаемое количество.\n", "\n", "Давайте для начала выберем это желаемое число постов. Пусть будет 400. " ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "nposts = 400" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Теперь вопрос: по каким значениям нужно \"пробегаться\" в цикле, чтобы сгрузить посты с 100 по 400 (первые 100 уже сохранены в `res`)? По целым значениям от 2 до 4 включительно, умножая эти значения на 100. В `vk.get` есть опция `offset`. Она позволяет \"сдвинуть\" начало отсчета постов на некоторое число. Так, если мы напишем `api.wall.get(domain = group, count = 100, offset = 100, v = 5.73)`, мы получим посты с 100 по 200, так как начало отсчета сдвинулось на 100." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Реализуем описанное выше. Для цикла нам понадобится `range()`, а для задержки после выгрузки каждой сотни постов нам пригодится функция `sleep`: " ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": [ "from time import sleep" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "for i in range(2, int(nposts/100) + 1):\n", " res2 = api.wall.get(domain = group, count = 100, offset = 100 * i, v = 5.73)\n", " items2 = res2['items']\n", " items.extend(items2) # добавляем к первой сотне постов в items\n", " sleep(10)" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [], "source": [ "# опять выберем только нужные поля\n", "full_list = []\n", "for item in items:\n", " l = [item['from_id'], item['id'], item['text'], item['date']]\n", " full_list.append(l)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Оставлось превратить обновленный список `items` (список списков) в датафрейм. Импортируем `pandas`." ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [], "source": [ "import pandas as pd" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Создадим датафрейм:" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [], "source": [ "df = pd.DataFrame(full_list)" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
0123
0-132320531527716601
1-132320521527716594
2-13232051Компания КРОК приглашает:\\nПривет! Этим летом ...1527538730
3-13232050Сбываются мечты Е.Г.Ясина. Вышка выращивает не...1527080728
4-132320491527078739
5-132320481527078368
6-13232047Павел Алферов, Дмитрий Маев, Valery Anshin, Ни...1527078310
7-132320461526849884
8-132320451525030127
9-13232044Вакансия для студентов Вышки от коллег из ADID...1524946182
\n", "
" ], "text/plain": [ " 0 1 2 3\n", "0 -132 32053 1527716601\n", "1 -132 32052 1527716594\n", "2 -132 32051 Компания КРОК приглашает:\\nПривет! Этим летом ... 1527538730\n", "3 -132 32050 Сбываются мечты Е.Г.Ясина. Вышка выращивает не... 1527080728\n", "4 -132 32049 1527078739\n", "5 -132 32048 1527078368\n", "6 -132 32047 Павел Алферов, Дмитрий Маев, Valery Anshin, Ни... 1527078310\n", "7 -132 32046 1526849884\n", "8 -132 32045 1525030127\n", "9 -132 32044 Вакансия для студентов Вышки от коллег из ADID... 1524946182" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.head(10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ура! Осталось только дать внятные названия столбцам и разобраться, почему дата представлена в таком виде. что делать со столбцами, мы уже знаем." ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
from_ididtextdate
0-132320531527716601
1-132320521527716594
2-13232051Компания КРОК приглашает:\\nПривет! Этим летом ...1527538730
3-13232050Сбываются мечты Е.Г.Ясина. Вышка выращивает не...1527080728
4-132320491527078739
5-132320481527078368
6-13232047Павел Алферов, Дмитрий Маев, Valery Anshin, Ни...1527078310
7-132320461526849884
8-132320451525030127
9-13232044Вакансия для студентов Вышки от коллег из ADID...1524946182
\n", "
" ], "text/plain": [ " from_id id text \\\n", "0 -132 32053 \n", "1 -132 32052 \n", "2 -132 32051 Компания КРОК приглашает:\\nПривет! Этим летом ... \n", "3 -132 32050 Сбываются мечты Е.Г.Ясина. Вышка выращивает не... \n", "4 -132 32049 \n", "5 -132 32048 \n", "6 -132 32047 Павел Алферов, Дмитрий Маев, Valery Anshin, Ни... \n", "7 -132 32046 \n", "8 -132 32045 \n", "9 -132 32044 Вакансия для студентов Вышки от коллег из ADID... \n", "\n", " date \n", "0 1527716601 \n", "1 1527716594 \n", "2 1527538730 \n", "3 1527080728 \n", "4 1527078739 \n", "5 1527078368 \n", "6 1527078310 \n", "7 1526849884 \n", "8 1525030127 \n", "9 1524946182 " ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.columns = ['from_id', 'id', 'text', 'date']\n", "df.head(10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "С датой все интереснее. То, что указано в столбце `date`, это дата в виде UNIX-времени (POSIX-времени). Это число секунд, прошедших с 1 января 1970 года. Несмотря на то, что такой формат даты-времени кажется необычным, он довольно широко распространен в разных системах и приложениях (см. подробнее [здесь](https://ru.wikipedia.org/wiki/Unix-%D0%B2%D1%80%D0%B5%D0%BC%D1%8F)). Этот факт, конечно, радует, но хочется получить дату в более человеческом формате. Давайте напишем функцию для перевода UNIX-времени в формат *год-месяц-день-часы-минуты-секунды*. Для этого нам понадобится модуль *datetime*." ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [], "source": [ "from datetime import datetime" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [], "source": [ "def date_norm(date):\n", " d = datetime.fromtimestamp(date) # timestamp - UNIX-время в виде строки\n", " str_d = d.strftime(\"%Y-%m-%d %H:%M:%S\") # %Y-%m-%d %H:%M:%S - год-месяц-день, часы:минуты:секунды\n", " date_norm, time_norm = str_d.split(' ') # разобьем результат на части, отделим дату от времени\n", " return date_norm, time_norm" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Применим нашу функцию к элементам столбца *date* и создадим новый ‒ *date_norm*." ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [], "source": [ "df['date_norm'] = df.date.apply(date_norm)" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
from_ididtextdatedate_norm
0-132320531527716601(2018-05-31, 00:43:21)
1-132320521527716594(2018-05-31, 00:43:14)
2-13232051Компания КРОК приглашает:\\nПривет! Этим летом ...1527538730(2018-05-28, 23:18:50)
3-13232050Сбываются мечты Е.Г.Ясина. Вышка выращивает не...1527080728(2018-05-23, 16:05:28)
4-132320491527078739(2018-05-23, 15:32:19)
\n", "
" ], "text/plain": [ " from_id id text \\\n", "0 -132 32053 \n", "1 -132 32052 \n", "2 -132 32051 Компания КРОК приглашает:\\nПривет! Этим летом ... \n", "3 -132 32050 Сбываются мечты Е.Г.Ясина. Вышка выращивает не... \n", "4 -132 32049 \n", "\n", " date date_norm \n", "0 1527716601 (2018-05-31, 00:43:21) \n", "1 1527716594 (2018-05-31, 00:43:14) \n", "2 1527538730 (2018-05-28, 23:18:50) \n", "3 1527080728 (2018-05-23, 16:05:28) \n", "4 1527078739 (2018-05-23, 15:32:19) " ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Можно было, конечно, не разбивать на части дату и время, сохранять одной строкой. А можно написать функции, которые будут отделять дату от времени ‒ извлекать их из кортежа в `date_norm`." ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [], "source": [ "def get_date(date):\n", " return date[0]\n", "\n", "def get_time(date):\n", " return date[1]" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [], "source": [ "df['Date'] = df.date_norm.apply(get_date)\n", "df['Time'] = df.date_norm.apply(get_time)" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
from_ididtextdatedate_normDateTime
0-132320531527716601(2018-05-31, 00:43:21)2018-05-3100:43:21
1-132320521527716594(2018-05-31, 00:43:14)2018-05-3100:43:14
2-13232051Компания КРОК приглашает:\\nПривет! Этим летом ...1527538730(2018-05-28, 23:18:50)2018-05-2823:18:50
3-13232050Сбываются мечты Е.Г.Ясина. Вышка выращивает не...1527080728(2018-05-23, 16:05:28)2018-05-2316:05:28
4-132320491527078739(2018-05-23, 15:32:19)2018-05-2315:32:19
\n", "
" ], "text/plain": [ " from_id id text \\\n", "0 -132 32053 \n", "1 -132 32052 \n", "2 -132 32051 Компания КРОК приглашает:\\nПривет! Этим летом ... \n", "3 -132 32050 Сбываются мечты Е.Г.Ясина. Вышка выращивает не... \n", "4 -132 32049 \n", "\n", " date date_norm Date Time \n", "0 1527716601 (2018-05-31, 00:43:21) 2018-05-31 00:43:21 \n", "1 1527716594 (2018-05-31, 00:43:14) 2018-05-31 00:43:14 \n", "2 1527538730 (2018-05-28, 23:18:50) 2018-05-28 23:18:50 \n", "3 1527080728 (2018-05-23, 16:05:28) 2018-05-23 16:05:28 \n", "4 1527078739 (2018-05-23, 15:32:19) 2018-05-23 15:32:19 " ] }, "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Всё! Материалы о разных методах и функциях для `vk.api` можно найти в [официальной документации](https://vk.com/dev/manuals). " ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.5.2" } }, "nbformat": 4, "nbformat_minor": 2 }