Пишем простой граббер статей на Python

Новостные сайты являются хорошим источником данных для обработки моделями машинного обучения. При этом, большинство новостных web-ресурсов перегружено различной «лишней» информацией, не относящейся к сути статей, будь то навязчивая реклама, всплывающие окна со служебной информацией и т.д. Очистка статей при выгрузке с web-ресурсов от «шума» помогла бы снизить количество ошибок обработки данных.

В этой статье мы рассмотрим создание инструмента, с помощью которого можно получать читабельный текст из статей с минимальной «лишней» информацией.

Пишем простой граббер статей на Python

Чтобы написать Ваш собственный граббер самостоятельно, Вам потребуются знания в области Web-разработки, такие как понимание языка гипертекстовой разметки HTML (понимание значений тегов, размещение информации внутри них) и основной информации о структуре DOM-дерева при отрисовке сайтов, а также базовые навыки программирования на языке Python.

Итак, начнем.

Для работы нам потребуются библиотеки:

  • request
  • BeautifulSoup

Библиотека requests по факту является стандартом при работе с составлением HTTP-запросов к web-ресурсам. В этой библиотеке собрано множество методов, с помощью которых значительно упрощается процесс создания запросов и разбора ответов от сервера. И это помогает нам сосредоточиться на написании непосредственно нашего алгоритма, а не на поиске способов обеспечить стабильную связь и получение данных с web-ресурсов.

В нашем скрипте будем использовать получение данных при помощи HTTP-метода GET. Метод GET является инструкцией web-ресурсу о том, что с него запрашиваются некоторые данные, указанные как параметр к GET. Чтобы выполнить такой запрос, используя библиотеку requests, достаточно ввести requests.get (< URL >; <дополнительные параметры>). При существовании URL и при наличии прав на доступ к ресурсу, в ответ придут данные HTML-страницы, которые уже можно обработать различными инструментами языка Python. Натболее распространенным инструментом для данной задачи является библиотека BeautifulSoup.

Библиотека BeautifulSoup используется для анализа документов HTML и XML. Она создает дерево синтаксического анализа для полученных страниц (DOM-дерево), которое можно использовать для извлечения данных из HTML в удобные для обработки на языке Python конструкции (словари, списки, строки), что полезно для очистки веб-страниц от ненужной информации.

Алгоритм работы нашей программы будет заключаться в том, что при запуске скрипта Python из командной строки и с указанием URL требуемой нам статьи в качестве параметра, мы будем получать HTML-страницу при помощи метода get библиотеки request. Затем создаем объект BeautifulSoup, который непосредственно и помогает нам очистить статью от лишней информации.

Но для того, чтобы обозначить, что именно считать лишней информацией, а что полезной, нам необходимо проанализировать источник, из которого мы будем брать статьи. Сейчас распространенной практикой является разработка web-ресурсов в блочном формате. Все данные, которые необходимо разместить на страницах разбиваются по логическим блокам и помещаются в теги < div > < /div >

Далее, уже внутри этих блоков информация может принимать различные вариации в зависимости от назначения. В блоках, предназначенных для навигации преобладают ссылочные теги, в блоках, где имеется много изображений, соответственно, много тегов. Нас же интересуют блоки web-страниц, в которых хранятся тексты статей.

Если провести небольшое исследование размещения информации на новостных сайтах, то почти на каждом мы увидим, что блоки с непосредственно самой статьей изобилуют тегами < p > < /p >

Поэтому, первым логичным шагом для создания нашего простого граббера будет взять за основу именно тег < p > < /p >

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

Чтобы наш код можно было удобно переиспользовать в других проектах и подключать файл скрипта в другие скрипты Python — первым делом напишем класс, в котором будем хранить все нужные нам методы и объекты.

class GrabberArticle: url = "" filename = "" path = "" content_tags = ['p'] wrap = 80

Описание объектов:

url – URL статьи, которую хотим обработать.

filename – имя файла для сохранения. Соответствует последнему элементу в URL. Например, для host.net/path1/path2 — это path2

path – Путь для сохранения обработанного текста. Соответствует ([Каталог с файлом скрипта]/host.net/path1/path2/…)

content_tags – HTML-теги для обработки. По умолчанию установлен тег

, так как мы приняли его за основной тег, в котором наиболее часто размещён основной полезный контент статьи.

wrap – количество символов в строке очищенного текста. По умолчанию установлено значение в 80 символов — негласное правило читаемости текста на экране.

Давайте теперь напишем главный метод для нашего класса GrabberArticle, который будет получать ответ от web-ресурса и при помощи BeautifulSoup отфильтровывать только нужные нам данные:

def get_text(self): r = requests.get(self.url).text soup = BeautifulSoup(r, 'html.parser') # найдем все теги по списку self.content_tags content = soup.find_all(self.content_tags) wrapped_text = "" for p in content: # пропускаем теги без значений if p.text != '': # форматирование ссылок в вид [ссылка] links = p.find_all('a') if links != '': for link in links: p.a.replace_with(link.text + str("[" + link['href'] + "]")) # устанавливаем ширину строки равной self.wrap (по умолчанию, 80 символов) wrapped_text += ''.join(textwrap.fill(p.text, self.wrap)) + "\n\n" self.write_in_file(wrapped_text)

В качестве результата будем выводить текстовый файл, который будет называться по имени последнего элемента URL- адреса. Также создадим иерархию для размещения этого файла в файловой системе, исходя из оставшихся элементов URL-адреса. Например, для URL: https://lenta.ru/news/2020/04/09/centenarian: файл будет сохранен под именем centenarian.txt в каталоге [Директория со скриптом]/lenta.ru/news/2020/04/09/. Такая иерархия на первый взгляд может выглядеть избыточной. Но такой подход может быть полезен, если с одного и того же источника (и тем более нескольких) будет выгружаться большое количество статей. В такой структуре данные будет легко сгруппировать по определенным признакам. Это позволит гораздо проще обращаться к массиву данных из статей, если, например, они будут использованы для проведения тематических исследований с помощью моделей машинного обучения.

def __init__(self, url_address): self.url = url_address # Get path and filename for saving article by splitting URL. # If the URL ends with some.html, then the previous (-2) element # of the path is taken to form the path and the filename = some.html.txt respectively. path_arr = self.url.split('/') if path_arr[-1] != '': self.filename = path_arr[-1] + ".txt" self.path = os.getcwd() + "/".join(path_arr[1:-1]) else: self.filename = path_arr[-2] + ".txt" self.path = os.getcwd() + "/".join(path_arr[1:-2]) if not os.path.exists(self.path): os.makedirs(self.path)

Допишем метод, который будет записывать в файл полученный «чистый» текст:

def write_in_file(self, text): # записывает text в каталог self.path:"[CUR_DIR]/host.ru/path_item1/path_item2/..." file = open(str(self.path) + '/' + str(self.filename), mode="a") file.write(text) file.close()

Готово! Теперь наш скрипт можно запускать из командной строки, просто передавая ему URL статьи:

Пишем простой граббер статей на Python

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

В дальнейшем данный скрипт можно усовершенствовать так, чтобы он в качестве входных данных использовал файл со списком URL и выгружал уже готовый массив данных целиком. А для написания более детального скрипта выгрузки для Ваших источников необходимо просто дописать нужные теги в объект GrabberArticle.content_tags, либо передавать их через отдельный файл настроек.

Примечание:

Несмотря на то, что грабберы являются очень полезным инструментом по созданию выборок для проведения исследований, машинная выгрузка данных с web-ресурсов приводит к значительному повышению сетевой нагрузки на сайты и доставляет проблемы владельцам ресурсов. Некоторые даже блокируют ip-адреса, с которых замечена подобная активность. Поэтому призываю пользоваться грабберами в пределах разумного и не перегружать удаленные web-ресурсы, чтобы не вызывать негативных последствий на них.

Полный код из статьи размещен по адресу: https://github.com/ZveRuss/GrabberArticle

44
5 комментариев

У многих новостных сайтов и у блогов бывает RSS-лента. RSS - структурированный, там и html-мусора не будет, и специализированные библиотеки под любой язык программирования есть, и многие программы для чтения новостей или книг умеют RSS поддерживать. Список доступных RSS-каналов lenta.ru есть здесь: https://lenta.ru/info/posts/export/
 

1
Ответить

Использую xpath для парсинга на python и php, все лучше чем BeautifulSoup)

Ответить

вы наверное имели ввиду lxml или какую-то еще библиотеку для работы с xml/html? xpath это ж язык запросов к элементам XML.

Ответить

мне кажется сейчас уже больше половины трафика в интернете - это роботы

Ответить

а кроме lenta.ru где новости живут?

Ответить