Допустим, у меня есть CSV с телефонными номерами. Я хочу проверить или отфильтровать эти телефонные номера по географическому местоположению, например по городу, штату, региону, оператору связи, часовому поясу и типу телефона (мобильный/стационарный/VoIP/и т. д.). Быстрый поиск в гугле дает несколько ссылок, связанных с SMS: Numverify, Nexmo и т. д., большинство из которых требует подписки или каким-то образом ограничено.
Что привлекло мое внимание, так это предложение Amazon — Pinpoint. Это широкое предложение, которое может помочь с маркетинговыми кампаниями, привлечением пользователей, аналитикой взаимодействия и т. д., которое включает в себя SMS-сервис и проверку номера телефона.
При цене 0,006 доллара за звонок (на момент написания статьи) это стоит недорого. Могут быть и другие бесплатные инструменты, но я скептически отношусь к тому, насколько сомнительными они могут оказаться, кэшируя мою ценную базу данных; Кроме того, если я уже использую другие компоненты AWS для различных нужд, это действительно быстрая интеграция для проверки телефонных номеров с помощью чего-то такого простого, как вызов CLI, с уже настроенными учетными данными/профилем AWS —
aws pinpoint phone-number-validate --number-validate-request IsoCountryCode="+1",PhoneNumber="+14085550100"
Вывод выглядит так-
Этого достаточно для случайной проверки телефонных номеров. Но у меня есть гигантский CSV размером в несколько гигабайт для обработки. Быстрое и грязное решение в RoR, так как у меня уже есть проект rails -
Добавьте необходимый SDK AWS в Gemfile
#Gemfile gem 'aws-sdk-pinpoint'
Отбросьте этот метод везде, где он подходит, возможно, в /lib под class-
PHONE_COLUMN = 34.freeze def process_phone_numbers(filename) pinpoint = Aws::Pinpoint::Client.new CSV.foreach(filename, headers: true) do |row, i| query = { number_validate_request: { iso_country_code: '+1', phone_number: '+1' + row[PHONE_COLUMN] } } response = pinpoint.phone_number_validate(query).number_validate_response pp response end end
Это просто красивая печать ответов на экране, не очень полезная. Давайте создадим еще один CSV-файл только с теми строками, которые удовлетворяют определенному условию, скажем, только с мобильными номерами. Измените приведенный выше файл, чтобы условно записать строку в новый CSV.
Во-первых, нам нужен новый файл CSV. Я создаю это, вставляя _verified
в уже существующее имя файла.
def process_phone_numbers(filename) pinpoint = Aws::Pinpoint::Client.new verified_filename = filename.dup verified_filename.insert(-5, '_verified') ...
Затем я открываю этот CSV для записи и циклического прохождения по условию.
def process_phone_numbers(filename) pinpoint = Aws::Pinpoint::Client.new verified_filename = filename.dup verified_filename.insert(-5, '_verified') CSV.open(verified_filename, 'wb') do |v_csv| CSV.foreach(filename, headers: true) do |row, i| { number_validate_request: { iso_country_code: '+1', phone_number: '+1' + row[PHONE_COLUMN] } } response = pinpoint.phone_number_validate().number_validate_response next unless response[:phone_type] == "MOBILE" v_csv << row v_csv.flush Rails.logger.info "⛳️ Wrote #{row[PHONE_COLUMN]} to file" end end end
Теперь у меня есть файл CSV, содержащий только строки, содержащие номера мобильных телефонов! И да, у меня есть флаг в моем журнале. ⛳️
Что, если бы у меня было несколько строк с одинаковым номером? Что, если бы это была база данных пользователей/людей, в которой несколько человек использовали один и тот же номер? Что делать, если AWS выдает ошибку? (Иногда это происходит, если вы отправляете неверный номер)
Кэшируйте это. Лови.
Для этого я разделяю часть запроса AWS и часть проверки на новые функции.
def valid_mobile?(number) r = phone_number_validate number r[:phone_type] == 'MOBILE' end def pinpoint_client @pinpoint_client ||= Aws::Pinpoint::Client.new end def phone_number_validate(number) Rails.cache.fetch(number, expires_in: 1.year.from_now) do query = { number_validate_request: { iso_country_code: '+1', phone_number: number } } r = pinpoint_client.phone_number_validate(query) r.number_validate_response.to_h end rescue StandardError => e Rails.logger.error e.message raise e # Lets stop if there are problems. Anyway there is cache. end
Первоначальный метод теперь должен выглядеть так, чтобы использовать вышеуказанное:
def process_phone_numbers(filename) verified_filename = filename.dup verified_filename.insert(-5, '_verified') CSV.open(verified_filename, 'wb') do |v_csv| CSV.foreach(filename, headers: true) do |row, i| next unless valid_mobile? row[PHONE_COLUMN] v_csv << row v_csv.flush Rails.logger.info "⛳️ Wrote #{row[PHONE_COLUMN]} to file" end end end
Там. Теперь у нас есть метод phone_number_validate
, который можно использовать повторно, он был закеширован. Метод process_phone_numbers
может обрабатывать CSV.
Конечно, есть и другие краеугольные случаи, такие как пропуск пустых строк, обработка чисел в формате +1(123)-(456)-7890 и т. д. Есть достаточно вопросов StackOverflow, касающихся этого, например, использование чрезвычайно сложного регулярного выражения.
Это я оставляю читателю в качестве упражнения!