{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Python для анализа данных\n", "\n", "*Алла Тамбовцева, НИУ ВШЭ*\n", "\n", "### Работа с `selenium`: продолжение" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Сегодня мы продолжим работать над задачей, поставленной на прошлом занятии ‒ выгрузка адресов всех участковых избирательных комиссий Ивановской области. Сначала загрузим все необходимые для работы библиотеки:\n", "\n", "* `selenium` ‒ для автоматизации работы в браузере\n", "* `re` ‒ для поиска адреса на странице с помощью регулярных выражений \n", "* `time` ‒ для добавления задержки\n", "* `pandas` ‒ для сохранения результатов в датафрейм" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "from selenium import webdriver as wb\n", "br = wb.Chrome(\"/Users/allat/Downloads/chromedriver\")\n", "\n", "br.implicitly_wait(2)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "import re\n", "from time import sleep\n", "import pandas as pd" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Теперь напишем функцию `get_uik_address()`, которая принимает на вход два аргумента, номер участка и регион, и возвращает строку с адресом. Для этого в тело функции скопируем код с прошлого занятия:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "def get_uik_address(n_uik, reg):\n", " \n", " br.get(\"http://www.cikrf.ru/services/lk_address/?do=find_by_uik\")\n", " uik_field = br.find_element_by_css_selector(\"#uik\")\n", " uik_field.send_keys(n_uik)\n", " \n", " region_field = br.find_element_by_name(\"subject\")\n", " region_field.send_keys(reg)\n", " sleep(1.5) # еще добавим задержку в 1.5 секунды\n", " \n", " button = br.find_element_by_link_text(\"Отправить запрос\")\n", " button.click()\n", " sleep(1.5) # еще добавим задержку в 1.5 секунды\n", " \n", " p = re.search(r\"Адрес помещения для голосования: ([^<]+)\", br.page_source)\n", " \n", " if p is None:\n", " \n", " p = re.search(r\"Адрес: ([^<]+)\", br.page_source)\n", " \n", " addr = p.group(1)\n", " \n", " return addr" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Теперь попробуем взять несколько номеров участков и посмотреть, что получается в цикле. Только давайте перестрахуемся ‒ напишем выражение с исключением, чтобы в случае, если страница не содержит адреса или загружается некорректно, наш код не ломался и не происходило выхода из цикла. В случае, если все хорошо (адрес есть), Python будет его сохранять («ветка» c `try`), в случае, если все плохо (адреса нет ни в каком виде), Python будет записывать вместо него пустую строку (ветка с `except`) и двигаться дальше. " ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "uiks = range(240, 245)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "240 \n", "241 155330, Ивановская область, городской округ Вичуга, город Вичуга, улица Желябова, дом 6, здание МБОУ ООШ №6\n", "242 155330, Ивановская область, городской округ Вичуга, город Вичуга, улица Ленинская, дом 26, здание МБУК \"Клуб имени Шагова\"\n", "243 155330, Ивановская область, городской округ Вичуга, город Вичуга, улица Ленинская, дом 26, здание МБУК \"Клуб имени Шагова\"\n", "244 155800, Ивановская область, городской округ Кинешма, город Кинешма, улица Григория Королева, дом 10, здание \"Кинешемский политехнический колледж\"\n" ] } ], "source": [ "addresses = []\n", "\n", "for u in uiks:\n", " try:\n", " address = get_uik_address(u, \"Ивановская область\")\n", " except:\n", " address = \"\"\n", " addresses.append(address)\n", " print(u, address)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Работает! Создадим список со всеми номерами избирательных участков Ивановской области:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "ivanovo = range(1, 777) # вроде все, см здесь новый список - http://www.ivanovo.izbirkom.ru/docs/4272/" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Внимание:** исполнение следующей ячейки займет много времени (примерно полтора часа). Если просто хотите посмотреть, как это работает (не выгружая информацию по всем участкам), уменьшите правое значение в `range()` в строчке выше." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "ivanovo_addr = []\n", "\n", "for i in ivanovo:\n", " try:\n", " address = get_uik_address(i, \"Ивановская область\")\n", " except:\n", " address = \"\"\n", " ivanovo_addr.append(address)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Важно:** периодически открывайте окно браузера, в котором Python ищет избирательные участки! Это не только приятно (смотреть, как в полях для поиска все заполняется без нашего участия), но и полезно: так можно заметить, если что-то пошло не так. История из жизни: опечаталась в букве внутри цикла, Python 777 раз открыл страницу с избирательным участком 244 и сохранил одинаковые адреса. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Создадим датафрейм из словаря, ключами которого служат названия столбцов таблицы, а значениями – списки элементов этих столбцов." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "df = pd.DataFrame({'uik': ivanovo, 'address': ivanovo_addr})" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " | address | \n", "uik | \n", "
---|---|---|
0 | \n", "153000, Ивановская область, городской округ Ив... | \n", "1 | \n", "
1 | \n", "153000, Ивановская область, городской округ Ив... | \n", "2 | \n", "
2 | \n", "153000, Ивановская область, городской округ Ив... | \n", "3 | \n", "
3 | \n", "153000, Ивановская область, городской округ Ив... | \n", "4 | \n", "
4 | \n", "153000, Ивановская область, городской округ Ив... | \n", "5 | \n", "