новостная лента

Сбор новостных статей через каналы RSS / Atom с использованием Python

Или как перестать зависеть от поставщиков данных

В одном из своих предыдущих постов я говорил о том, как можно очищать и анализировать новостные статьи с помощью всего 5 строк кода:



На этот раз я покажу вам, как можно настроить канал для автоматического сбора всех новых статей, опубликованных практически любым поставщиком новостей (например, NY Times, CNN, Bloomberg и т. Д.)

Для достижения этой цели я покажу вам, как можно автоматизировать сбор новостей с помощью пакета Python feedparser, который помогает нормализовать каналы RSS / Atom.

Для кого эта статья?

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

Что такое RSS и Atom?

RSS - это обычный текст в формате XML, содержащий краткое изложение статей, недавно опубликованных некоторыми поставщиками контента (новости, подкасты, личный блог и т. Д.)

Наиболее распространенными производителями RSS являются издатели новостей.

RSS-канал существует для обеспечения доступа к последним новостям (например, для агрегаторов новостей и синдикаторов новостей).

RSS-канал не содержит всего текста статьи (в большинстве случаев), но предоставляет некоторую базовую информацию, такую ​​как автор, название, описание, время публикации и т. Д.

Atom - это еще один формат XML, который был разработан как альтернатива RSS-каналу. Atom кажется более продвинутым по сравнению с RSS, но я не собираюсь сравнивать эти 2 формата в этом посте.

Пример RSS XML:

<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
 <title>RSS Title</title>
 <description>This is an example of an RSS feed</description>
 <link>http://www.example.com/main.html</link>
 <lastBuildDate>Mon, 06 Sep 2010 00:01:00 +0000 </lastBuildDate>
 <pubDate>Sun, 06 Sep 2009 16:20:00 +0000</pubDate>
 <ttl>1800</ttl>
 <item>
  <title>Example entry</title>
  <description>Here is some text containing an interesting description.</description>
  <link>http://www.example.com/blog/post/1</link>
  <guid isPermaLink="false">7bd204c6-1655-4c27-aeee-53f933c5395f</guid>
  <pubDate>Sun, 06 Sep 2009 16:20:00 +0000</pubDate>
 </item>
</channel>
</rss>

Очистите новости через конечную точку RSS

Итак, осталось только собрать все URL-адреса (конечные точки) издателей новостей, которые нас интересуют.

В этой статье я использую конечную точку канала NY Times. Для этого мне пришлось:

  • перейдите на https://www.nytimes.com/
  • «Проверить» исходный код страницы
  • поиск по запросу "rss"
  • получить первый результат

Давайте возьмем эту ссылку и проверим, похожа ли она на то, что нам нужно.

Хорошо, как мы видим, это RSS «Нью-Йорк Таймс».

В разделе ‹channel› вы можете найти общую информацию о самом фиде - описание, время создания, язык и т. Д.

Каждый ‹item› в этом RSS представляет статью. Первый пункт представляет собой статью с заголовком (‹title›) под названием «Трамп делает ставку, что он может изолировать Иран и очаровать Северную Корею». Это не так просто ».

Если мы перейдем по ссылке (‹link›) под этим ‹item›, мы будем перенаправлены на исходную страницу статьи:

RSS не предоставит нам полный текст статьи, но вместо этого предложит краткое ‹description›.

Feedparser

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

Главный недостаток RSS / Atom-каналов в том, что они не нормализованы. Согласно странице Википедии, в RSS / Atom есть только несколько обязательных полей (ссылка, заголовок, описание).

Это означает, что в случае, если вы хотите хранить данные от разных издателей новостей, вы должны либо учитывать все возможные пары ключ-значение, либо использовать некоторую технологию без схемы (например, elasticsearch).

Изучите пакет feedparser

pip install feedparser

import feedparser

feed = feedparser.parse('https://rss.nytimes.com/services/xml/rss/nyt/HomePage.xml')

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

feed.feed
Out[171]: 
{‘title’: ‘NYT > Top Stories’,
 ‘title_detail’: {‘type’: ‘text/plain’,
 ‘language’: None,
 ‘base’: ‘https://rss.nytimes.com/services/xml/rss/nyt/HomePage.xml',
 ‘value’: ‘NYT > Top Stories’},
 ‘links’: [{‘rel’: ‘alternate’,
 ‘type’: ‘text/html’,
 ‘href’: ‘https://www.nytimes.com?emc=rss&partner=rss'},
 {‘href’: ‘https://rss.nytimes.com/services/xml/rss/nyt/HomePage.xml',
 ‘rel’: ‘self’,
 ‘type’: ‘application/rss+xml’}],
 ‘link’: ‘https://www.nytimes.com?emc=rss&partner=rss',
 ‘subtitle’: ‘’,
 ‘subtitle_detail’: {‘type’: ‘text/html’,
 ‘language’: None,
 ‘base’: ‘https://rss.nytimes.com/services/xml/rss/nyt/HomePage.xml',
 ‘value’: ‘’},
 ‘language’: ‘en-us’,
 ‘rights’: ‘Copyright 2020 The New York Times Company’,
 ‘rights_detail’: {‘type’: ‘text/plain’,
 ‘language’: None,
 ‘base’: ‘https://rss.nytimes.com/services/xml/rss/nyt/HomePage.xml',
 ‘value’: ‘Copyright 2020 The New York Times Company’},
 ‘updated’: ‘Thu, 02 Jan 2020 15:03:52 +0000’,
 ‘updated_parsed’: time.struct_time(tm_year=2020, tm_mon=1, tm_mday=2, tm_hour=15, tm_min=3, tm_sec=52, tm_wday=3, tm_yday=2, tm_isdst=0),
 ‘published’: ‘Thu, 02 Jan 2020 15:03:52 +0000’,
 ‘published_parsed’: time.struct_time(tm_year=2020, tm_mon=1, tm_mday=2, tm_hour=15, tm_min=3, tm_sec=52, tm_wday=3, tm_yday=2, tm_isdst=0),
 ‘image’: {‘title’: ‘NYT > Top Stories’,
 ‘title_detail’: {‘type’: ‘text/plain’,
 ‘language’: None,
 ‘base’: ‘https://rss.nytimes.com/services/xml/rss/nyt/HomePage.xml',
 ‘value’: ‘NYT > Top Stories’},
 ‘href’: ‘https://static01.nyt.com/images/misc/NYT_logo_rss_250x40.png',
 ‘links’: [{‘rel’: ‘alternate’,
 ‘type’: ‘text/html’,
 ‘href’: ‘https://www.nytimes.com?emc=rss&partner=rss'}],
 ‘link’: ‘https://www.nytimes.com?emc=rss&partner=rss'}}

Наиболее важные поля - copyright и published.

Feedparser присваивает этим атрибутам правильные значения, чтобы вам не приходилось тратить время на их нормализацию самостоятельно.

Нормализованные статьи

Как и в случае с фидами, вы можете найти информацию о каждой статье под атрибутом .entries.

feed.entries[0].title
Out[5]: 'Trump Bet He Could Isolate Iran and Charm North Korea. It’s Not That Easy.'

Таким образом, мы будем знать основную информацию о каждом элементе фида.

Если вам нужен полный текст статьи, вам нужно взять URL-адрес и использовать газету3k. Отметьте другую мою статью, которую я встроил в начало этого поста.

Дальнейшая работа

Попытайтесь подумать о том, как вы могли бы построить канал данных для сбора новых статей, дедупликации с теми, которые ваша база данных уже видела. Кроме того, дополнительный конвейер NLP сверху может дать много полезных идей (пакет python spaCy идеально подходит для этого).

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