Время прочтения: 7 мин.

Перед группой программистов была поставлена задача создать сервис для накопления информации об упоминании публичных персон в новостных интернет-порталах (далее сервис):

Что должен видеть пользователь сервиса: интернет ресурс, на котором можно запустить «Просмотр общей статистики».

В результате запуска отображается информация в виде таблицы с полями: «Имя персоны», «Количество упоминаний», «Название статей, Даты статьи».

На основе полученного задания было решено реализовать сервис, состоящий из следующих компонент:

Также пользователь может запустить просмотр /поиск статистики по конкретной персоне.

Таким образом, если информация по запросу на поиск пользователя уже имеется в базе данных, то ответ будет сформирован сразу и выведен в составе «Просмотра общей статистики», если же информация по запросу в базе данных  отсутствует, то будет сформировано задание для crawler, обработанная информация с которого будет занесена в базу данных, откуда и будет сформирован ответ пользователю.  


[1] crawler (обходчик) — служба, которая по определенному расписанию, или принудительно, обращается к сайтам в интернете. Анализирует их на наличие новых страниц. Загружает новые страницы, после чего обрабатывает контент новой страницы. Результаты обработки и ссылку на новую страницу записывает в Базу Данных. Результатом обработки является количество упоминаний имен политиков на странице сайта.

Наша группа разделилась на 2 большие подгруппы:

  • программирование сервиса на  Java;
  • программирование сервиса на Python.

Далее внутри групп было произведено деление по программированию компонент.

Группе, в которую попал и я, была поручена разработка crawler на Python и пробный новостной сайт “lenta.ru”.

Для поиска данных на html страницах web сайтов можно использовать различные библиотеки Python, например:  Scrapy, Selenium, Beautiful Soup.

Scrapy — это готовая платформа для поиска данных с веб-сайтов, которая работает без блокировки отправленных запросов, самая быстрая и надежная, особенно при создании сложных проектов.

Selenium используется для тестирования веб-приложений.

Beautiful Soup — быстро извлекает данные из скачанных (локальных или в память компьютера) файлов HTML и XML.

Выбрана была библиотека Beautiful Soup вследствие не высокой сложности нашего проекта.

Установим Beautiful Soup на компьютер:

pip3 install bs4  - для Windows;
sudo pip3 install bs4  – для Ubuntu, Centos.

В отличии от Scrappy,  Beautiful Soup не может напрямую просматривать страницы Web сайтов, поэтому еще необходимо поставить библиотеку requests, которая работает с http – запросами:

pip3 install requests - для Windows;
sudo pip3 install requests – для Ubuntu, Centos.

По заданию на вход crawler должны быть поданы следующие параметры: персона, дата статей, на выходе название статей, количество упоминаний персоны. По входным и выходным данным в базу будут произведены записи: дата найденных статей, персона, название статей, количество упоминаний персоны.

Разделим наше задание на несколько этапов:

  1. Определение страниц/разделов в lenta.ru, в которых будет производится поиск статей;
  2. Открытие указанных страниц/разделов в lenta.ru за конкретную дату;
  3. Получение данных с указанных страниц/разделов в lenta.ru;
  4. Формализация данных поиска (персоны и даты);
  5. Поиск персоны в статьях с указанных страниц/разделов в lenta.ru за конкретную дату;
  6. Передача данных в базу данных сервиса в json — формате {‘гиперссылка на статью’: Количество упоминаний}.

Определение страниц/разделов в lenta.ru, в которых будет производится поиск статей.

Любой серьезный сайт публикует карту своего сайта в файле robots.txt, для того чтобы было видно куда разрешено роботам спокойно заходить и смотреть страницы и/или указать файл карты сайта. Обычно это sitemap.xml или sitemap.xml.gz

У новостного сайта lenta.ru карта сайта описана в файле https://lenta.ru/sitemap.xml.gz

Проведя анализ данного файла, был сделан вывод: основные папки статей: news, articles.

Открытие указанных страниц/разделов в lenta.ru за конкретную дату

Пример кода открытия страницы с помощью requests:

import requests                                                                                                
year = “2018”
may = “06”
day = “28”
main_url = 'https://lenta.ru' 
them = 'news'
url = "%s/%s/%s/%s/%s/" % (main_url, them, year, may, day)
r = requests.get(url)
page = r.text
print(page)

(в блоках добавлена функция print (), чтобы можно было увидеть результат работы кода)

Так как страниц/разделов может быть несколько, немного модифицируем наш код (этот код используйте только в составе класса[1])

import requests                                                                                                
year = “2018”
may = “06”
day = “28”
main_url = 'https://lenta.ru' 
thems = ('news', 'articles')
for them in thems:
    url = "%s/%s/%s/%s/%s/" % (main_url, them, year, may, day)
    r = requests.get(url)
    page = r.text
    print(page)

Получение данных с указанных страниц/разделов в lenta.ru

Для получения данных о статьях необходимо определить в каких тегах они закреплены.

Проведя анализ полученной страницы, можно сделать вывод:

—  статьи на этой странице ограничены тегами:

div class=”row”; div class=”titles”.

На основании этих ограничений прочитаем выгруженную страницу с помощью Beautyful Soup и сохраним все гиперссылки на статьи в список.

import requests
from bs4 import BeautifulSoup

#…….. здесь предыдущий код

newlinks = []
soup = BeautifulSoup(page, 'lxml')
link_block = soup.find_all('div', class_='row')
for blocks in link_block:
    if blocks.find_all('div', class_='titles'):
        for block in blocks.find_all('div', class_='titles'):
            newlinks.append("%s%s" % (main_url, block.find('a').get('href')))
print(newlinks)

Так выглядит список статей:

Формализация данных поиска (персоны и даты)

У нас есть список статей и осталось провести поиск искомой персоны. Имеется немало разных библиотек, с помощью которых можно задать правильный поиск по Фамилии Имени Отчеству.

Немного упростим задачу, будем искать только по фамилии персоны, для этого напишем следующий код:

name = 'Меркель'
if (name[-2:] == 'ая' or name[-2:] == 'яя' or name[-2:] == 'ий' or name[-2:] == 'ой' \
    or name[-2:] == 'ый' or name[-2:] == 'ая') and len(name) > 4:
    newname = name[:-2]
elif name[-1:] == 'а' or name[-1:] == 'ь' or name[-1:] == 'й' and len(name) > 4:
    newname = name[:-1]
else:
    newname = name
print(newname)

Если вы заметили, то дата в коде написана в виде

url = "%s/%s/%s/%s/%s/" % (main_url, them, year, may, day)..

То есть необходимо распарсить входящую дату, что будет сделано с помощью кода:

date = "26.06.2018"
year = date.split(".")[2]
may = date.split(".")[1]
day = date.split(".")[0]

И необходимо вставить эти 2 фрагмента кода выше блока «Открытие указанных страниц/разделов в lenta.ru за конкретную дату».

Поиск персоны в статьях с указанных страниц/разделов в lenta.ru за конкретную дату

С помощью requests открываем статьи, указанные в списке newlinks, будем искать и считать количество упоминаний нашей персоны в каждой статье с помощью Beautyful Soup.

pages_name ={}
for url in newlinks:
    page = requests.get(url)
    soup = BeautifulSoup(page.text, 'lxml')
    link_block = soup.find_all('div', class_='b-topic__content')
    page_count = str(link_block).count(newname)
    if page_count > 0:
        pages_name[url] = page_count
print(pages_name)

Передача данных в базу данных сервиса в json — формате {‘гиперссылка на статью’: Количество упоминаний}

На выходе:

{‘https://lenta.ru/articles/2018/06/25/merkel_i_ee_problemi/’: 21}

Была найдена 1 статья с 21 упоминанием персоны Меркель.

Вот и всё. Как видите ничего сложного. Весь указанный код, объединенный в класс,  выложен на   https://github.com/IldarVS/crawler

Что можно почитать по парсингу сайтов:

1. Python: Scrapy, Selenium, Beautiful Soup что лучше для парсинга веб сайтов

2. Grab — python библиотека для парсинга сайтов

3. BeautifulSoup – парсинг HTML в Python на примерах