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

Заголовки новостей были выбраны в качестве основы для алгоритма неконтролируемой кластеризации из-за его способности кратко представлять информацию. Хотя просеивание новостей само по себе позволило бы получить больше географических местоположений, объем вычислительной обработки и пропускная способность перевешивают преимущества, которые они предоставляют. Чтобы найти самые популярные источники новостей, были выбраны две статьи Feedspot (100 лучших новостных веб-сайтов США и 100 лучших мировых новостных веб-сайтов), содержащие список из ста лучших источников новостей в мире и США; эта статья постоянно обновляется, чтобы обеспечить наличие в ней самой последней информации. Этот метод действительно представляет предвзятость, поскольку некоторые новостные веб-сайты, такие как The Los Angeles Times, обычно сообщают новости о своем городе, создавая искаженные кластеры; соответственно, были удалены новостные веб-сайты, относящиеся к определенному городу.

Подробное объяснение кода приведено ниже.

Шаг 1. Установите и импортируйте соответствующие библиотеки.

!pip install bs4
!pip install django

from bs4 import BeautifulSoup as bs
import urllib.request
from django.core.validators import URLValidator
from django.core.exceptions import ValidationError
import time
from datetime import datetime
import boto3

Шаг 2. Инициализируйте и очистите корзину S3 (необязательно)

С помощью библиотеки boto3 и учетных данных конфигурации учетной записи AWS объект S3 очищается и помещается в корзину S3. Этот шаг не требуется, если интеграция с AWS не требуется.

s3 = boto3.resource(
    's3',
    region_name='us-east-1',
    aws_access_key_id=*HIDDEN*,
    aws_secret_access_key=*HIDDEN*
)

content = ""
s3.Object('headlines', 'headline.txt').put(Body=content)

Шаг 3. Создайте функцию для извлечения веб-сайтов.

Сначала, используя библиотеку urllib, код открывает URL-адрес и преобразует содержимое веб-сайта в HTML. Затем с помощью библиотеки Beautiful Soup HTML анализируется, а гиперссылки извлекаются из HTML-кода. Эти гиперссылки определяются путем нахождения блоков «a» в коде HTML. При реализации библиотеки Django URL-адреса гиперссылок проверяются, фильтруются на основе URL-адреса исключения и добавляются в массив. Затем возвращается этот массив URL-адресов.

def extractWebsites(url, exceptionURL):
    try:
        webUrl = urllib.request.urlopen(url)
        data = webUrl.read()
        soup = bs(data)
        arr = []
        for link in soup.find_all('a'):
            validate = URLValidator()
            href = link.get('href')
            if (href != None):
                try:
                    validate(href)
                    if (href.find(exceptionURL) == -1):
                        arr.append(href)
                except ValidationError as exception:
                    continue
        return arr
    except:
        return []

Шаг 4. Создайте функцию, которая ищет в URL-адресе определенные ключевые слова.

Функция выполняет итерацию по массиву ключевых слов и возвращает истину, если какое-либо из ключевых слов находится в URL-адресе.

def search_array(url, arrOfPoss):
    for index in arrOfPoss:
        if (url.find(index.capitalize()) != -1 or url.find( index.lower()) != -1):
            return True
    return False

Шаг 5. Извлеките заголовки

Во-первых, ряд новостных каналов выбирается из 100 лучших американских и мировых новостных сайтов Feedspot. Затем этот массив повторяется с помощью функции extractWebsites для поиска подходящих веб-сайтов, имеющих отношение к COVID-19. «Интерактивный» выбран в качестве URL-адреса исключения, поскольку они не содержат релевантных заголовков. Другие заголовки фильтруются с помощью функции search_array с набором ключевых слов COVID-19. Эти отфильтрованные заголовки сохраняются в новом массиве с именем covid_urls.

Снова используя функцию extractWebsites, выполняется итерация covid_urls для поиска дополнительных веб-сайтов, связанных с COVID. Чтобы сократить время выполнения, реализован счетчик, который останавливается, если необходимо пройти слишком много веб-сайтов. Кроме того, если эта процедура занимает больше десяти минут, внутренний цикл for завершается. И снова в качестве execptionURL выбран «интерактивный», а заголовки фильтруются с помощью функции search_array с тем же набором ключевых слов COVID-19. Эти отфильтрованные заголовки сохраняются в новом массиве с именем new_covid_urls.

Этот процесс повторяется еще раз, чтобы оптимизировать количество извлекаемых релевантных заголовков. Отфильтрованные заголовки сохраняются в другом массиве с именем newest_covid_urls. Чтобы сохранить соответствующие заголовки в объекте S3, были повторены URL-адреса внутри new_covid_urls и newest_covid_urls. Для каждого веб-сайта в этих массивах URL-адрес был преобразован в HTML, чтобы определить заголовок URL-адреса. После проверки на повторение в массиве headlines заголовок был добавлен внутри объекта S3 и массива headlines. Последний массив headlines был помещен внутри объекта S3.

headlines = []
for index in data:
    new_data = extractWebsites(index, 'interactive')
    covid_urls = []
    arr_keywords = ['coronavirus', 'COVID', 'covid', 'pandemic', 'epidemic', 'disease', 'SARS', 'sars', 'virus']
    for index1 in new_data:
        if (search_array(index1, arr_keywords)):
            covid_urls.append(index1)
    count = 0
    for val in covid_urls:
        if count > 13:
            break
        future = time.time() + 600
        newer_data = extractWebsites(val, "interactive")
        new_covid_urls = []
        for index1 in newer_data:
            if (search_array(index1, arr_keywords)):
                new_covid_urls.append(index1)
        for value in new_covid_urls:
            if (time.time()) > future:
                break
            newest_data = extractWebsites(value, "interactive")
            newest_covid_urls = []
            for index2 in newest_data:
                if (time.time()) > future:
                    break
                if (search_array(index2, arr_keywords)):
                    newest_covid_urls.append(index2)
            for urls1 in newest_covid_urls:
                if ((time.time()) > future):
                    break
                try:
                    webUrl = urllib.request.urlopen(urls1)
                    data = webUrl.read()
                    soup = bs(data)
                    try:
                        title = soup.find('title').string
                        if (title not in headlines) and (search_array(title, arr_keywords)):
                            headlines.append(title)
                            content = "\n".join(headlines)
                            s3.Object('headlines', 'headline.txt').put(Body=content)
                    except TypeError as exception:
                        print("Exception occured")
                        continue
                except:
                    continue
        for urls in new_covid_urls:
            if (time.time()) > future:
                break
            try:
                webUrl = urllib.request.urlopen(urls)
                data = webUrl.read()
                soup = bs(data)
                try:
                    title = soup.find('title').string
                    if (title not in headlines) and (search_array(title, arr_keywords)):
                        headlines.append(title)
                        content = "\n".join(headlines)
                        s3.Object('headlines', 'headline.txt').put(Body=content)
                        
                except:
                    continue
            except:
                continue
                
content = "\n".join(headlines)
s3.Object('headlines', 'headline.txt').put(Body=content)

В зависимости от того, выполняется ли этот код на вашем локальном компьютере или в экземпляре AWS Sagemaker, время выполнения кода может варьироваться от нескольких часов до нескольких дней. Код в настоящее время работает на экземпляре ml.c5.xlarge с хранилищем EBS 20 ГБ; обратите внимание, что работа на Sagemaker требует дополнительных затрат в отличие от вашей локальной машины.

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

Щелкните эту ссылку для доступа к репозиторию Github с подробным объяснением кода: Github.