{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Web-scraping: сбор данных из баз данных и интернет-источников\n", "\n", "*Алла Тамбовцева, НИУ ВШЭ*\n", "\n", "## Работа с API ВКонтакте: собираем информацию о друзьях" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Загружаем модули и библиотеки, необходимые для работы:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import requests\n", "import time\n", "import pandas as pd" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Добавляем токен доступа и версию API:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "token = \"a4265e3ff88bb0437aeb539d33f6cdf411ab1823a5bac597b3ee4a5e0401d828fac459cdaa929f4c00ee9\"\n", "v = \"5.131\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Задача 1\n", "\n", "Используя документацию API (раздел *Friends*), напишите код, который запросит информацию по друзьям пользователя с некоторым id. Пока достаточно базовой информации – количество друзей и их идентификаторы. Сохраните количество друзей в переменную `n`, а список идентификаторов – в переменную `ids`." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "main_friends = \"https://api.vk.com/method/friends.get\"\n", "\n", "# параметры – поиск по user_id\n", "params_friends = {\"access_token\" : token, \"v\" : v, \n", " \"user_id\" : 171544496}\n", "\n", "# как обычно – выгружаем результаты в формате JSON\n", "req = requests.get(main_friends, params = params_friends)\n", "json = req.json()" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "# извлекаем count и items\n", "n = json[\"response\"][\"count\"]\n", "ids = json[\"response\"][\"items\"] " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Задача 2\n", "\n", "Сохраните в переменную `i` первый элемент списка `ids`. Используя документацию API (раздел *Users*), напишите код, который запросит следующую информацию по этому пользователю:\n", "\n", "* id;\n", "* имя и фамилия;\n", "* дата рождения;\n", "* город проживания (только название);\n", "* родной город (только название);\n", "* университет (только название)." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "130896\n" ] } ], "source": [ "i = ids[0]\n", "print(i)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "# в main вписываем необходимый метод\n", "# в params добавляем запись с ключом fields\n", "# в fields перечисляем необходимые поля через запятую\n", "\n", "main = \"https://api.vk.com/method/users.get\"\n", "params = {\"access_token\" : token, \"v\" : v, \"user_id\" : i,\n", " \"fields\" : \"bdate,city,home_town,universities\"}\n", "req2 = requests.get(main, params = params)\n", "json2 = req2.json() " ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "# извлекаем результат (resp – список)\n", "# извлекаем пользователя (нулевой и единственный элемент в resp)\n", "\n", "resp = json2[\"response\"]\n", "user = resp[0]" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "# извлекаем значения из необходимых полей\n", "# поиск по ключам id, first_name и так далее\n", "\n", "id_ = user[\"id\"] \n", "first_name = user[\"first_name\"] \n", "last_name = user[\"last_name\"]\n", "bdate = user[\"bdate\"] \n", "home_town = user[\"home_town\"] \n", "\n", "# здесь интереснее – внутри словаря ещё словарь\n", "# извлекаем два раза, оба раза поиск по ключу\n", "\n", "city = user['city']['title'] \n", "\n", "# а здесь ещё интереснее – внутри словаря список\n", "# извлекаем из списка первый элемент, а уже\n", "# из него – запись по ключу name\n", "\n", "univ = user['universities'][0]['name'] " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Проверяем:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "130896 Егор Юрескул 29.9.1988 Оренбург Москва МГУ\n" ] } ], "source": [ "print(id_, first_name, last_name, bdate, home_town, city, univ) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Задача 3\n", "\n", "Напишите функцию `get_users()`, которая принимает на вход список id пользователей, а возвращает характеристики этих пользователей, перечисленные в задаче 2.\n", "\n", "**Подсказка:** метод для поиска информации по пользователям умеет принимать на вход более одного id за раз." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Сначала напишем вспомогательную функцию `one_user()`, которая будет извлекать необходимую информацию по одному пользователю (`user` – это просто словарь с данными одного пользователя):" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "def one_user(user):\n", " \n", " # извлекаем информацию более аккуратным способом\n", " # через метод .get() на словарях:\n", " # если записи с таким ключом нет, возвращается None,\n", " # мы не получаем KeyError\n", " \n", " id_ = user.get(\"id\")\n", " first_name = user.get(\"first_name\") \n", " last_name = user.get(\"last_name\")\n", " bdate = user.get(\"bdate\") \n", " home_town = user.get(\"home_town\") \n", " \n", " # пишем исключения, чтобы в случае отсутствия информации \n", " # по городу/университету не возникала ошибка,\n", " # а возвращалась пустая строка\n", " \n", " try:\n", " city_raw = user.get('city')\n", " city = city_raw.get('title') \n", " except:\n", " city = \"\"\n", " \n", " try:\n", " univ_raw = user.get('universities')\n", " univ = univ_raw[0]['name'] \n", " except:\n", " univ = \"\"\n", " \n", " return id_, first_name, last_name, bdate, home_town, city, univ" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Теперь пишем основную функцию `get_users()`:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "def get_users(user_ids):\n", " \n", " # user_ids – список из числовых id\n", " # каждый числовой id нужно превратить в текстовый – тип string\n", " # потом склеить список из текстовых id \n", " # в одну большую строку с разделителем «запятая»\n", " \n", " ids_str = [str(u) for u in user_ids] \n", " res = \",\".join(ids_str)\n", " \n", " # теперь в params в качестве user_ids\n", " # используем строку res со всеми id сразу\n", " \n", " main = \"https://api.vk.com/method/users.get\"\n", " params = {\"access_token\" : token, \"v\" : v, \"user_ids\" : res,\n", " \"fields\" : \"bdate,city,home_town,universities\"}\n", " req2 = requests.get(main, params = params)\n", " json2 = req2.json() \n", " resp = json2[\"response\"]\n", " \n", " # в resp сохранен список словарей\n", " # один словарь = один пользователь\n", " # вопользуемся one_user() и извлечем\n", " # из каждого словаря необходимые значения\n", " \n", " info = []\n", " \n", " for u in resp:\n", " r = one_user(u)\n", " info.append(r)\n", " \n", " return info" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Задача 4\n", "\n", "Примените функцию `get_users()` к пользователям из списка друзей `ids`, сохраните полученные результаты и оформите их в датафрейм." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " | 0 | \n", "1 | \n", "2 | \n", "3 | \n", "4 | \n", "5 | \n", "6 | \n", "
---|---|---|---|---|---|---|---|
0 | \n", "130896 | \n", "Егор | \n", "Юрескул | \n", "29.9.1988 | \n", "Оренбург | \n", "Москва | \n", "МГУ | \n", "
1 | \n", "251877 | \n", "Антон | \n", "Воробьев | \n", "26.3 | \n", "Москва | \n", "Москва | \n", "ГУ-ВШЭ | \n", "
2 | \n", "703151 | \n", "Елизавета | \n", "Ерохина | \n", "10.5.1989 | \n", "None | \n", "Москва | \n", "\n", " |
3 | \n", "762901 | \n", "Ярослав | \n", "Баяр | \n", "16.12.1988 | \n", "None | \n", "Москва | \n", "\n", " |
4 | \n", "822104 | \n", "Любовь | \n", "Сысоева | \n", "27.1 | \n", "None | \n", "Москва | \n", "\n", " |