Web-scraping: сбор данных из баз данных и интернет-источников

Алла Тамбовцева, НИУ ВШЭ

Работа с API ВКонтакте: собираем информацию о друзьях

Загружаем модули и библиотеки, необходимые для работы:

In [1]:
import requests
import time
import pandas as pd

Добавляем токен доступа и версию API:

In [2]:
token = "a4265e3ff88bb0437aeb539d33f6cdf411ab1823a5bac597b3ee4a5e0401d828fac459cdaa929f4c00ee9"
v = "5.131"

Задача 1

Используя документацию API (раздел Friends), напишите код, который запросит информацию по друзьям пользователя с некоторым id. Пока достаточно базовой информации – количество друзей и их идентификаторы. Сохраните количество друзей в переменную n, а список идентификаторов – в переменную ids.

In [3]:
main_friends = "https://api.vk.com/method/friends.get"

# параметры – поиск по user_id
params_friends = {"access_token" : token, "v" : v, 
                  "user_id" : 171544496}

# как обычно – выгружаем результаты в формате JSON
req = requests.get(main_friends, params = params_friends)
json = req.json()
In [4]:
# извлекаем count и items
n = json["response"]["count"]
ids = json["response"]["items"] 

Задача 2

Сохраните в переменную i первый элемент списка ids. Используя документацию API (раздел Users), напишите код, который запросит следующую информацию по этому пользователю:

  • id;
  • имя и фамилия;
  • дата рождения;
  • город проживания (только название);
  • родной город (только название);
  • университет (только название).
In [5]:
i = ids[0]
print(i)
130896
In [6]:
# в main вписываем необходимый метод
# в params добавляем запись с ключом fields
# в fields перечисляем необходимые поля через запятую

main = "https://api.vk.com/method/users.get"
params = {"access_token" : token, "v" : v, "user_id" : i,
         "fields" : "bdate,city,home_town,universities"}
req2 = requests.get(main, params = params)
json2 = req2.json() 
In [7]:
# извлекаем результат (resp – список)
# извлекаем пользователя (нулевой и единственный элемент в resp)

resp = json2["response"]
user = resp[0]
In [8]:
# извлекаем значения из необходимых полей
# поиск по ключам id, first_name и так далее

id_ = user["id"] 
first_name = user["first_name"] 
last_name = user["last_name"]
bdate = user["bdate"] 
home_town = user["home_town"] 

# здесь интереснее – внутри словаря ещё словарь
# извлекаем два раза, оба раза поиск по ключу

city = user['city']['title'] 

# а здесь ещё интереснее – внутри словаря список
# извлекаем из списка первый элемент, а уже
# из него – запись по ключу name

univ = user['universities'][0]['name'] 

Проверяем:

In [9]:
print(id_, first_name, last_name, bdate, home_town, city, univ) 
130896 Егор Юрескул 29.9.1988 Оренбург Москва МГУ

Задача 3

Напишите функцию get_users(), которая принимает на вход список id пользователей, а возвращает характеристики этих пользователей, перечисленные в задаче 2.

Подсказка: метод для поиска информации по пользователям умеет принимать на вход более одного id за раз.

Сначала напишем вспомогательную функцию one_user(), которая будет извлекать необходимую информацию по одному пользователю (user – это просто словарь с данными одного пользователя):

In [10]:
def one_user(user):
    
    # извлекаем информацию более аккуратным способом
    # через метод .get() на словарях:
    # если записи с таким ключом нет, возвращается None,
    # мы не получаем KeyError
    
    id_ = user.get("id")
    first_name = user.get("first_name") 
    last_name = user.get("last_name")
    bdate = user.get("bdate") 
    home_town = user.get("home_town") 
    
    # пишем исключения, чтобы в случае отсутствия информации 
    # по городу/университету не возникала ошибка,
    # а возвращалась пустая строка
    
    try:
        city_raw = user.get('city')
        city = city_raw.get('title') 
    except:
        city = ""
        
    try:
        univ_raw = user.get('universities')
        univ = univ_raw[0]['name'] 
    except:
        univ = ""
        
    return id_, first_name, last_name, bdate, home_town, city, univ

Теперь пишем основную функцию get_users():

In [11]:
def get_users(user_ids):
    
    # user_ids – список из числовых id
    # каждый  числовой id нужно превратить в текстовый – тип string
    # потом склеить список из текстовых id 
    # в одну большую строку с разделителем «запятая»
    
    ids_str = [str(u) for u in user_ids] 
    res = ",".join(ids_str)
    
    # теперь в params в качестве user_ids
    # используем строку res со всеми id сразу
    
    main = "https://api.vk.com/method/users.get"
    params = {"access_token" : token, "v" : v, "user_ids" : res,
              "fields" : "bdate,city,home_town,universities"}
    req2 = requests.get(main, params = params)
    json2 = req2.json() 
    resp = json2["response"]
    
    # в resp сохранен список словарей
    # один словарь = один пользователь
    # вопользуемся one_user() и извлечем
    # из каждого словаря необходимые значения
    
    info = []
    
    for u in resp:
        r = one_user(u)
        info.append(r)
    
    return info

Задача 4

Примените функцию get_users() к пользователям из списка друзей ids, сохраните полученные результаты и оформите их в датафрейм.

In [12]:
final = get_users(ids) 
dat = pd.DataFrame(final)
dat.head()
Out[12]:
0 1 2 3 4 5 6
0 130896 Егор Юрескул 29.9.1988 Оренбург Москва МГУ
1 251877 Антон Воробьев 26.3 Москва Москва ГУ-ВШЭ
2 703151 Елизавета Ерохина 10.5.1989 None Москва
3 762901 Ярослав Баяр 16.12.1988 None Москва
4 822104 Любовь Сысоева 27.1 None Москва
In [13]:
dat.columns = ["id", "name", "surname", "bdate", 
               "hometown", "city", "univ"]