Python для анализа данных

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

Работа с selenium: продолжение

Сегодня мы продолжим работать над задачей, поставленной на прошлом занятии ‒ выгрузка адресов всех участковых избирательных комиссий Ивановской области. Сначала загрузим все необходимые для работы библиотеки:

  • selenium ‒ для автоматизации работы в браузере
  • re ‒ для поиска адреса на странице с помощью регулярных выражений
  • time ‒ для добавления задержки
  • pandas ‒ для сохранения результатов в датафрейм
In [2]:
from selenium import webdriver as wb
br = wb.Chrome("/Users/allat/Downloads/chromedriver")

br.implicitly_wait(2)
In [3]:
import re
from time import sleep
import pandas as pd

Теперь напишем функцию get_uik_address(), которая принимает на вход два аргумента, номер участка и регион, и возвращает строку с адресом. Для этого в тело функции скопируем код с прошлого занятия:

In [7]:
def get_uik_address(n_uik, reg):
    
    br.get("http://www.cikrf.ru/services/lk_address/?do=find_by_uik")
    uik_field = br.find_element_by_css_selector("#uik")
    uik_field.send_keys(n_uik)
    
    region_field = br.find_element_by_name("subject")
    region_field.send_keys(reg)
    sleep(1.5) # еще добавим задержку в 1.5 секунды
    
    button = br.find_element_by_link_text("Отправить запрос")
    button.click()
    sleep(1.5) # еще добавим задержку в 1.5 секунды
    
    p = re.search(r"Адрес помещения для голосования: ([^<]+)", br.page_source)
    
    if p is None:
        
        p = re.search(r"Адрес: ([^<]+)", br.page_source)
    
    addr = p.group(1)
        
    return addr

Теперь попробуем взять несколько номеров участков и посмотреть, что получается в цикле. Только давайте перестрахуемся ‒ напишем выражение с исключением, чтобы в случае, если страница не содержит адреса или загружается некорректно, наш код не ломался и не происходило выхода из цикла. В случае, если все хорошо (адрес есть), Python будет его сохранять («ветка» c try), в случае, если все плохо (адреса нет ни в каком виде), Python будет записывать вместо него пустую строку (ветка с except) и двигаться дальше.

In [8]:
uiks = range(240, 245)
In [9]:
addresses = []

for u in uiks:
    try:
        address = get_uik_address(u, "Ивановская область")
    except:
        address = ""
    addresses.append(address)
    print(u, address)
240 
241 155330, Ивановская область, городской округ Вичуга, город Вичуга, улица Желябова, дом 6, здание МБОУ ООШ №6
242 155330, Ивановская область, городской округ Вичуга, город Вичуга, улица Ленинская, дом 26, здание МБУК "Клуб имени Шагова"
243 155330, Ивановская область, городской округ Вичуга, город Вичуга, улица Ленинская, дом 26, здание МБУК "Клуб имени Шагова"
244 155800, Ивановская область, городской округ Кинешма, город Кинешма, улица Григория Королева, дом 10, здание "Кинешемский политехнический колледж"

Работает! Создадим список со всеми номерами избирательных участков Ивановской области:

In [6]:
ivanovo = range(1, 777) # вроде все, см здесь новый список - http://www.ivanovo.izbirkom.ru/docs/4272/

Внимание: исполнение следующей ячейки займет много времени (примерно полтора часа). Если просто хотите посмотреть, как это работает (не выгружая информацию по всем участкам), уменьшите правое значение в range() в строчке выше.

In [7]:
ivanovo_addr = []

for i in ivanovo:
    try:
        address = get_uik_address(i, "Ивановская область")
    except:
        address = ""
    ivanovo_addr.append(address)

Важно: периодически открывайте окно браузера, в котором Python ищет избирательные участки! Это не только приятно (смотреть, как в полях для поиска все заполняется без нашего участия), но и полезно: так можно заметить, если что-то пошло не так. История из жизни: опечаталась в букве внутри цикла, Python 777 раз открыл страницу с избирательным участком 244 и сохранил одинаковые адреса.

Создадим датафрейм из словаря, ключами которого служат названия столбцов таблицы, а значениями – списки элементов этих столбцов.

In [9]:
df = pd.DataFrame({'uik': ivanovo, 'address': ivanovo_addr})
In [10]:
df.head()
Out[10]:
address uik
0 153000, Ивановская область, городской округ Ив... 1
1 153000, Ивановская область, городской округ Ив... 2
2 153000, Ивановская область, городской округ Ив... 3
3 153000, Ивановская область, городской округ Ив... 4
4 153000, Ивановская область, городской округ Ив... 5
In [13]:
list(df.address)[0:10]
Out[13]:
['153000, Ивановская область, городской округ Иваново, город Иваново, Ленинский район, проспект Шереметевский, дом 8, здание ФГБОУ ВО "Ивановская государственная медицинская академия" Министерства здравоохранения Российской Федерации',
 '153000, Ивановская область, городской округ Иваново, город Иваново, Ленинский район, проспект Шереметевский, дом 10, здание ФГБОУ ВО "Ивановский государственный химико-технологический университет"',
 '153000, Ивановская область, городской округ Иваново, город Иваново, Ленинский район, проспект Шереметевский, дом 21, здание Текстильного института ФГБОУ ВО "Ивановский государственный политехнический университет"',
 '153000, Ивановская область, городской округ Иваново, город Иваново, Ленинский район, улица Арсения, дом 33/16, здание МАОУ лицей № 21',
 '153000, Ивановская область, городской округ Иваново, город Иваново, Ленинский район, улица Арсения, дом 33/16, здание МАОУ лицей № 21',
 '153000, Ивановская область, городской округ Иваново, город Иваново, Ленинский район, улица Сакко, дом 45, здание Культурно-спортивный центр',
 '153000, Ивановская область, городской округ Иваново, город Иваново, Ленинский район, улица Колотилова, дом 43, здание МБУ ДО Дом детского творчества № 3',
 '153012, Ивановская область, городской округ Иваново, город Иваново, Ленинский район, улица Суворова, дом 72, здание МБУ ДО "Центр развития детской одаренности"',
 '153000, Ивановская область, городской округ Иваново, город Иваново, Ленинский район, улица Бубнова, дом 49, здание Центральная городская библиотека им. Я.П. Гарелина',
 '153000, Ивановская область, городской округ Иваново, город Иваново, Ленинский район, улица Смирнова, дом 103, здание МБОУ "Средняя школа № 53"']

Сохраним таблицу в csv-файл:

In [14]:
df.to_csv('Ivanovo.csv')