При разработке iOS-приложений нам часто приходится работать с данными из различных API. Однако иногда нужные данные не упакованы удобно и недоступны через REST API. В таких случаях мы можем извлекать данные напрямую с веб-страницы с помощью библиотеки Kanna для Swift.
Давайте создадим iOS-приложение, которое будет отображать все предстоящие метал-концерты в Нью-Йорке, парся данные с сайта NYC Metal Scene.
Начнем с клонирования этого репозитория, который содержит стартовый проект для дальнейшей разработки. В проекте уже настроен storyboard с `UITableView`, который мы будем использовать для отображения данных, полученных в результате скрейпинга. Я использую XCode версии 7.3 и Swift версии 2.2, поэтому убедитесь, что этот код совместим с вашей версией XCode и Swift.
Откройте терминал и перейдите в директорию, где вы хотите разместить проект. Введите следующую команду для клонирования репозитория. Также можно скачать zip-архив проекта:
CocoaPods позаботится о подключении всех необходимых фреймворков, создав новый Xcode Workspace. Теперь при открытии проекта в Xcode необходимо использовать `UpcomingMetalShows.xcworkspace` вместо обычного проекта Xcode.
Проверьте, что Kanna и Alamofire установлены корректно, добавив эти две строки в файл `ViewController.swift`:
Нажмите «Command-B», чтобы убедиться, что проект собирается с указанными зависимостями.
После настройки стартового проекта переходим к следующему шагу — выполнению HTTP-запроса для получения данных о концертах. В нашем случае мы хотим сделать запрос к `http://nycmetalscene.com/` и извлечь HTML-контент, который будет возвращен.
Прежде чем делать запрос, необходимо настроить приложение для работы с небезопасными сайтами, то есть сайтами, которые не поддерживают HTTPS. Начиная с iOS 9, Apple включила App Transport Security, которая по умолчанию запрещает запросы к небезопасным сайтам. Чтобы наше приложение работало, нужно добавить исключение в эту политику, отредактировав файл `Info.plist`.
Откройте `Info.plist`, добавьте новый ключ `App Transport Security Settings` в `Information Property List` и установите значение `Allow Arbitrary Loads` в `YES`, как показано в этом GIF:
После добавления исключения мы можем получить HTML-код страницы, которую пытаемся спарсить. Для этого нужно отправить `GET`-запрос с помощью Alamofire.
Откройте `ViewController.swift` и добавьте следующий код в класс `ViewController`:
Метод `parseHTML(html: String) -> Void` будет обрабатывать HTML из нашего `GET`-запроса и использовать Kanna для его анализа.
Запустите загрузку данных, добавив вызов этой новой функции в конец метода `viewDidLoad`:
Теперь снова запустите приложение, чтобы проверить успешность отправки запроса.
Прежде чем писать код для парсинга контента, полученного из `GET`-запроса, давайте сначала посмотрим на HTML, который отображается в браузере. Каждая веб-страница уникальна, и иногда для извлечения данных требуется немного наблюдательности и изобретательности.
В нашем случае мы хотим получить все метал-концерты, содержащиеся в разметке.
Каждый концерт находится в теге `td` и имеет ID `Text`, за которым следует какое-то число. Это первый шаблон, который мы будем использовать для извлечения HTML-элементов, содержащих информацию о концерте.
Далее вы можете заметить, что *каждый* текстовый элемент на странице следует этому шаблону ID, а не только концерты. Чтобы извлечь только текстовые узлы, относящиеся к концертам, мы будем использовать второе регулярное выражение для поиска текста, начинающегося с первых трех букв дня недели. Этот шаблон указывает на то, что текст относится к концерту.
Имея два шаблона для извлечения данных о концертах, мы готовы парсить контент. С помощью Kanna разработчики могут использовать CSS-селекторы или XPath-запросы для навигации по HTML-документу. Давайте используем CSS-селекторы с регулярным выражением, чтобы найти все узлы `td`, у которых ID начинается с «Text». Затем мы пройдемся по этим результатам и применим регулярное выражение для дней недели.
Отредактируйте метод `parseHTML`, добавив следующий пример кода, который будет выводить текст всех концертов на странице:
Запустите приложение, чтобы убедиться, что оно выводит только информацию о концертах, а не весь ненужный текст, как показано на следующем скриншоте из Xcode.
Далее мы будем работать над отображением этих данных в мобильном приложении.
Давайте отобразим все концерты в `UITableView`, чтобы у нас было настоящее приложение.
В стартовом проекте уже добавлен и настроен `UITableView` в `Main.storyboard`, а также необходимые методы в `ViewController.swift`. Нам остается только связать наши данные с этим представлением.
Мы используем массив `shows` в качестве источника данных для `UITableView`. Добавьте строку в конец нашей функции `parseHTML`, чтобы убедиться, что данные в `UITableView` загружаются после завершения парсинга концертов:
Нам также нужно определить, какие данные содержит ячейка в нашем табличном представлении. Замените функцию `tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)` на следующую:
Теперь запустите приложение и посмотрите список предстоящих метал-концертов в Нью-Йорке.
Ух ты, похоже, что Megadeth, Amon Amarth, Suicidal Tendencies, Metal Church и Havok играют на одном концерте в октябре! Звучит как довольно крутой состав.
Теперь вы можете создавать приложения, используя данные, которые не всегда доступны в удобном формате через публичные API, просто извлекая их из Интернета.
Имейте в виду, что изменения в HTML-разметке веб-страницы могут сломать ваше приложение, поэтому следите за актуальностью вашего кода.
Если вы хотите разрабатывать что-то, что не требует скрейпинга данных со старых веб-страниц, ознакомьтесь с Video и IP Messaging iOS SDK от Twilio для добавления видеоконференций и чата в реальном времени в ваши Swift-приложения.
С нетерпением жду, что вы создадите, теперь, когда у вас есть доступ ко всем данным на любой веб-странице. Не стесняйтесь обращаться с вопросами или показать, что вы создали:
— Email: sagnew@twilio.com
— Twitter: @Sagnewshreds
— Github: Sagnew
— Twitch (стримы живого кодинга): Sagnewshreds