前端笔记

分享前端开发思考与感悟

刮擦Web进行更新并使用Ruby发送SMS警报

我们都去过那儿。您醒了,这是新的一天,您只需要知道最迫切的问题的答案即可。现在是周末吗?您这一周忙于专业和个人责任。您要做的就是花几天时间坐下来放松一下。

要回答这个问题,您当然可以在手机上打开日历应用程序,或者询问您最喜欢的个人数字家庭助理。但是,当您可以构建自己的向您发送短信的应用程序时,为什么要执行这些操作呢?

我们将创建一个执行以下操作的Ruby on Rails应用程序:

  • 既允许新订阅者,也允许退订列表
  • isittheweekend.com刮掉我们问题的答案
  • 每天将我们抓取的数据中的答案发送给所有订阅的收件人

为了将它们包装在一起,我们还将创建一个Rake任务,该任务将一次运行所有这些任务,并每24小时指定一次执行。

如果愿意,您还可以在GitHub找到此应用程序的完整版本。

让我们开始吧!

先决条件

生成Rails应用程序

我们需要做的第一件事是创建新的Rails应用程序。在命令行中执行以下操作:

$ rails new weekend-checker-app --database=postgresql

这将为我们的Rails应用程序创建必要的文件结构,并将默认数据库设置为PostgreSQL。

完成后,cd进入创建的目录。在安装依赖项之前,我们将添加应用程序将使用的其他gem。

在首选的代码编辑器中打开代码,然后导航到Gemfile。在里面Gemfile添加以下宝石:

gem 'nexmo'
gem 'watir'
gem 'webdrivers', '~> 4.0'
gem 'whenever', require: false
gem 'dotenv-rails'

我们使用nexmogem来发送SMS更新,使用gem watirwebdriversgem来向具有动态JavaScript内容的站点发出HTTP请求,使用whenevergem来计划Rake任务,以及使用dotenv-railsgem来管理环境变量。

保存之后Gemfile,就可以从命令行运行bundle install了。

下一步是创建我们的数据库模式和模型。

创建数据库架构和模型

现在已经创建了Rails应用程序并安装了其依赖项,接下来的任务是创建正确的数据库架构来容纳操作应用程序所需的数据。我们需要存储以下类型的信息:

  • 收件人:带有电话号码的订户列表
  • DiffStorage:要比较的网站数据的副本,以确定是否有更改

我们将使用Rails生成器工具创建迁移文件,然后对每个文件进行编辑。

$ rails generate model Recipient number:string subscribed:boolean
$ rails generate model DiffStorage website_data:text

这些命令将在中创建模型文件app/models并在中创建迁移文件db/migrate。在将这些更改提交到应用程序之前,一旦完成生成器操作,请检查在两个目录中创建的文件以确保它们正确。

具体来说,您要确保在迁移文件中,每个迁移都包括t.timestamps,这会在表中添加created_atupdated_at列。您还应该在迁移文件中看到numbersubscribedRecipient,其类型分别设置为stringboolean。同样,您应该在DiffStorage迁移文件中看到一列website_data,其类型设置为text

app/models除类声明及其从的继承外,内部的模型文件应为空ApplicationRecord

当看起来令人满意时,就该从命令行运行rake db:migrate了。该命令会将结果输出到您的控制台,并且如果您检查db/schema.rb文件,您将能够看到您创建的在应用程序内部初始化的模式。

最后,我们还需要创建MessengerScraper建模,但是不需要迁移它们。为此,我们再次运行Rails生成器并向其添加一个--migration=false标志:

$ rails generate model Messenger --migration=false
$ rails generate model Scraper --migration=false

现在到了定义模型内部逻辑的时候了。

定义模型

如上所述,我们有四个模型负责应用程序的独特领域:

  • DiffStorage检查网站数据是否有差异
  • Recipient管理添加和删除订户
  • Messenger管理SMS消息的发送
  • Scraper负责抓取网站数据

定义DiffStorage模型

DiffStorage模型将包含两个类模型。一个将包含我们正在抓取的URL。第二个将检查自上次刮刮网站以来的任何更改,并在满足条件时调用应用程序中的后续步骤。

首先,让我们以自己的方法定义URL,以便我们在其存在的位置创建一个单独的位置,并且如果以后选择的话可以轻松地对其进行修改:

def self.url
  'http://isittheweekend.com'
end

接下来,该模型的大部分内容将存在于#check_last_recordclass方法中:

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)
end

上面的方法首先调用Scraper类中的方法,该类将开始抓取网站以获取最新快照并将该数据分配给today_answer。然后,将下一步包装在一个if语句中,该语句询问中是否有任何记录DiffStorage。如果那里存储了以前的记录,则该方法将获取最近的记录并将其分配给yesterday_answer。如果以前没有记录,则将空字符串分配给yesterday_answer。最后,它将收件人和两个变量发送到Messenger模型以处理发送消息的过程。

定义刮板模型

Scraper模型将负责完成从isittheweekend.com收集数据的工作,以确定是否确实是周末。该模型将具有四个类方法,我们将在此处定义每个方法:

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
end

抓取行为中的每个动作都定义为自己的小方法,以使我们的关注点分离。该#call方法是该类的切入点。这就是自身之外的其他方法所调用的东西。该#get_url方法通过使用Watir库模拟Chome浏览器请求来发出HTTP请求,并使用进行解析Nokogiri。该#check_text方法检查是否获得了任何数据。该#store_text方法将数据保存到数据库。

定义Messenger模型

Messenger模型中将包含负责将每日SMS更新发送给订户的所有代码。我们将创建一种发送消息的方法,一种组合周末回复文本的方法,一种将整个消息放在一起的方法,以及一种在订户发送删除请求时管理确认消息的方法。

首先,发送更新消息的方法:

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
end

text上面参数的值引用一个称为的类方法#weekend_message。此方法将通过检查今天是否与昨天相同来组成周末更新的字符串:

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)
end

接下来,包含HEREDOC带有消息正文的字符串的方法:

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
end

最后,发送删除确认消息的方法:

def self.send_removal_message(to)
  @client.sms.send(
    from: ENV['FROM_NUMBER'],
    to: to,
    text: 'You have been successfully removed.'
  )
end

在继续下一步之前,我们需要定义的最后一个模型是Recipient模型。

定义收件人模型

该模型不包含任何类方法。我们将对该模型进行的唯一添加是为收件人的数据添加两个验证。将新电话号码添加到数据库时,这些验证将充当保护措施。我们将检查a)确实在数据中提供了一个数字,并且b)该数字不是已经存在的记录的重复。为了进行这些验证,我们在类定义下添加了两行:

class Recipient < ApplicationRecord
  validates :number, presence: true
  validates :number, uniqueness: true
end

创建控制器和路由

我们即将完成我们应用的构建!下一步是定义将控制应用程序流程的控制器操作。首先,让我们从命令行使用Rails生成器生成控制器:

$ rails generate controller WeekendChecker

这将在中的app/controllers调用weekend_checker_controller.rb视图文件和补充视图文件中创建一个新的空控制器文件app/views/weekend_checker。我们将在短期内添加索引视图。在这一点上,我们将专注于控制器。

该控制器需要三个动作对应于三条路线:#index#create#event。该#index路线将是我们网站的默认和唯一视图。那将是个人可以订阅列表的地方。该#create路线将是处理新号码的地方。最后,#event路由将是应用程序从SMS API接收webhook数据(包括删除请求)并进行处理的地方。

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

这三个控制器动作需要在中定义的三个对应的路由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'
end

我们的应用程序代码设置的倒数第二项是创建/路线的基本视图。

定义视图

为了订阅SMS列表,我们将在URL的顶层创建一个视图,该视图将包含注册表单。

app/views/weekend_checker文件夹内添加index.html.erb文件。它将包含以下代码:

<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="https://developer.nexmo.com">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 %>

我们要做的最后一个编码任务是设置新的Rake任务,它将运行所有这些代码,并将whenevergem 配置为每天执行一次Rake任务。

创建耙任务并将其计划

再次,我们将从命令行使用Rails生成器为Rake任务创建文件。从命令行运行以下命令:

$ rails generate task scraper check_site_update

上面的任务将创建一个lib/tasks名为的文件scraper.rake。当我们在代码编辑器中打开它时,它将如下所示:

namespace :scraper do
  desc "TODO"
  task :check_site_update => :environment do
  end
end

让我们desc用此任务的简短字符串重新定义:desc "Check Website for Any Updates"。接下来,在task块内添加DiffStorage#check_last_recordclass方法,这是我们之前创建的所有工作的入口点:

namespace :scraper do
  desc "Check Website for Any Updates"
  task :check_site_update => :environment do
    DiffStorage.check_last_record
  end
end

现在已经定义了Rake任务,我们最后需要初始化whenevergem并让它知道我们希望该任务每天运行一次。为此,首先,从命令行运行gem的initializer命令:

$ bundle exec wheneverize .

上面的命令在schedule.rb文件config/夹内创建一个文件。将以下代码添加到该文件以scraper:check_site_update每天运行任务:

every 1.day do
  rake "scraper:check_site_update"
end

现在已经创建了计划,我们需要更新计算机上的crontab文件以了解此新作业。我们通过bundle exec whenever --update-crontab从命令行运行来实现。一旦完成,任务将被完全初始化并配置为每天在我们的计算机上运行一次。

我们应用程序的代码已全部设置好。现在唯一缺少的是创建我们的Nexmo帐户,获取我们的Nexmo API凭据,并提供一个虚拟电话号码来发送日常短信。获得这些信息后,我们会将其作为环境变量添加到我们的应用程序中。

Nexmo API凭证和电话号码

要创建一个帐户,请导航到Nexmo仪表板并完成注册步骤。完成注册后,将进入仪表板,其外观类似于以下内容:

《刮擦Web进行更新并使用Ruby发送SMS警报》

如果你还没有这样做之前,创建一个.env在应用程序中的顶级目录文件并添加NEXMO_API_KEYNEXMO_API_SECRET给它。这些值可在仪表板页面顶部Your API credentials标题下找到。

NEXMO_API_KEY=
NEXMO_API_SECRET=

我们需要在仪表板内部执行的下一个任务是提供电话号码。单击Numbers侧边栏导航上的链接后,将显示一个下拉菜单。选择Buy numbers选项然后单击Search按钮后,您将看到要获取的可能数字的列表:

《刮擦Web进行更新并使用Ruby发送SMS警报》

在按功能,国家和类型搜索号码时,建议选择用户所基于的国家,SMS功能和Mobile类型。

点击Buy您要购买的电话号码的橙色按钮后,您可以将该号码.env作为新变量添加到文件中FROM_NUMBER

NEXMO_API_KEY=
NEXMO_API_SECRET=
FROM_NUMBER=

我们在仪表板中需要做的最后一项工作是提供一个外部可访问的URL,作为电话号码的事件webhook。出于开发目的,ngrok是一个很好的工具,您可以按照本指南进行安装和运行。

从仪表板Numbers侧边栏导航下拉菜单中,选择Your numbers后将在列表演示文稿中看到新配置的电话号码。单击齿轮图标以管理其属性后,将显示一个设置对话框菜单:

《刮擦Web进行更新并使用Ruby发送SMS警报》

在上面的屏幕截图示例中,您将用Inbound Webhook URL自己的URL 替换文本字段,该URL以结尾/webhooks/event

而已!我们的代码都已完成,我们的Nexmo凭据都已设置。此时,您将面临运行应用程序的选择。您可以在本地运行它,也可以将其部署到外部托管提供商,例如Heroku。在最后一步,我们将讨论如何在本地运行它。

如果您有兴趣将其部署为更长期的解决方案,则可以访问GitHub存储库,然后单击Deploy to Heroku自述文件顶部的按钮以开始该过程。

运行应用程序

现在,我们准备运行我们的全新应用程序!为了在本地运行它,Rails事件Webhook需要本地环境外部的外部环境访问。例如,如果您在遵循本指南后使用ngrok,则Rails应用程序和ngrok需要同时运行。

要启动Rails应用程序,请从命令行执行以下命令:

$ bundle exec rails server

然后,您可以在选择的浏览器中导航到localhost:3000。您将看到您创建的注册表单。继续填写您的电话号码并提交。现在,一旦运行Rake任务,您应该期望收到一条SMS,告知您是否是周末以及今天是否与昨天不同!

下一步

我们在异想天开时构建的应用程序展示了利用Web抓取和SMS来创建向订户提供更新的应用程序的潜力。像这样的应用程序有无数潜在的用例。无论您是要复制这种确切的场景,还是要为自己的用例移植代码,都需要在这个主题上进行探索。

要进一步探索其他SMS可能性,请查看以下资源:

点赞
  1. 您的评论现正待审。这是一份预览,您的评论将在被批准后显示。

    Процедура регистрации: 4 метода на выбор Моментальное открытие счета Подготовлена игровая ставка и дорога любая секунда? Дополнительно для таких случаев разработана 1xbet регистрация одним кликом наиболее стремительной процедуры и не выдумать. Стоит только правильно выбрать страну и валюту, сразу после чего предложат записать номер счета и пароль от него путем: Доставки на электронный адрес; Сохранения в виде изображения; Записи в файл. Доступ в личный кабинет производится в автоматическом режиме, а по окончании первого депозита приступаем к ставкам. Записать личные данные для верификации счета можно после в любое время. Регистрация 1xbet через телефон Для того, чтобы предохранить собственный аккаунт от несанкционированного доступа, следует пройти регистрацию по номеру телефона. Записав лишь номер и валюту, вам выдадут данные для входа по СМС. Начальные 24 часа допускается беспрепятственно вводить денежные средства и совершать ставки, на вторые сутки потребуется ввод личных данных для контроля над аккаунтом. Открытие счета по E-mail адрес Реализован и стандартный метод, написать сразу же абсолютно все сведения через ресурс. Комплексная версия онлайн-регистрации избавит от надобности вернуться к записи значений в дальнейшем. Все, что потребуется указать: Страна проживания; Денежная единица счета (не изменить в дальнейшем); Имя и фамилия (как в документе); Действующий e-mail; Номер сотового телефона; Для захода в личный кабинет остается только надавить по кнопке «регистрация». Комплексная версия, всё-таки, не избавляет от последующей операции верификации и отправки данных паспорта. На подтвержденный E-mail вы будете получать секретную информацию, в том числе ссылку с активационном текстом, по какой необходимо перейти для подтверждения адреса. Зарегистрироваться через соцсети В числе иных способов, разрешающих быстро начать совершать ставки в БК 1xbet, процедура регистрации нового игрового счета с помощью социальных сетей. Кроме валюты, подберите любую из площадок, в какой у вас открыт аккаунт. Личные данные переместятся автоматически, а играющему останется только лишь сохранить полученные в окне номер счета и пароль. Каким образом пройти регистрацию с телефона? Для любителей держать ставки под рукой открыта регистрация с сотового, достаточно зайти на зеркало. Все 4 возможных способа открытия счета игрока доступны для телефонов и планшетников. Ещё фирма выпустила программы для девайсов: iOS, Android и Java. Можно закачать 1xbet с главного ресурса. Мобильное приложение русской букмекерской конторы содержит ряд особенностей: Способность вводить и снимать денежные средства; Скорый вход к хронологии ставок; Комфортный Лайв-раздел; Выделены популярные события. Прямиком из программы также возможно пройти регистрацию и испытать себя в ходе игры на тотализаторе.

  2. 您的评论现正待审。这是一份预览,您的评论将在被批准后显示。

    1XBET зеркало: 1XBET зеркало регистрация

  3. 您的评论现正待审。这是一份预览,您的评论将在被批准后显示。

    1XBET зеркало рабочее: 1ХБЕТ зеркало скачать

  4. 您的评论现正待审。这是一份预览,您的评论将在被批准后显示。

    1XBET работающее зеркало: 1ХБЕТ зеркало сейчас

发表评论

电子邮件地址不会被公开。 必填项已用*标注