
Teilen Sie:
Ben ist ein Entwickler im zweiten Beruf, der zuvor ein Jahrzehnt in den Bereichen Erwachsenenbildung, Community-Organisation und Non-Profit-Management tätig war. Er arbeitete als Anwalt für Entwickler bei Vonage. Er schreibt regelmäßig über die Überschneidung von Gemeindeentwicklung und Technologie. Ursprünglich aus Südkalifornien stammend und lange Zeit in New York City ansässig, wohnt Ben jetzt in der Nähe von Tel Aviv, Israel.
Mit Ruby das Web nach Updates durchsuchen und SMS-Warnungen senden
Lesedauer: 18 Minuten
Wir alle kennen das. Man wacht auf, es ist ein neuer Tag, und man muss einfach die Antwort auf die brennendste Frage wissen. Ist es schon Wochenende? Die Woche war so vollgepackt mit beruflichen und privaten Verpflichtungen. Alles, was Sie tun möchten, ist, sich ein paar Tage zurückzulehnen und zu entspannen.
Um diese Frage zu beantworten, könnten Sie natürlich Ihre Kalender-App auf Ihrem Telefon öffnen oder Ihren persönlichen digitalen Haushaltsassistenten fragen. Aber warum sollten Sie das tun, wenn Sie stattdessen eine App entwickeln können, die Ihnen eine Textnachricht schickt?
Wir werden eine Ruby on Rails-Anwendung erstellen, die Folgendes tut:
Ermöglicht sowohl neue Abonnenten als auch die Möglichkeit, sich von der Liste abzumelden
Kratzt die Antwort auf unsere Frage von isittheweekend.com
Sendet die Antwort aus unseren gescrapten Daten täglich an alle abonnierten Empfänger
Um das Ganze zu vervollständigen, werden wir auch eine Rake-Aufgabe erstellen, die alle diese Aufgaben auf einmal ausführt und deren Ausführung einmal alle 24 Stunden festgelegt wird.
Wenn Sie es bevorzugen, können Sie auch eine voll funktionsfähige Version dieser Anwendung auf GitHub.
Fangen wir an!
Voraussetzungen
Vonage API-Konto
Um dieses Tutorial durchzuführen, benötigen Sie ein Vonage API-Konto. Wenn Sie noch keines haben, können Sie sich noch heute anmelden und mit einem kostenlosen Guthaben beginnen. Sobald Sie ein Konto haben, finden Sie Ihren API-Schlüssel und Ihr API-Geheimnis oben auf dem Vonage-API-Dashboard.
In diesem Lernprogramm wird auch eine virtuelle Telefonnummer verwendet. Um eine zu erwerben, gehen Sie zu Rufnummern > Rufnummern kaufen und suchen Sie nach einer Nummer, die Ihren Anforderungen entspricht.
Generieren der Rails-Anwendung
Als erstes müssen wir unsere neue Rails-Anwendung erstellen. Führen Sie in der Befehlszeile Folgendes aus:
Dadurch wird die notwendige Dateistruktur für unsere Rails-Anwendung erstellt und die Standarddatenbank auf PostgreSQL gesetzt.
Sobald dies geschehen ist, cd in das erstellte Verzeichnis. Bevor wir unsere Abhängigkeiten installieren, fügen wir die zusätzlichen Edelsteine hinzu, die unsere Anwendung verwenden wird.
Öffnen Sie den Code in Ihrem bevorzugten Code-Editor und navigieren Sie zur Gemfile. Innerhalb der Gemfile fügen Sie die folgenden Edelsteine ein:
gem 'nexmo'
gem 'watir'
gem 'webdrivers', '~> 4.0'
gem 'whenever', require: false
gem 'dotenv-rails'Wir verwenden das nexmo um die SMS-Updates zu versenden, die watir und webdrivers um die HTTP-Anfrage an eine Website mit dynamischen JavaScript-Inhalten zu stellen, das whenever um die Rake-Aufgabe zu planen, und das dotenv-rails um die Umgebungsvariablen zu verwalten.
Nachdem Sie die Gemfilegespeichert haben, können Sie bundle install über die Befehlszeile auszuführen.
Der nächste Schritt ist die Erstellung unseres Datenbankschemas und unserer Modelle.
Erstellen des Datenbankschemas und der Modelle
Nachdem unsere Rails-Anwendung erstellt und ihre Abhängigkeiten installiert sind, besteht die nächste Aufgabe darin, das richtige Datenbankschema für die Daten zu erstellen, die wir für den Betrieb unserer Anwendung benötigen. Wir müssen die folgenden Arten von Informationen speichern:
Empfängern: Die Liste der Abonnenten mit ihren Telefonnummern
DiffStorage: Kopien der Websitedaten, mit denen verglichen wird, um festzustellen, ob es eine Änderung gab
Wir werden das Rails-Generator-Tool verwenden, um die Migrationsdateien zu erstellen und anschließend jede einzelne Datei zu bearbeiten.
Diese Befehle erstellen sowohl Modelldateien in app/models und Migrationsdateien in db/migrate. Bevor Sie diese Änderungen in Ihre Anwendung übernehmen, überprüfen Sie nach Abschluss der Generatoraktionen die in beiden Verzeichnissen erstellten Dateien, um sicherzustellen, dass sie korrekt sind.
Insbesondere müssen Sie in den Migrationsdateien sicherstellen, dass jede Migration Folgendes enthält t.timestampsenthält, die ein created_at und updated_at Spalte zur Tabelle hinzufügt. Sie sollten auch die number und subscribed Spalten in der Recipient Migrationsdatei sehen, wobei die Typen auf string und booleangesetzt sind. In ähnlicher Weise sollten Sie eine Spalte in der DiffStorage Migrationsdatei eine Spalte für website_data mit dem Typ text.
Die Modelldateien innerhalb von app/models sollten leer sein, abgesehen von den Klassendeklarationen und deren Vererbung von ApplicationRecord.
Wenn es zufriedenstellend aussieht, ist es an der Zeit, das Programm rake db:migrate über die Befehlszeile auszuführen. Der Befehl gibt die Ergebnisse auf Ihrer Konsole aus, und wenn Sie die Datei db/schema.rb überprüfen, können Sie sehen, dass das von Ihnen erstellte Schema innerhalb der Anwendung initialisiert wurde.
Zu guter Letzt müssen wir auch Messenger und Scraper Modelle erstellen, aber wir brauchen keine Migration für sie. Dazu führen wir den Rails-Generator erneut aus und fügen ein --migration=false Flag an:
Jetzt ist es an der Zeit, die Logik innerhalb der Modelle zu definieren.
Definieren der Modelle
Wie bereits erwähnt, haben wir vier Modelle, die für bestimmte Bereiche der Anwendung zuständig sind:
DiffStorage: Überprüft, ob es Unterschiede in den Daten der Website gibtRecipient: Verwaltet das Hinzufügen und Entfernen von AbonnentenMessenger: Verwaltet den Versand von SMS-NachrichtenScraper: Verantwortlich für das Scraping der Website nach Daten
Definieren des DiffStorage-Modells
Das DiffStorage Modell wird zwei Klassenmodelle enthalten. Das eine enthält die URL, die wir auslesen wollen. Das zweite prüft, ob sich seit dem letzten Scraping der Website etwas geändert hat, und ruft die nächsten Schritte in der Anwendung auf, wenn die Bedingungen erfüllt sind.
Zunächst definieren wir die URL in einer eigenen Methode, so dass sie an einer einzigen Stelle existiert und bei Bedarf später leicht geändert werden kann:
def self.url
'http://isittheweekend.com'
endAls nächstes wird der Großteil dieses Modells innerhalb der #check_last_record Methode der Klasse:
def self.check_last_record
today_answer = Scraper.call(self.url)
if DiffStorage.any?
yesterday_answer = DiffStorage.last
else
yesterday_answer = ''
end
Messenger.send_update_message(Recipient.all, yesterday_answer, today_answer)
endDie obige Methode ruft zunächst die Methode in der Klasse Scraper Klasse auf, die mit dem Scraping der Website beginnt, um den aktuellsten Schnappschuss zu erhalten, und weist diese Daten an today_answer. Dann wird der nächste Schritt in eine if Anweisung, die fragt, ob es irgendwelche Datensätze in DiffStorage. Wenn dort frühere Datensätze gespeichert sind, greift die Methode auf den neuesten Datensatz zu und ordnet ihn yesterday_answer. Wenn es keine vorherigen Datensätze gibt, wird eine leere Zeichenkette zugewiesen yesterday_answer. Zum Schluss werden die Empfänger und die beiden Variablen an das Messenger Modell zur Verarbeitung für das Versenden der Nachricht.
Definition des Scraper-Modells
Das Scraper Das Modell ist für das Sammeln der Daten von isittheweekend.com um festzustellen, ob es tatsächlich Wochenende ist oder nicht. Das Modell wird vier Klassenmethoden haben, die wir hier definieren werden:
require 'nokogiri'
require 'webdrivers/chromedriver'
require 'watir'
class Scraper < ApplicationRecord
def self.call(url)
self.get_url(url)
end
def self.get_url(url)
doc = HTTParty.get(url)
browser = Watir::Browser.new :chrome, headless: true
browser.goto(url)
parsed_page ||= Nokogiri::HTML.parse(browser.html)
answer = parsed_page.css('h1#isit').text
self.check_text(answer)
end
def self.check_text(data)
if data == '' || data == nil
puts "There was no text received from the web scrape."
exit
else
puts "There was data in the text received from the web scrape."
self.store_text(data)
end
end
def self.store_text(text)
record = DiffStorage.new
record.website_data = text
if record.save
puts "Record Updated Successfully"
end
return record
end
endJede Aktion innerhalb des Schürfvorgangs wird in einer eigenen kleinen Methode definiert, um unsere Anliegen getrennt zu halten. Die Methode #call Methode ist der Einstiegspunkt für die Klasse. Sie wird von anderen Methoden außerhalb der Klasse aufgerufen. Die Methode #get_url Methode stellt die HTTP-Anfrage, indem sie eine Anfrage des Chrome-Browsers mit Hilfe der Watir Bibliothek simuliert und analysiert sie mit Nokogiri. Die Methode #check_text Methode prüft, ob Daten erhalten wurden. Die Methode #store_text Methode speichert diese Daten in der Datenbank.
Definition des Messenger-Modells
Innerhalb des Messenger Modells befindet sich der gesamte Code, der für den Versand der täglichen SMS-Aktualisierung an die Abonnenten verantwortlich ist. Wir werden eine Methode erstellen, die die Nachricht sendet, eine Methode, die den Wochenend-Antworttext zusammenstellt, eine Methode, die die gesamte Nachricht zusammenstellt, und eine Methode, die eine Bestätigungsnachricht verwaltet, wenn ein Abonnent eine Abmeldeanfrage sendet.
Zunächst die Methode zum Senden der Aktualisierungsnachricht:
def self.send_update_message(recipients, yesterday, today)
@client = Nexmo::Client.new(
api_key: ENV['NEXMO_API_KEY'],
api_secret: ENV['NEXMO_API_SECRET']
)
puts "Sending Message to Each Recipient"
recipients.each do |recipient|
if recipient.subscribed == true
client.sms.send(
from: ENV['FROM_NUMBER'],
to: recipient.number,
text: self.weekend_message(yesterday, today)
)
puts "Sent message to #{recipient.number}"
end
end
endDer Wert für den text Parameter bezieht sich auf eine Klassenmethode namens #weekend_message. Diese Methode setzt die Zeichenfolge für die Wochenendaktualisierung zusammen, indem sie prüft, ob der heutige Tag mit dem gestrigen Tag identisch ist oder nicht:
def self.weekend_message(yesterday, today)
if today == yesterday
response = "Today is the same as yesterday, and the answer is #{today}."
elsif today =! yesterday
response = "Today is not the same as yesterday, the answer for today is #{today}."
else
response = 'Today and yesterday are both neither affirmative or positive. Are we in an alternative dimension of time and space?'
end
self.compose_message(response)
endAls nächstes wird die Methode, die den HEREDOC Zeichenfolge mit dem Text der Nachricht:
def self.compose_message(response)
<<~HEREDOC
Hello!
It is a new day, but is it a weekend day?
#{response}
To be removed from the list please respond with "1".
HEREDOC
endSchließlich die Methode zum Senden einer Bestätigungsnachricht für den Umzug:
def self.send_removal_message(to)
@client.sms.send(
from: ENV['FROM_NUMBER'],
to: to,
text: 'You have been successfully removed.'
)
endDas letzte Modell, das wir definieren müssen, bevor wir mit dem nächsten Schritt fortfahren, ist das Recipient Modell.
Definition des Empfängermodells
Dieses Modell enthält keine der Methoden seiner Klasse. Die einzige Ergänzung, die wir an diesem Modell vornehmen werden, ist das Hinzufügen von zwei Validierungen zu den Daten für Empfänger. Diese Überprüfungen dienen als Schutz beim Hinzufügen neuer Telefonnummern zur Datenbank. Wir überprüfen, ob a) eine Nummer tatsächlich in den Daten enthalten ist und b) die Nummer kein Duplikat eines bereits vorhandenen Datensatzes ist. Um diese Überprüfungen durchzuführen, fügen wir zwei Zeilen unter der Klassendefinition hinzu:
class Recipient < ApplicationRecord
validates :number, presence: true
validates :number, uniqueness: true
end Erstellen Sie den Controller und die Routes
Wir sind kurz davor, die Konstruktion unserer Anwendung abzuschließen! Der nächste Schritt ist die Definition der Controller-Aktionen, die den Ablauf der Anwendung bestimmen werden. Lassen Sie uns zunächst den Controller mit dem Rails-Generator von der Kommandozeile aus erzeugen:
Dadurch wird eine neue leere Controller-Datei in app/controllers namens weekend_checker_controller.rb und ergänzende View-Dateien in app/views/weekend_checker. Wir werden in Kürze eine Indexansicht hinzufügen. Zu diesem Zeitpunkt konzentrieren wir uns auf den Controller.
Der Kontrolleur benötigt drei Aktionen, die drei Strecken entsprechen: #index, #create und #event. Die #index wird die Standardansicht und die einzige Ansicht für unsere Website sein. Dort können sich Personen für die Liste anmelden. Die #create Route wird der Ort sein, an dem neue Numbers bearbeitet werden. Schließlich wird die #event schließlich empfängt die Anwendung Webhook-Daten von der SMS API, einschließlich Abmeldeanforderungen, und verarbeitet sie.
class WeekendCheckerController < ApplicationController
def index
end
def create
@recipient = Recipient.new(recipient_params)
if @recipient.save
flash[:notice] = "Phone number saved successfully."
else
flash[:alert] = "Form did not save. Please fix and try again."
end
redirect_to '/'
end
def event
if params[:text] == '1'
recipient = Recipient.find_by(number: params[:msisdn])
if recipient
if recipient.update(subscribed: false)
Messenger.send_removal_message(params[:msisdn])
end
end
end
puts params
head :no_content
end
private
def recipient_params
params.permit(:number, :subscribed)
end
end
Diese drei Controller-Aktionen benötigen drei entsprechende Routen, die in config/routes.rb:
Rails.application.routes.draw do
get '/', to: 'weekend_checker#index'
get '/webhooks/event', to: 'weekend_checker#event'
post '/recipient/new', to: 'weekend_checker#create'
endDer vorletzte Punkt bei der Einrichtung unseres Anwendungscodes ist die Erstellung einer Basisansicht für die / Route.
Definieren der Ansicht
Um die SMS-Liste zu abonnieren, erstellen wir eine Ansicht, die auf der obersten Ebene der URL zugänglich ist und ein Anmeldeformular enthält.
Innerhalb des app/views/weekend_checker Ordners fügen Sie eine index.html.erb Datei. Sie wird den folgenden Code enthalten:
<h2>Is It The Weekend? Get a Daily Text to Find Out!</h2>
<p>
This is a free service that will analyze <a href="http://isittheweekend.com">isittheweekend.com</a> and check for any updates once a day. If there is an update it will send you a text message at the number you provide.
</p>
<p>
To remove yourself from the SMS list, reply to the text message you receive with the number "1".
</p>
<p>
SMS messages are sent using the <a href="/home">Nexmo SMS API</a>.
</p>
<% flash.each do |type, msg| %>
<div>
<%= msg %>
</div>
<% end %>
<%= form_with model: @recipient, url: "/recipient/new" do |f| %>
<%= f.telephone_field :number, :placeholder => '12122222222' %>
<%= f.hidden_field :subscribed, value: true %>
<%= f.submit "Add Number" %>
<% end %>Die letzte Aufgabe, die wir erledigen müssen, ist das Einrichten unserer neuen Rake-Aufgabe, die den gesamten Code ausführt, und das Konfigurieren des whenever gem so zu konfigurieren, dass die Rake-Aufgabe einmal am Tag ausgeführt wird.
Erstellen Sie die Aufgabe "Rake" und planen Sie sie ein
Auch hier werden wir einen Rails-Generator von der Kommandozeile aus verwenden, um die Datei für unseren Rake-Task zu erstellen. Führen Sie auf der Kommandozeile Folgendes aus:
Die obige Aufgabe erstellt eine Datei in lib/tasks mit dem Namen scraper.rake. Wenn wir sie in unserem Code-Editor öffnen, wird sie wie folgt aussehen:
namespace :scraper do
desc "TODO"
task :check_site_update => :environment do
end
end
Definieren wir die desc mit einer kurzen Zeichenfolge, was diese Aufgabe tun wird: desc "Check Website for Any Updates". Als nächstes fügen wir innerhalb des task Blocks fügen wir die DiffStorage#check_last_record Klassenmethode hinzu, die der Einstiegspunkt für die gesamte Arbeit ist, die wir zuvor erstellt haben:
namespace :scraper do
desc "Check Website for Any Updates"
task :check_site_update => :environment do
DiffStorage.check_last_record
end
end
Nun, da unsere Rake-Aufgabe definiert ist, müssen wir zum Schluss noch das whenever gem initialisieren und ihm mitteilen, dass die Aufgabe einmal pro Tag ausgeführt werden soll. Dazu führen wir zunächst den Initialisierungsbefehl für den Edelstein von der Kommandozeile aus:
Der obige Befehl erstellt eine schedule.rb Datei im Ordner config/ Ordner. Fügen Sie den folgenden Code in diese Datei ein, um die scraper:check_site_update Aufgabe täglich auszuführen:
every 1.day do
rake "scraper:check_site_update"
endJetzt, da der Zeitplan erstellt ist, müssen wir die Datei crontab auf unserem Rechner aktualisieren, damit sie von diesem neuen Auftrag weiß. Dazu führen wir bundle exec whenever --update-crontab von der Befehlszeile aus aufrufen. Danach ist die Aufgabe vollständig initialisiert und so konfiguriert, dass sie einmal pro Tag auf unserem Rechner ausgeführt wird.
Der Code für unsere Anwendung ist fertig. Das Einzige, was jetzt noch fehlt, ist die Erstellung unseres Nexmo Accounts, die Beschaffung unserer Nexmo API-Zugangsdaten und die Einrichtung einer virtuellen Telefonnummer, über die wir die täglichen Textnachrichten versenden. Sobald wir diese Informationen haben, fügen wir sie als Umgebungsvariablen zu unserer Anwendung hinzu.
Nexmo API Anmeldedaten und Telefonnummer
Um einen Account zu erstellen, navigieren Sie zum Nexmo Dashboard und führen Sie die Registrierungsschritte durch. Sobald Sie die Registrierung abgeschlossen haben, gelangen Sie zu Ihrem Dashboard.
Falls Sie dies noch nicht getan haben, erstellen Sie eine .env Datei im obersten Verzeichnis Ihrer Anwendung und fügen Sie Ihre NEXMO_API_KEY und NEXMO_API_SECRET hinzu. Die Werte dafür finden Sie am oberen Rand der Dashboard-Seite unter der Your API credentials Überschrift.
NEXMO_API_KEY=
NEXMO_API_SECRET=Die nächste Aufgabe, die wir innerhalb des Dashboards erledigen müssen, ist die Bereitstellung einer Telefonnummer. Nachdem Sie auf den Link Numbers in der Seitenleiste klicken, wird ein Dropdown-Menü angezeigt. Sobald Sie die Option Buy numbers auswählen und dann auf die Schaltfläche Search klicken, sehen Sie eine Liste möglicher Numbers, die Sie erwerben können.
Bei der Suche nach Numbers nach Merkmalen, Land und Typ empfiehlt es sich, das Land auszuwählen, in dem Ihre Nutzer ansässig sind, SMS für Merkmale und Mobile für den Typ.
Nachdem Sie auf die orangefarbene Buy Schaltfläche für die Nummer, die Sie kaufen möchten, können Sie diese Nummer in Ihre .env Datei als eine neue Variable mit dem Namen FROM_NUMBER:
NEXMO_API_KEY=
NEXMO_API_SECRET=
FROM_NUMBER=Der letzte Punkt, den wir in unserem Dashboard erledigen müssen, ist die Bereitstellung einer extern zugänglichen URL als Ereignis-Webhook für die Telefonnummer. Für Entwicklungszwecke, ngrok ein gutes Werkzeug, und Sie können dieser diese Anleitung folgen, wie Sie es zum Laufen bringen können.
Auf dem Dashboard Numbers in der Seitenleiste, sobald Sie die Option Your numbers wählen, sehen Sie Ihre neu eingerichtete Telefonnummer in einer Listendarstellung. Nachdem Sie auf das Zahnradsymbol geklickt haben, um die Eigenschaften zu verwalten, wird Ihnen ein Einstellungsdialogmenü angezeigt.
Im obigen Beispiel des Screenshots würden Sie das Inbound Webhook URL Textfeld durch Ihre eigene URL ersetzen, die mit /webhooks/event.
Das war's! Unser Code ist fertiggestellt und unsere Nexmo-Anmeldedaten sind bereit. An diesem Punkt haben Sie die Wahl, wie Sie Ihre Anwendung ausführen möchten. Sie können sie entweder lokal ausführen oder sie bei einem externen Hosting-Anbieter wie Heroku bereitstellen. Im letzten Schritt werden wir besprechen, wie man die Anwendung lokal ausführt.
Wenn Sie daran interessiert sind, es für eine längerfristige Lösung einzusetzen, können Sie das GitHub-Repository und klicken Sie auf die Schaltfläche Deploy to Heroku oben in der README klicken, um diesen Prozess zu starten.
Ausführen der Anwendung
Wir sind nun bereit, unsere brandneue Anwendung auszuführen! Um sie lokal ausführen zu können, muss der Rails-Event-Webhook für die Außenwelt außerhalb Ihrer lokalen Umgebung zugänglich sein. Wenn Sie zum Beispiel ngrok verwenden, nachdem Sie dieser Anleitung dann müssen sowohl die Rails-Anwendung als auch ngrok gleichzeitig laufen.
Um die Rails-Anwendung zu starten, führen Sie Folgendes in der Befehlszeile aus:
Dann können Sie mit dem Browser Ihrer Wahl zu folgender Adresse navigieren localhost:3000. Sie werden das von Ihnen erstellte Anmeldeformular sehen. Füllen Sie es mit Ihrer Telefonnummer aus und schicken Sie es ab. Sobald die Rake-Aufgabe ausgeführt wird, sollten Sie eine SMS erhalten, die Sie darüber informiert, ob Wochenende ist und ob heute ein anderer Tag ist als gestern!
Nächste Schritte
Die von uns erstellte Anwendung ist zwar skurril, zeigt aber das Potenzial der Nutzung von Web-Scraping und SMS zur Erstellung einer Anwendung, die Abonnenten mit aktuellen Informationen versorgt. Es gibt unzählige potenzielle Anwendungsfälle für eine derartige Anwendung. Unabhängig davon, ob Sie daran interessiert sind, genau dieses Szenario nachzubauen oder den Code für Ihren eigenen Anwendungsfall zu portieren, gibt es noch viel mehr zu diesem Thema zu entdecken.
Weitere SMS-Möglichkeiten finden Sie in den folgenden Ressourcen:
Teilen Sie:
Ben ist ein Entwickler im zweiten Beruf, der zuvor ein Jahrzehnt in den Bereichen Erwachsenenbildung, Community-Organisation und Non-Profit-Management tätig war. Er arbeitete als Anwalt für Entwickler bei Vonage. Er schreibt regelmäßig über die Überschneidung von Gemeindeentwicklung und Technologie. Ursprünglich aus Südkalifornien stammend und lange Zeit in New York City ansässig, wohnt Ben jetzt in der Nähe von Tel Aviv, Israel.
