Освой Android играючи
/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000
Общая информация
Подключаем библиотеку
Первый пример для знакомства
Извлекаем заголовок страницы
Извлекаем ссылки
Разбор текста с сайта
Разбор текста из файла
Первоначально статья писалась, когда деревья были большими, коты были котятами, Android был версии 2.3, а библиотека jsoup была версии 1.6.1.
С тех пор утекло много воды. Хорошая новость - библиотека подросла до версии 1.13.1, стала чуть меньше размером, стала быстрее работать (почти в два раза). Плохая новость - мои примеры, связанные с интернетом, перестали работать в Android 4.0, так как теперь явно запретили использовать сетевые операции в основном потоке.
Я оставлю старую версию статьи здесь. Если вы пишете программы под старые устройства, то всё остаётся без изменений. Примеры под новые устройства находятся в закрытой зоне 4 курса.
Рассмотрим примеры работы с библиотекой jsoup. Java-библиотека jsoup предназначена для разбора HTML-страниц (парсинг), позволяя извлечь необходимые данные, используя DOM, CSS и методы в стиле jQuery.
Библиотека поддерживает спецификации HTML5 и позволяет парсить страницы, как это делают современные браузеры.
Библиотеке можно подсунуть для анализа URL, файл или строку.
Официальная страница библиотеки: jsoup Java HTML Parser, with best of DOM, CSS, and jquery
В Android Studio пропишите в файле build.gradle строку в блоке зависимостей.
implementation 'org.jsoup:jsoup:1.13.1'
Создаём новый проект JsoupDemo. Добавляем на форму кнопку и TextView.
После установки библиотеки вам нужно получить документ для разбора текста. Это может быть страница на сайте или локальный файл на устройстве. Таким образом вам надо подключиться к нужной странице и получить объект класса Document. При импортировании обращайте внимание на полное название класса org.jsoup.nodes.Document, так как многие пакеты имеют в своём составе одноимённый класс.
Document doc = Jsoup.connect(URL).get();
Получив документ в своё распоряжение, вы можете извлекать требуемую информацию. Например, вы можете получить все теги meta:
Elements metaElements = doc.select("meta");
Метод select() позволяет получить нужные теги.
Если нужно получить атрибут тега, то используйте метод attr():
String name = metaElement.attr("name");
Можно выбрать теги с заданным классом. Например, на странице встречается тег типа <h2 class="main">. Тогда код будет следующим.
Elements mainHeaderElements = doc.select("h2.main");
Для первого знакомства разберём простой пример. А потом будем его усложнять. Создадим переменную, содержащий html-текст. Далее вызываем библиотеку jsoup и смотрим на результат.
// Kotlin
// Если этот код работает, его написал Александр Климов,
// а если нет, то не знаю, кто его писал.
package ru.alexanderklimov.jsoupdemo
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import org.jsoup.Jsoup
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val textView: TextView = findViewById(R.id.textView)
val button: Button = findViewById(R.id.button)
button.setOnClickListener {
val html = ("<html><head><title>Коты учатся кодить</title>"
+ "<body><p>Коты умеют <del>ш</del>кодить.<br> Они великие программисты." +
"<p>А еще они умеют мяукать.</p>" +
"<a href='http://developer.alexanderklimov.ru'>Подробности здесь</a>" +
"</body></html>")
val doc = Jsoup.parse(html)
textView.text = doc.html()
}
}
}
// Java
package ru.alexanderklimov.jsoupdemo;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class JsoupDemoActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final Button button = findViewById(R.id.button);
final TextView txtView = findViewById(R.id.textView);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String html = "<html><head><title>Коты учатся кодить</title>"
+ "<body><p>Коты умеют <del>ш</del>кодить.<br> Они великие программисты." +
"<p>А еще они умеют мяукать.</p>" +
"<a href='http://developer.alexanderklimov.ru'>Подробности здесь</a>" +
"</body></html>";
Document doc = Jsoup.parse(html);
textView.setText(doc.html());
}
});
}
}
Запустите проект и нажмите на кнопку. На экране отобразится наш текст. Но если вы присмотритесь внимательнее, то заметите некоторые отличия (скорее всего вы и не заметили). Я намеренно сделал две "ошибки". Во-первых, я не закрыл тег </head>, а также не закрыл тег </p> у первого параграфа. Однако библиотека сама подставила недостающие элементы. Именно так поступают и браузеры, если веб-мастер по невнимательности забывает ставить закрывающие парные теги.
Что мы сделали? Мы передали нужный html-текст библиотеке Jsoup и попросили его осуществить его разбор (метод parse()). В результате мы получаем экземпляр класса Document, из которого с помощью метода html() извлекаем уже обработанный текст, с которым можно работать дальше.
Если у вас всё получилось, то можно перейти к более сложным примерам. Подробная документация по методам и свойствам есть на сайте библиотеки. Вам нужно только пробовать.
Заголовок страницы находится в теге <title>. Чтобы получить текст заголовка, воспользуемся методом Document.title():
// Kotlin
textView.text = doc.title()
// Java
textView.setText(doc.title()); // вернёт строку "Коты учатся кодить"
Теперь попробуем поработать с ссылками. В нашем тексте есть ссылка, которую можно разбить на несколько логических элементов: адрес, на который ведёт ссылка, текст в ссылке и полная ссылка, которая объединяет оба элемента.
Начнём с адреса ссылки:
// Kotlin
val doc = Jsoup.parse(html)
val link = doc.select("a").first()
val linkHref = link.attr("href")
textView.text = linkHref
// Java
Document doc = Jsoup.parse(html);
Element link = doc.select("a").first();
String linkHref = link.attr("href");
textView.setText(linkHref); //http://developer.alexanderklimov.ru
Чтобы получить текст ссылки:
// Kotlin
val linkInnerH = link.html()
textView.text = linkInnerH
// Java
String linkInnerH = link.html();
textView.setText(linkInnerH); //Подробности здесь
И, наконец, общий вариант:
// Kotlin
val linkOuterH = link.outerHtml()
textView.text = linkOuterH
// Java
String linkOuterH = link.outerHtml();
tvInfo.setText(linkOuterH);
Некоторые несознательные граждане могут меня обвинить в том, что я использовал синтетический пример, специально подготовленный для демонстрации. И хотят видеть пример с использованием ваших тырнетов. Ну что ж, вот вам пример.
Document doc = null;
try {
doc = Jsoup.connect("http://developer.alexanderklimov.ru/android/").get();
} catch (IOException e) {
e.printStackTrace();
}
String title = doc.title();
textView.setText(title);
Я подключаюсь к самой известной странице в мире http://developer.alexanderklimov.ru/android/ и получаю его заголовок.
Не забудьте установить разрешение на подключение к Интернету вашей программе. Я сам сначала долго тупил, не понимая, почему моя программа вылетала с ошибкой. Но, посмотрев в честные глаза своего кота, я понял в чем моя ошибка и исправил ее. Коты рулят.
Последний пример, который мы не разобрали - это разбор текста из файла. В этом случае используется метод Jsoup.parse(File in, String charsetName, String baseUri):
File input = new File("/tmp/input.html");
Document doc = Jsoup.parse(input, "UTF-8", "http://example.com/");
Попробуйте самостоятельно. Удачи в программировании! Да пребудет с вами кот!
Библиотека jsoup и многопоточность. Продолжение