Есть много статей о очистке веб-страниц с помощью Beautiful Soup и еще больше об анализе тональности. Однако было трудно найти статью, которая связывала бы эти точки, поэтому в этой статье я покажу, как можно использовать News API, Beautiful Soup и предварительно обученную модель BERT для надежного анализа тональности.

Анализ настроений

Анализ настроений, также известный как анализ мнений, представляет собой процесс определения настроений или эмоций, стоящих за фрагментом текста. Это метод обработки естественного языка (NLP), целью которого является выявление и категоризация мнений, выраженных в тексте, чтобы определить, является ли настроение положительным, отрицательным или нейтральным. Анализ настроений приобрел большое значение в различных областях, таких как маркетинг, обслуживание клиентов, мониторинг социальных сетей и исследования рынка.

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

  1. Размещение рекламы. Анализируя настроение новостных статей, компании могут определить положительный или нейтральный контент, который соответствует имиджу и ценностям их бренда, и соответствующим образом размещать свои объявления, чтобы максимизировать охват и избежать негативных ассоциаций.
  2. Анализ конкурентов. Анализ настроений может помочь компаниям отслеживать освещение своих конкурентов в новостях и понимать, как их продукты и услуги воспринимаются в сравнении.
  3. Связи с общественностью: отслеживание настроений в новостях позволяет компаниям выявлять потенциальные кризисы в сфере PR и предпринимать соответствующие действия, чтобы уменьшить ущерб, наносимый их репутации.
  4. Исследование рынка. Анализ новостных настроений может помочь компаниям выявить тенденции и изменения в потребительских предпочтениях, что позволит им соответствующим образом адаптировать свои стратегии и предложения продуктов.

Итак, теперь, когда мы понимаем, что такое анализ настроений и некоторые потенциальные приложения этого проекта, давайте начнем!

Получение новостных статей с помощью News API

В этом разделе мы обсудим, как использовать News API для получения новостных статей из различных источников, таких как CNN, MSNBC и Fox News.

Создайте учетную запись на веб-сайте News API и получите ключ API.

Для начала вам необходимо создать учетную запись на сайте News API. После регистрации вы получите ключ API, который потребуется для выполнения запросов к API новостей.

Используйте NewsApiClient из пакета newsapi для получения статей.

Чтобы получать статьи с помощью News API, вам необходимо установить пакет newsapi-python, который предоставляет удобную оболочку Python для News API. Вы можете установить его с помощью pip:

pip install newsapi-python

После установки пакета вы можете использовать класс NewsApiClient для взаимодействия с News API. Сначала импортируйте класс и инициализируйте его своим ключом API:

from newsapi import NewsApiClient

# replace 'your-api-key' with the api key you got in the previous step
newsapi = NewsApiClient(api_key='your-api-key')

Метод get_everything() класса NewsApiClient можно использовать для получения всех статей из указанных источников новостей. Этот метод позволяет фильтровать статьи на основе параметров запроса, таких как источники, язык и порядок сортировки.

Например, чтобы получить все статьи из CNN, MSNBC и Fox News, вы можете использовать следующий код:

news_sources = ['cnn', 'msnbc', 'fox-news']

def fetch_articles(source_list):
    articles = []
    for source in source_list:
        source_articles = newsapi.get_everything(sources=source, language='en', sort_by='relevancy')
        articles.extend(source_articles['articles'])
    return articles

articles_data = fetch_articles(news_sources)

Приведенный выше код определяет функцию fetch_articles(), которая берет список источников новостей и извлекает статьи из каждого источника с помощью метода get_everything(). Выбранные статьи затем объединяются в единый список.

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

# Save the data to a JSON file
with open('articles_data_all_sources.json', 'w') as file:
    json.dump(articles_data, file, ensure_ascii=False, indent=4)

Теперь у нас есть извлеченные статьи, сохраненные на диск. Однако есть еще одно ограничение, которое нам нужно преодолеть. News API захватывает только ограниченное количество фактических статей, и для целей этого проекта мы хотели бы иметь все содержимое для каждой статьи.

Парсинг содержимого статьи с помощью Beautiful Soup

В этом разделе мы обсудим, как использовать Beautiful Soup для получения полного содержания статей, полученных с помощью News API. Это важно, потому что News API предоставляет только ограниченное количество контента для каждой статьи, а нам нужен весь текст для выполнения всестороннего анализа тональности.

Важность получения полного контента для анализа настроений

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

Чтобы получить полное содержимое статей, мы будем использовать функцию get_article_content(), которая использует библиотеку requests для получения содержимого веб-страницы и Beautiful Soup для анализа HTML. Функция может быть определена следующим образом:

import requests
from bs4 import BeautifulSoup

def get_article_content(url):
    try:
        response = requests.get(url)
        response.raise_for_status()

        soup = BeautifulSoup(response.text, 'html.parser')
        paragraphs = soup.find_all('p')

        content = '\n'.join([paragraph.get_text() for paragraph in paragraphs])
        return content
    except Exception as e:
        print(f"Error fetching content from {url}: {e}")
        return None

Функция находит все теги <p> и извлекает из них текст для создания полноценного контента.

Функция get_article_content() работает, сначала отправляя HTTP-запрос на URL-адрес статьи, используя библиотеку requests. Если запрос выполнен успешно, текст ответа передается Beautiful Soup для анализа. Затем Beautiful Soup ищет в HTML все теги <p>, которые обычно содержат основное содержание статьи. Текст внутри этих тегов извлекается, а абзацы объединяются для создания полного содержания статьи.

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

for i, article in enumerate(articles_data):
    url = article['url']
    content = get_article_content(url)
    if content:
        articles_data[i]['content'] = content

Хорошо, теперь мы получили полное содержимое каждой статьи, используя URL-адреса, которые мы получили при выборке News API. Теперь пришло время перейти к следующему шагу — получению прогнозов настроений для каждой статьи.

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

Анализ настроений с использованием BERT

Теперь пришло время использовать модель BERT (представления двунаправленного кодировщика от преобразователей) для анализа тональности. BERT — это мощная модель обработки естественного языка, разработанная Google AI, которая достигла самых современных результатов в различных задачах, включая анализ тональности.

Используется предварительно обученная модель BERT из библиотеки трансформеров Hugging Face.

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

Для этого проекта мы будем использовать модель «nlptown/bert-base-multilingual-uncased-sentiment», предварительно обученную модель BERT, специально разработанную для анализа настроений. Эта модель способна анализировать текст на нескольких языках и предоставляет прогнозы настроений как отрицательные, нейтральные или положительные.

Чтобы использовать модель BERT для анализа тональности, мы создадим функцию get_sentiment(), которая принимает входной текст, токенизирует его с помощью токенизатора BERT и передает его модели для получения прогнозов тональности. Функция может быть определена следующим образом:

import torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification

# Frist, create a DataFrame from the articles data
df = pd.DataFrame(articles_data, columns=['title', 'description', 'url', 'author', 'source', 'content'])

tokenizer = AutoTokenizer.from_pretrained("nlptown/bert-base-multilingual-uncased-sentiment")
model = AutoModelForSequenceClassification.from_pretrained("nlptown/bert-base-multilingual-uncased-sentiment")

def get_sentiment(text):
    inputs = tokenizer.encode(text, return_tensors="pt", max_length=512, truncation=True, padding='max_length')
    outputs = model(inputs)[0]
    _, prediction = torch.max(outputs, 1)
    prediction_index = prediction.item()

    if prediction_index > 2:
        prediction_index = 2

    sentiment = ["negative", "neutral", "positive"][prediction_index]
    return sentiment

Как только мы определили функцию get_sentiment(), мы можем применить ее к полному содержимому каждой статьи в нашем DataFrame, чтобы получить прогнозы настроений:

# Apply sentiment analysis to the DataFrame
df["sentiment"] = df["content"].apply(get_sentiment)

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

Результаты и визуализация

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

Обзор результатов анализа тональности с использованием сгруппированной гистограммы

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

# Get the sentiment counts per author
sentiment_counts = df.groupby('source_name')['sentiment'].value_counts().unstack().fillna(0)

# Sort the authors by the total number of articles
sorted_authors = sentiment_counts.sum(axis=1).sort_values(ascending=False).index

# Select the top 10 authors
top_sentiment_counts = sentiment_counts.loc[sorted_authors[:10]]

# Plot the stacked bar chart
ax = top_sentiment_counts.plot(kind='bar', stacked=True, figsize=(10, 6))
ax.set_title('Sentiment Counts per Author (Top 10 Authors)')
ax.set_ylabel('Number of Articles')
ax.set_xlabel('Author')

# Display the legend
ax.legend(title='Sentiment', bbox_to_anchor=(1, 1))

plt.show()

Отлично, теперь мы можем видеть общие настроения для каждого источника новостей. Похоже, что Fox News выпускает шокирующее большое количество статей, которые считаются негативными, в то время как CNN преимущественно выпускает статьи с положительным или нейтральным настроением, а MSNBC довольно равномерно сочетает все три.

Визуализация карты дерева с использованием Plotly

Чтобы лучше понять распределение настроений между источниками новостей и их ведущими авторами, мы можем создать визуализацию древовидной карты с помощью библиотеки Plotly. Это поможет визуализировать иерархию и пропорции различных источников новостей, авторов и связанных с ними настроений.

Во-первых, убедитесь, что у вас установлена ​​библиотека Plotly. Вы можете установить его с помощью следующей команды:

pip install plotly

Затем вы можете использовать следующий код для создания визуализации древовидной карты:

import plotly.express as px

fig = px.treemap(df, path=['source', 'author', 'sentiment'], color='sentiment',
                 color_discrete_map={"positive": "rgba(0,255,0,0.8)", "negative": "rgba(255,0,0,0.8)", "neutral": "rgba(0,0,255,0.8)"},
                 hover_data=['title'])
fig.update_layout(title="Sentiment Distribution of News Articles Across Sources and Authors")
fig.show()

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

Визуализация ключевых слов в облаке слов

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

1. Импортируйте необходимые библиотеки:

Сначала мы импортируем необходимые библиотеки, такие как NumPy, Matplotlib, WordCloud, Collections и Pandas.

2. Объедините все содержимое статей для каждого источника новостей:

Мы создаем словарь с именем source_contents для хранения объединенного содержимого всех статей для каждого источника новостей (CNN, MSNBC и Fox News). Мы перебираем DataFrame и объединяем содержимое каждой статьи с соответствующим источником новостей в словаре.

3. Определите цветовую функцию для облака слов:

Функция `color_func` назначает цвет каждому слову в зависимости от источника новостей, которому оно принадлежит. Мы используем красный цвет для CNN, синий для MSNBC и зеленый для Fox News.

4. Сгенерируйте частоты слов:

Мы создаем функцию `generate_word_frequencies`, которая принимает текст и набор стоп-слов в качестве входных данных. Эта функция размечает текст, удаляет стоп-слова и фильтрует слова на основе их тегов части речи (POS), чтобы сосредоточиться на существительных. Затем он вычисляет частоту каждого существительного и возвращает его в виде словаря.

5. Создайте более строгий набор стоп-слов:

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

6. Подсчитайте частоты слов для каждого источника:

Мы рассчитываем частоты слов для каждого источника новостей после удаления стоп-слов и сохраняем их в словаре с именем `source_word_frequencies`.

7. Выберите первые N слов из каждого источника:

Мы устанавливаем N равным 50, и для каждого источника новостей мы выбираем первые N слов на основе их частотности, используя метод счетчика `most_common()`.

8. Объедините верхние слова для всех источников:

Мы создаем словарь с именем `combined_top_words` и еще один с именем `word_sources`. Затем мы перебираем самые популярные слова для каждого источника новостей и обновляем их частотность в словаре `combined_top_words`. Мы также сохраняем источник для каждого слова в словаре word_sources.

9. Создайте облако слов:

Мы создаем объект WordCloud со строгим набором стоп-слов и белым фоном. Мы генерируем облако слов из частот в словаре `combined_top_words`. Мы используем метод `recolor()` с функцией `color_func`, чтобы назначить разные цвета словам в зависимости от их источника новостей.

10. Отобразите облако слов:

Наконец, мы отображаем сгенерированное облако слов с помощью Matplotlib. Полученное облако слов показывает самые популярные ключевые слова для каждого источника новостей с разными цветами, представляющими каждый источник.

Вот окончательный код:

import numpy as np
import matplotlib.pyplot as plt
from wordcloud import WordCloud, STOPWORDS
from collections import defaultdict, Counter
import pandas as pd

news_sources = ['CNN', 'MSNBC', 'Fox News']

# Concatenate all article contents for each news source
source_contents = defaultdict(str)
for _, row in df.iterrows():
    source = row['source_name']
    content = row['content']
    if isinstance(content, str):
        source_contents[source] += content

# Define a color function for the word cloud
def color_func(word, font_size, position, orientation, random_state=None, **kwargs):
    source = word_sources[word]
    if source == "CNN":
        return "red"
    elif source == "MSNBC":
        return "blue"
    elif source == "Fox News":
        return "green"

def generate_word_frequencies(text, stopwords):
    words = word_tokenize(text)
    words = [word for word in words if word.lower() not in stopwords and word.isalpha()]
    tagged_words = pos_tag(words)
    nouns = [word for word, pos in tagged_words if pos in ["NN", "NNS", "NNP", "NNPS"]]
    word_frequencies = defaultdict(int)
    for noun in nouns:
        word_frequencies[noun] += 1
    return word_frequencies


# Create a stricter set of stopwords
strict_stopwords = set(stopwords.words('english'))
strict_stopwords.update(["said", "first", "last", "will", 'Monday','month', 'months', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday', 'week', 'weeks', 'year', 'years', 'day', 'days', 'weekend', 'weekends', 'today', 'tomorrow', 'yesterday', 'morning', 'afternoon', 'evening', 'night', 'evenings', 'nights', 'weekdays', 'weeknights'
, 'Solutions', 'minutes', 'broadcast', 'people',])

# Calculate the word frequencies for each source after removing stop words
source_word_frequencies = {}
for source in news_sources:
    content = source_contents[source]
    word_frequencies = generate_word_frequencies(content, strict_stopwords)
    source_word_frequencies[source] = word_frequencies

# Select the top N words from each source
N = 50
top_words = {}
for source in news_sources:
    word_frequencies = source_word_frequencies[source]
    top_words[source] = dict(Counter(word_frequencies).most_common(N))

# Combine the top words for all sources
combined_top_words = defaultdict(int)
word_sources = {}
for source in news_sources:
    for word, freq in top_words[source].items():
        combined_top_words[word] += freq
        word_sources[word] = source

# Generate the word cloud with different colors for each source and without stop words
wordcloud = WordCloud(stopwords=strict_stopwords, background_color="white", width=800, height=400)
wordcloud.generate_from_frequencies(frequencies=combined_top_words)
wordcloud.recolor(color_func=color_func)
plt.figure(figsize=(16, 8))
plt.imshow(wordcloud, interpolation='bilinear')
plt.axis("off")
plt.title("Combined Word Cloud")
plt.show()

Здесь есть что распаковать, и мы можем оставить это зрителю для изучения. Здесь важно отметить, что Fox News закодирован зеленым цветом, CNN — красным, а MSNBC — синим.

Выводы из анализа настроений

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

  1. Общее распределение настроений для каждого источника новостей, показывающее, склонен ли конкретный источник новостей публиковать больше позитивных, негативных или нейтральных статей.
  2. Распределение настроений для ведущих авторов из каждого источника новостей, помогающее выявить любые предубеждения или тенденции, связанные с конкретными авторами.
  3. Корреляция между определенными темами или предметами и настроением обсуждающих их статей, что может быть полезно для предприятий, рассматривающих рекламу или другие решения, основанные на общественном мнении.

Изучая результаты и визуализацию, вы можете лучше понять структуру новостных статей и их тональность, предоставляя ценную информацию для различных приложений и процессов принятия решений.

Заключение

В этой статье мы продемонстрировали, как получать новостные статьи из различных источников, выполнять анализ тональности с помощью предварительно обученной модели BERT и визуализировать результаты с помощью визуализаций древовидной карты и облаков слов. С помощью этих визуализаций и аналитических данных мы выявили распределение настроений по различным источникам новостей и их ведущим авторам, а также определили важные ключевые слова.

Полученные нами сведения включают в себя понимание общего настроения каждого источника новостей, выявление потенциальных предубеждений или тенденций, связанных с конкретными авторами, а также выявление корреляции между определенными темами или темами и настроением обсуждающих их статей. Эти идеи могут быть бесценны для компаний, рассматривающих рекламу, PR-стратегии или другие решения, основанные на общественном мнении и освещении в СМИ.

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

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