Парсим контент для скрапера
После реализации функционала обхода ссылок на отдельные спортивные события (реализовано в методе get_items_params класса ItemsParser, подробнее здесь) рассмотрим способы сбора интересуемой нас информации. Предположим, мы скачиваем сведения о прошедших боях на турнирах, организованных спортивной организацией UFC (сайт www.ufcstats.com).
На первоначальном этапе требуется решить следующие задачи:
- определиться с перечнем данных, которые мы хотим собирать;
- установить конкретные пути их задания на веб-странице;
- определиться с методами скачивания (основной инструментарий - библиотека BeautifulSoup, подробнее здесь);
- выбрать форму промежуточного хранения полученной информации;
- выбрать способ долгосрочного хранения результатов сбора для их легкого объединения со сведениями из предыдущих закачек.
При помощи описанной ранее функции get_url_delay Закачаем в наш сценарий страницу с поединком следующего вида:
delay = 1
url = 'http://www.ufcstats.com/fight-details/524b49a676498c6d'
html = net_scrape.get_url_delay(delay=delay, url = url).text
bsObj = BeautifulSoup(html, 'lxml')
Проведем предварительное изучение тегов путем наведения на элементы курсора, нажатия правой кнопкой мыши и выбора "исследовать элемент" (браузер Mozilla Firefox):
В результате мы пришли к заключению, что
- название события содержится внутри тега 'a' со свойством 'class'='b-link';
- имена соперников - в тексте тегов 'h3' с 'class'='b-fight-details__person-name';
- а результаты - в тегах 'i' с классом 'class', начинающимся с 'b-fight-details__person-status'.
Во всех трех случаях сведения можно извлечь схожим образом - путем вызова find либо findAll (если несколько тегов), затем get_text для каждого результата и удаления пробелов strip (подробнее читай здесь):
Теперь закачаем информацию из уровня детализированных результатов поединка (вид победы, количество раундов, время...):
Как можно заметить, в этом случае нужные нам поля скрыты в тегах 'i', внутри которых располагается тег 'i' с полем 'class'='b-fight-details__label'. Сначала поэкспериментируем. Найдем в документе все теги 'i' с полем 'class'='b-fight-details__label', для каждого получим содержимое при помощи get_text (это будет название вида детализированного результата). Например:
f_det_res_tags = bsObj.findAll('i',{'class':'b-fight-details__label'})
Затем перейдем к родителю путем вызова свойства parent, получим содержимое всех его внутренних тегов при помощи get_text:
Очевидно, чтобы получить результат детализированного поля, нужно из содержимого родителя убрать содержимое дочернего поля и удалить пробельные символы. Соберем все вместе и итог представим в виде словаря:
f_det_res_tags = bsObj.findAll('i',{'class':'b-fight-details__label'})
det_res = {}
for i,f_det_res_tag in enumerate(f_det_res_tags):
key = f_det_res_tag.get_text().strip()
det_res[key] = f_det_res_tag.parent.get_text().strip().replace(key,'').strip()
Методику сбора остальных полей, а также способы сохранения результатов (пункты 4 и 5 вышеуказанного списка) обсудим позже.