February 4, 2021

Парсим контент для скрапера

После реализации функционала обхода ссылок на отдельные спортивные события (реализовано в методе get_items_params класса ItemsParser, подробнее здесь)  рассмотрим способы сбора интересуемой нас информации. Предположим, мы  скачиваем сведения о прошедших боях на турнирах, организованных  спортивной организацией UFC (сайт www.ufcstats.com).

На первоначальном этапе требуется решить следующие задачи:

  1. определиться с перечнем данных, которые мы хотим собирать;
  2. установить конкретные пути их задания на веб-странице;
  3. определиться с методами скачивания (основной инструментарий - библиотека BeautifulSoup, подробнее здесь);
  4. выбрать форму промежуточного хранения полученной информации;
  5. выбрать способ долгосрочного хранения результатов сбора для их легкого объединения со сведениями из предыдущих закачек.

При помощи описанной ранее функции 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  вышеуказанного списка) обсудим позже.