Извлечь максимум из новостей в интернете, часть 1

1ce3a61b03a6c0d51d7bfd01e3d27cbd.png

Извлечь максимум из новостей в интернете

Навеяно статьей Почему я по-прежнему пользуюсь RSS

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

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

Будут следующие части:

  1. Часть 1:

  • Какую информацию я вообще потребляю через новости;

  • Чтение программами (rss-агрегаторами) — что использую лично я;

  • Форматы RSS и Atom, как их можно обрабатывать программами на локальном компьютере;

  1. Часть 2:

  • Автоматизаторы (zapier, ifttt);

  1. Часть 3:

  • Как я автоматизировал доставку аудио-подкастов на свой плеер.

Часть 1

Какую информацию я вообще потребляю с помощью новостей

Раньше, когда я много времени проводил в метро по пути на работу и обратно, то загружал новости в свой планшет и потом, уже без интернета спокойно читал то, что было интересно (не все помнят, но интернет в метро был не всегда!). Например, баш и ЖЖ поставляют контент в формате RSS. Новости со всего мира от лента.ру есть в формате RSS. Поговаривают, что в древние времена и твиттер можно было читать через ленту новостей в формате RSS! Но потом пришли жадные менеджеры и сказали, что так они не получат много денег, поэтому RSS исчез из твиттера.

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

Потом обнаружил, что многие другие, интересные мне темы (например, аудиоподкасты) тоже можно отслеживать через ленту новостей. Вот, например, Радио Маяк.

Чтение программами (rss-агрегаторами)

Чтобы читать новости на планшете, можно использовать любую подходящую программу. Благо, их очень много — для Андроида, для Apple и для десктопов.

В какой-то момент пришлось удалить читалку новостей с планшета, т.к. это сильно мешало сну — в постели чтение новостей » перед сном» могло занимать до часа. Но это уже другая история.

Для десктопа я раньше использовал RSS Owl:

RSS OwlRSS Owl

А потом с удивлением открыл для себя продукт от JetBrains: OMEA Reader:

JetBrains OMEA ReaderJetBrains OMEA Reader

Функционал у продукта JetBrains просто космический, поэтому как только я на него перешёл, то уже и не уходил:

  • можно ставить комментарии к новостям

  • можно фильтровать новости и по отборам назначать тэги, выделять цветом или выдавать оповещения на экране

  • иерархическая группировка лент новостей

  • и многое-многое другое.

Форматы RSS и Atom, как их можно обрабатывать программами на локальном компьютере

Новости, по сути — это простой xml-файл. Есть формат RSS (очень старый формат, непонятно кто его поддерживает и будет ли он развиваться). Мне он не очень нравится:

  • из-за формата дат — Sun, 28 May 2017 09:00:00 GMT, что затрудняло для меня автоматическую обработку

  • из-за того, что непонятна спецификация RSS, (во всяком случае я нашёл несколько разных вариантов). Расскажу про особенности его обработки дальше. Тем не менее, это самый узнаваемый и устоявшийся формат, известный всем.

bf69f9e040a05937c10c875a0e375a8d.png

На замену RSS фирма Google придумала свой формат — Atom, и вроде бы даже поддерживает его.

16b1a317a94b087da739e834824fe5b3.png

Файлы из интернета, в том числе и новости, можно читать с помощью curl, wget и (почему-бы и нет?) с помощью Power-shell.

Пока писал статью, с удивлением узнал, что в Windows 10 curl уже есть » из коробки » и не надо ничего скачивать и настраивать. Приятно.

Curl:

chcp 65001  
  
curl ^  
  --header "user-agent: cURL automated task" ^  
  --output "%TEMP%\updates.xml" ^  
  "https://news.webits.1c.ru/news/Updates/atom"

Если на компьютере включен Антивирус Касперского, то можно получить ошибку curl: (35) schannel: next InitializeSecurityContext failed: Unknown error (0x80092012) - Функция отзыва не смогла произвести проверку отзыва для сертификата. Я просто отключил антивирус на 5 минут.

Файл записывается без BOM, что может вызвать проблемы с дальнейшей обработкой. Наверное это как-то настроено на сервере.

Power-shell:

# file: Get-News-001.ps1  
Clear-Host  
  
$webClient = New-Object Net.WebClient  
$webClient.UseDefaultCredentials = $true  
$webClient.Proxy.Credentials = $webClient.Credentials  
$webClient.Headers.Add("user-agent", "PowerShell automated task")  
  
# Подозреваю, что из-за того, что данные передаются без BOM, то получение данных  
# через DownloadString с последующим выводом выдаст на экран кракозябры.  
# Поэтому в явном виде преобразуем в UTF8  
$newsData = $webClient.DownloadData("https://news.webits.1c.ru/news/Updates/atom")  
  
Write-Host ([System.Text.Encoding]::UTF8).GetString($newsData)

Не забываем, что в power-shell надо включить возможность запуска неподписанных макросов. Это делается или в настройках вашей IDE, или прямо в командной строке, параметром -ExecutionPolicy=RemoteSigned

powershell -file "Get-News-001.ps1" -ExecutionPolicy=RemoteSigned

Что нам это даст? Пока ничего интересного. Но так как новости — это структурированный текст в формате xml, почему-бы не обработать его? Например, найти новость по значению какой-нибудь категории?

Найдём в новостях от 1С новости со значениями категорий « Вид новости обновления=Публикация новой версии» и « Продукт=Комплексная автоматизация»

Пример кода:

# file: Get-News-002.ps1
Clear-Host

# Настройки отбора, в виде массива
$CategoryProducts = @(
    # "Продукт=1С:Библиотека стандартных подсистем", # Заполнить!
    "Продукт=Комплексная автоматизация" # Заполнить!
)
$CategoryNewsTypes = @(
    "Вид новости обновлений=Публикация новой версии"
)

$webClient = New-Object Net.WebClient
$webClient.UseDefaultCredentials = $true
$webClient.Proxy.Credentials = $webClient.Credentials
$webClient.Headers.Add("user-agent", "PowerShell automated task")

# Т.к. данные без BOM, то лучше явно преобразовать.
$newsData = $webClient.DownloadData("https://news.webits.1c.ru/news/Updates/atom")
[xml]$news = ([System.Text.Encoding]::UTF8).GetString($newsData)
#[xml]$news = Get-Content -Encoding UTF8 -LiteralPath "$($env:TEMP)\updates.xml"

for($c1=0;$c1 -lt $news.feed.entry.Count;$c1++){
    # Получим новость
    $entry = $news.feed.entry[$c1]
    $ProductName    = ""
    $bFoundProduct  = $false
    $bFoundNewsType = $false
    for($c2=0;$c2 -lt $entry.category.Count;$c2++){
        # Получим и проверим категории новости
        $CategoryProducts | ForEach-Object {
            if($entry.category[$c2].term -eq $_){
                $ProductName = $entry.category[$c2].term
                $bFoundProduct = $true
            }
        }
        $CategoryNewsTypes | ForEach-Object {
            if($entry.category[$c2].term -eq $_){
                $bFoundNewsType = $true
            }
        }
    }
    if ($bFoundProduct -and $bFoundNewsType) {
        Write-Host ("Найдена подходящая новость. УИН: {0}, Заголовок: {1}" -f ($entry.id, $entry.title))
    }

}

Уже интереснее. А что мы можем сделать, если нашли нужную категорию? Например, можно самому себе отправить письмо.

Напишем код сразу так, чтобы письмо о выходе новости не отправлялось несколько раз — в отдельном файлике будем хранить entry.id — уникальный идентификатор новости и дату отправки.

# file: Get-News-003.ps1
Clear-Host

# Файл с информацией об отправленных email.
$sendedEmailsPath = "$($env:TEMP)\sended.csv" # Заполнить!
if(Test-Path $sendedEmailsPath){
    # Файл существует
} else {
    # Файла не существует - создать пустой файл
    Add-Content -LiteralPath $sendedEmailsPath -Encoding UTF8 -Force -Value ""
}
$sendedEmails = Get-Content -LiteralPath $sendedEmailsPath -Encoding UTF8 -Force

# Настройки почты
$CurrentDate        = Get-Date 
$CurrentDate_String = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$From               = "news_center_tester@mail.ru" # Заполнить!
$To                 = "old-coder-75@mail.ru" # Заполнить!
$EncodingUTF8       = [System.Text.Encoding]::UTF8
$UserName           = "news_center_tester" # Заполнить!
$Password           = "*****" # Заполнить!
$Credential         = New-Object -TypeName System.Management.Automation.PSCredential($UserName, (ConvertTo-SecureString $Password -AsPlainText -Force))

$SMTPServer         = "smtp.mail.ru" # Заполнить!
$SMTPPort           = 587 # Заполнить!

# Настройки отбора, в виде массива
$CategoryProducts = @(
    # "Продукт=1С:Библиотека стандартных подсистем", # Заполнить!
    "Продукт=Комплексная автоматизация" # Заполнить!
)
$CategoryNewsTypes = @(
    "Вид новости обновлений=Публикация новой версии"
)

$webClient = New-Object Net.WebClient
$webClient.UseDefaultCredentials = $true
$webClient.Proxy.Credentials = $webClient.Credentials
$webClient.Headers.Add("user-agent", "PowerShell automated task")

$newsData = $webClient.DownloadData("https://news.webits.1c.ru/news/Updates/atom")
[xml]$news = ([System.Text.Encoding]::UTF8).GetString($newsData)
#[xml]$news = Get-Content -Encoding UTF8 -LiteralPath "$($env:TEMP)\updates.xml"

for($c1=0;$c1 -lt $news.feed.entry.Count;$c1++){
    # Получим новость
    $entry = $news.feed.entry[$c1]
    $ProductName    = ""
    $bFoundProduct  = $false
    $bFoundNewsType = $false
    for($c2=0;$c2 -lt $entry.category.Count;$c2++){
        # Получим и проверим категории новости
        $CategoryProducts | ForEach-Object {
            if($entry.category[$c2].term -eq $_){
                $ProductName = $entry.category[$c2].term
                $bFoundProduct = $true
            }
        }
        $CategoryNewsTypes | ForEach-Object {
            if($entry.category[$c2].term -eq $_){
                $bFoundNewsType = $true
            }
        }
    }

    if ($bFoundProduct -and $bFoundNewsType) {

           Write-Host ("Найдена подходящая новость. УИН: {0}, Заголовок: {1}" -f ($entry.id, $entry.title))

        # Проверим, была ли информация уже отправлена по email?
        # Информация об отправке email хранится по каждому id новости в лог-файле $sendedEmailsPath.
        $bEmailWasSent = $false
        foreach ($sendedEmail in $sendedEmails) {
            if ( $sendedEmail.StartsWith($entry.id) ) {
                $bEmailWasSent = $true
                break
            }
        }

        # По этой новости ещё не создавался email.
        if ($bEmailWasSent -eq $false){

            Write-Host "По подходящей новости отправляем емейл..."

            # Отправить почту
            $Subject = $entry.title
            $Body = "

Выход новой версии

" + ` "

" + ` $entry.summary."#cdata-section" + ` "

" Send-MailMessage ` -From $From ` -To $To ` -Body $Body ` -BodyAsHtml ` -Credential $Credential ` -Encoding $EncodingUTF8 ` -SmtpServer $SMTPServer ` -Subject $Subject ` -Priority High ` -UseSsl ` -Port $SMTPPort ` -Verbose # Записать в лог, чтобы повторно не отправлять почту по этой новости $LogString = $entry.id + ";" + $CurrentDate_String + ";" Add-Content -LiteralPath $sendedEmailsPath -Encoding UTF8 -Force -Value $LogString } else { Write-Host "По подходящей новости уже был отправлен емейл." } } }

Хм. Не хочется вызывать скрипт ручками. Было бы неплохо это вызывать регулярно, например каждые 2 часа. Настроим «Планировщик заданий». В окне запуска (Win+R) вызовем »taskschd.msc».

Добавим новое расписание:

624fc65a010f1d2c62702b596fb67545.png

Настроим частоту запуска » каждые 4 часа » (триггер):

ec711c9f40e048eaa7f81ee979ca9f63.png

Добавим запуск скрипта (» Действие»):

5a1af14cf5eba3cdbf5d4ef01deb2ff3.png

Путь к программе powershell.exe надо указывать полный. И в аргументах — или полный путь к скрипту в параметре -file, или заполнить » Рабочая папка».

Немного тюнинга — не люблю всплывающие окна. А при выполнении задания по расписанию, каждые 4 часа вылезает на весь экран окно выполнения скрипта. Можно запускать код power-shell через SilentCMD или CreateProcessHidden. Правда, на последнюю ругается антивирус, но не сильно.

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

Что ж, надеюсь, что информация оказалась полезной.
С интересом почитаю комментарии.

Остальные главы постараюсь в ближайшее время выложить.

© Habrahabr.ru