Разработка оффлайн-браузера, способного сохранять HTML-страницы со всем их содержимым из Сети
Введение
Браузер (Веб-обозреватель) (от англ. Web browser) - программное
обеспечение для просмотра веб-сайтов, то есть для запроса веб-страниц
(преимущественно из Сети), их обработки, вывода и перехода от одной страницы к
другой.
Часть браузеров поддерживают кроме онлайн-режима, когда
браузер пытается получить страницы с веб-сервера, оффлайн-режим, при котором
можно просматривать сохранённые копии ранее посещённых страниц. Оффлайн-режим
полезен, когда по какой-либо причине нет соединения с интернетом. Страницы либо
неявно сохраняются в кэше браузера при посещении веб-сервера, либо браузер
специально настраивается на сохранение и поддержание локальных копий
определённых сайтов. Копии обновляются либо при восстановлении соединения, либо
по расписанию.
Целью задачи данной работы является создание
оффлайн-браузера, способного сохранять HTML страницы со всем их
содержимым из Сети. Одной из особенностей программы будет загрузка страниц с
заданным уровнем вложенности, то есть с заданным количеством переходов по ссылкам
«вглубь». Таким образом, при необходимости, можно будет сохранить не одну
страницу, а все страницы, к которым мы можем получить доступ, переходя по
ссылке с предыдущей. В итоге у нас будет возможность сохранять весь сайт
целиком.
В случае же, когда на странице присутствует контент,
требующий для своей работы подгрузку дополнительных элементов, программа будет
загружать и их.
Ниже приведена схема, показывающая принцип работы программы:
1. HTML
1.1 Общие сведения по HTML
(HyperText Mark-up Language/язык гипертекстовой разметки) -
это язык, который позволяет представлять информацию в Internet. То, что вы
видите при просмотре страницы в Internet, это интерпретация вашим браузером
HTML-текста.
· Hyper противоположно linear/построчно.
Ранее компьютерные программы работали построчно: программа выполняла одну
строку, затем переходила к выполнению следующей, и т.д. Но HTML работает
по-иному - вы можете перейти куда и когда захотите.
· Text - собственно, текст.
· Mark-up - это разметка, то, что
вы можете делать с текстом. Размечается текст так же, как это делается в
текстовых редакторах: выставление заголовка, списков, выделение текста жирным
шрифтом и т.д.
· Language - это язык HTML. В нём
используется много английских слов, что заметно облегчает работу с ним.
Изначально язык HTML был задуман и создан как средство
структурирования и форматирования документов без их привязки к средствам
воспроизведения (отображения). В идеале, текст с разметкой HTML должен был без
стилистических и структурных искажений воспроизводиться на оборудовании с
различной технической оснащённостью. Однако современное применение HTML очень
далеко от его изначальной задачи.
.2 Структура HTML-документа
- теговый язык разметки документов. Любой документ на языке
HTML представляет собой набор элементов, причём начало и конец каждого элемента
обозначается специальными пометками - тегами. Элементы могут быть пустыми, то
есть не содержащими никакого текста и других данных (например, тег перевода
строки <br />). В этом случае обычно не указывается закрывающий тег.
Кроме того, элементы могут иметь атрибуты, определяющие какие-либо их свойства
(например, размер шрифта для элемента font). Атрибуты указываются в открывающем
теге.
Тэги - это метки, которые используются для указания браузеру,
как он должен показывать web-сайт.
Все тэги имеют одинаковый формат: они начинаются знаком
«<» и заканчиваются знаком «>».
Обычно имеются два тэга - открывающий: <html> и
закрывающий: </html>. Различие в том, что в закрывающем имеется слеш «/».
Всё содержимое, помещённое между открывающим и закрывающим
тэгами, является содержимым тэга.
Но из каждого правила есть исключения - в HTML также имеются
тэги, которые являются и открывающими, и закрывающими. Эти тэги не содержат
текста, а являются метками, например, перенос строки выглядит так: <br
/>.
Примеры использования тегов:
Пример 1:
Тэг <b> информирует браузер, что весь текст между
<b> и </b> должен быть напечатан жирным шрифтом. («b» это
сокращение для «bold») То есть
<b>This text must be bold.</b>
будет выглядеть при просмотре в браузере следующим образом:
This text must be bold.
Пример
2:
Тэги
<h1>, <h2>, <h3>, <h4>, <h5> и <h6>
указывают браузеру создавать заголовки (h для «heading»), где <h1> это
заголовок первого уровня - самый крупный шрифт, <h2> - заголовок второго
уровня - шрифт меньшего размера, и <h6> - заголовок шестого уровня -
самого низкого в этой иерархии, и самый маленький шрифт.
<h1>Это заголовок</h1>
<h2>Это подзаголовок</h2>
будет выглядеть в браузере:
Это заголовок
Это подзаголовок
Большинству браузеров безразлично, в каком регистре введены
буквы тэгов. <HTML>, <html> или <HtMl> обычно даёт одинаковый
результат. Однако корректным будет нижний регистр.прост и логичен. Браузер
читает HTML так, как читаете его вы: сверху вниз и слева направо. Таким
образом, HTML-документ начинается и заканчивается тем, чем должен начинаться и
заканчиваться обычный текст.
Структура документа HTML выглядит следующим образом:
<html>
<head>
<title></title>
</head>
<body>
</body>
</html>
1.3 Теги A, IMG, Script и Style
Тег a является одним из важных элементов HTML и
предназначен для создания ссылок. В зависимости от присутствия атрибутов name
или href тег <a> устанавливает ссылку или якорь. Якорем называется
закладка внутри страницы, которую можно указать в качестве цели ссылки. При
использовании ссылки, которая указывает на якорь, происходит переход к закладке
внутри веб-страницы.
Синтаксис
<a href= «URL»>…</a>
<a name= «идентификатор»>…</a>
Тег img, как один из самых основных в HTML, нужен для
вставки изображения на страницу. Он имеет такой синтаксис:
<img src= «путь_к_картинке»>
Тег может иметь пути, как внутренний (например, к картинке в
папке), так и внешний (указанный ссылкой на изображение в Сети).
Для тега img рекомендуется прописывать описание (всплывающую
подсказку) вида:
<img src= «blog.jpg» alt= «Блог» title= «Блог»>
Такое указание описаний позволит дать поисковым системам
больше информации об изображении, и, соответственно, ваша картинка будет иметь
позиции гораздо выше при поиске картинок.
Тег script (англ. script - сценарий) - тег-контейнер,
добавляет на страницу скрипт. Текст скрипта может располагаться между начальным
и конечным тегами или определяется как URL файла, содержащего скрипт. Может
содержаться как в секции <head>, так и в <body>
Обычно скрипты используются для манипуляций с рисунками,
проверки ввода данных в форму или динамического изменения контента.
В случае если браузер не поддерживает скрипты, тег
<script> будет проигнорирован. Все, что расположено между <script>
и </script> будет выведено на экран, как обычный текст. Для того, чтобы
этого не случилось текст скрипта обозначается, как комментарий (<! - //
->).
Тег style применяется для определения стилей элементов
веб-страницы Тег <style> необходимо использовать внутри контейнера
<head>. Можно задавать более чем один тег <style>.
Синтаксис:
<head>
<style type= «text/css»>
…
</style>
</head>
Пример:
<! DOCTYPE HTML>
<html>
<head>
<meta charset= «utf-8»>
<title>Тег STYLE</title>
<style type= «text/css»>{size: 120%;family:
Verdana, Arial, Helvetica, sans-serif;: #333366;
}
</style>
</head>
<body>
<H1>Hello, world!</H1>
</body>
</html>
2.
Используемые технологии Java
.1 Общие сведения о Java
Java - это мощный язык программирования, разработанный в 1995
г. фирмой Sun Microsystems (в последующем приобретённой компанией Oracle) для интерактивного
телевидения и управления бытовыми устройствами. Однако быстрое развитие
Internet открыло другое призвание Java - создание небольших программ,
называемых аплетами (applets), которые могут быть загружены Веб-браузером с
сервера и исполнены на стороне клиента.
Популярность Java объясняется тем, что он имеет одно
принципиальное отличие от всех остальных языков программирования. Как известно,
все языки делятся на компилируемые и интерпретируемые. Программа на
компилируемом языке (например, C++) перед использованием должна быть предварительно
скомпилирована и собрана в загрузочный модуль в машинных кодах. Такой модуль
характеризуется высокой скоростью работы, но он жестко привязан к конкретной
платформе и конкретной операционной системе; для его переноса в другую среду
требуется перекомпиляция всей программы. Интерпретируемые языки не требуют
предварительной компиляции, программы на них исполняются интерпретатором,
который читает исходный текст программы и немедленно его исполняет.
Программа на языке Java компилируется в промежуточный стандартный
код, который называется байт-кодом (такие файлы имеют расширение.class). Этот
код не является машинным языком какого-либо конкретного процессора, а
специально создан авторами Java; его следует рассматривать как язык ассемблера
виртуальной Java-машины, не имеющей физической реализации.
2.2 Описание библиотеки JSOUP, предназначенной
для обработки HTML страницы
Java-библиотека jsoup предназначена
для разбора HTML-страниц (парсинг), позволяя извлечь необходимые данные,
используя DOM, CSS и методы в стиле jQuery.
Библиотека поддерживает спецификации HTML5
и позволяет парсить страницы, как это делают современные браузеры.
Библиотеке можно предоставить для анализа
URL, файл или строку.
Синтаксис очень прост в использовании и
достаточно гибок, чтобы получить то, что необходимо.
В приложении JSOUP используется для обработки HTML документа
и получения ссылок на другие ресурсы из соответствующих тэгов:
Метод разбора исходного HTML документа. Считывает
исходный файл, загруженный по ссылке page, и заменяет ссылки, найденные в base[href], a[href], img[src], link[href], script[src], на ссылки на
загружаемые файлы. Для обработки используется библиотека Jsoup.
@param dm объект DownloadManager необходим для получения
доступа к глобальному списку ссылок.
@param page ссылка на текущую страницу.
@param sourceFileName имя исходного файла.
@param destFileName имя файла, в котором исходные ссылки уже
заменены на локальные.
@param charsetName кодировка исходного файла.
@return список ссылок, найденных в файле.
@see Jsoup
@see DownloadManager
@see DownloadURLList<DownloadURL>
parseLinksInDocument (DownloadManager dm, DownloadURL page, String
sourceFileName, String destFileName, String charsetName) {{<DownloadURL>
pageLinks = new ArrayList<DownloadURL>();sourceFile = new File(sourceFileName);
// Обработка HTML файла sourceFile с кодировкой
charsetNamedoc = Jsoup.parse (sourceFile, charsetName);
// Поиск тэгов base с атрибутами href
Elements base = doc.select («base[href]»);
// Поиск тэгов a с атрибутами href
Elements links = doc.select («a[href]»);
// Поиск тэгов img с атрибутом src
Elements media = doc.select («img[src]»);
// Поиск тэгов import с атрибутом href
Elements imports = doc.select («link[href]»);
// Поиск тэгов script с атрибутом src
Elements scripts = doc.select («script[src]»);
// Для каждого тэга base(Element b: base) {
// Формируем абсолютную ссылку на ресурс из аттрибута href тэга
URL url = makeURL (b.attr («href»),
page.getUrl()); (url!= null) {
// Если ссылка указывает на ресурс этого же домена, заменяем
на ссылку на локальный файл
if (url.getHost().equals
(page.getUrl().getHost())) {
// Если ссылка указывает на ресурс на этом же домене, то
добавляем ссылку для дальнейшего скачивания
if (! dm.globalInfo.contains(url) &&
page.getLevel() < Common.DEFAULTLEVEL) {du = new DownloadURL (url,
page.getLevel() + 1, null,
DownloadURL.DOWNLOADING);.globalInfo.addPageInfo(du);.add(du);
}.attr («href»,
dm.globalInfo.getSiteSaveAbsolutePath() + url.getPath());
} else {.attr («href»,
dm.globalInfo.getSiteSaveAbsolutePath() + File.separator + url.getHost() +
url.getPath());
}
}
}
// Для каждого тэга img(Element src: media) {
// Формируем абсолютную ссылку на ресyрс из атрибута src
URL url = makeURL (src.attr («src»),
page.getUrl()); (url!= null) {
// Если ссылка на документ находящийся на том же домене, то
ссылка заменяется на локальный файл
if (url.getHost().equals
(page.getUrl().getHost())) {
// Если ссылка на документ того же домена, то добавляет в
глобальный список ссылок для скачивания
if (! dm.globalInfo.contains(url) &&
page.getLevel() < Common.DEFAULTLEVEL) {du = new DownloadURL (url,
page.getLevel() + 1, null,
DownloadURL.DOWNLOADING);.globalInfo.addPageInfo(du);.add(du);
}.attr («src»,
dm.globalInfo.getSiteSaveAbsolutePath() + url.getPath());
} else {.attr («src»,
dm.globalInfo.getSiteSaveAbsolutePath() + File.separator + url.getHost() +
url.getPath());
}
}
}
// Для каждого тэга import(Element link: imports)
{
// Формируем абсолютную ссылку на ресyрс из атрибута href
URL url = makeURL (link.attr («href»),
page.getUrl()); (url!= null) {
// Если ссылка на документ находящийся на том же домене, то
ссылка заменяется на локальный файл
if (url.getHost().equals
(page.getUrl().getHost())) {
// Если ссылка на документ того же домена, то добавляет в
глобальный список ссылок для скачивания
if (! dm.globalInfo.contains(url) &&
page.getLevel() < Common.DEFAULTLEVEL) {du = new DownloadURL (url,
page.getLevel() + 1, null,
DownloadURL.DOWNLOADING);.globalInfo.addPageInfo(du);.add(du);
}.attr («href», dm.globalInfo.getSiteSaveAbsolutePath()
+ url.getPath());
} else {.attr («href»,
dm.globalInfo.getSiteSaveAbsolutePath() + File.separator + url.getHost() +
url.getPath());
}
}
}
// Для каждого тэга link(Element link: links) {
// Формируем абсолютную ссылку на ресyрс из аттрибута href
URL url = makeURL (link.attr («href»),
page.getUrl()); (url!= null) {
// Если ссылка на документ находящийся на том же домене, то
ссылка заменяется на локальный файл
if (url.getHost().equals
(page.getUrl().getHost())) {
// Если ссылка на документ того же домена, то добавляет в
глобальный список ссылок для скачивания
if (! dm.globalInfo.contains(url) &&
page.getLevel() < Common.DEFAULTLEVEL) {du = new DownloadURL (url,
page.getLevel() + 1, null, DownloadURL.DOWNLOADING);.add(du);.globalInfo.addPageInfo(du);
}.attr («href»,
dm.globalInfo.getSiteSaveAbsolutePath() + url.getPath());
} else {.attr («href»,
dm.globalInfo.getSiteSaveAbsolutePath() + File.separator + url.getHost() +
url.getPath());
}
}
}
// Для каждого тэга script(Element script:
scripts) {
// Формируем абсолютную ссылку на ресyрс из атрибута href
URL url = makeURL (script.attr («src»),
page.getUrl()); (url!= null) {
// Если ссылка на документ находящийся на том же домене, то
ссылка заменяется на локальный файл
if (url.getHost().equals
(page.getUrl().getHost())) {
// Если ссылка на документ того же домена, то добавляет в
глобальный список ссылок для скачивания
if (! dm.globalInfo.contains(url) &&
page.getLevel() < Common.DEFAULTLEVEL) {du = new DownloadURL (url,
page.getLevel() + 1, null,
DownloadURL.DOWNLOADING);.add(du);.globalInfo.addPageInfo(du);
}.attr («src»,
dm.globalInfo.getSiteSaveAbsolutePath() + url.getPath());
} else {.attr («src»,
dm.globalInfo.getSiteSaveAbsolutePath() + File.separator + url.getHost() +
url.getPath());
}
}
}dest = new File(destFileName);(!
sourceFileName.equals(destFileName))(dest.delete()).moveFile (sourceFile, new
File(destFileName));
// if (sourceFile.delete())
pw = new PrintWriter(destFileName);.write
(doc.html());.flush();.close();pageLinks;
} catch (IOException ex) {.getLogger
(Parser.class.getName()).log (Level.SEVERE, null, ex);
}
return null;
}
.3 Многопоточность в Java
браузер программа сайт
тег
Наиболее очевидная область применения многопоточности - это
программирование интерфейсов. Многопоточность незаменима тогда, когда
необходимо, чтобы графический интерфейс продолжал отзываться на действия
пользователя во время выполнения некоторой обработки информации. Например,
поток, отвечающий за интерфейс, может ждать завершения другого потока,
загружающего файл из интернета, и в это время выводить некоторую анимацию или
обновлять прогресс-бар. Кроме того он может остановить поток загружающий файл,
если была нажата кнопка «отмена».
Еще одна популярная и, пожалуй, одна из самых распространённых
областей применения многопоточности - игры. В играх различные потоки могут
отвечать за работу с сетью, анимацию, расчет физики и т.д.
Рассмотрим пример реализации многопоточности из нашей
программы. Приложение использует механизм многопоточности для параллельного
скачивания файлов. Для каждой загрузки открывается новый поток загрузки. Код
метода run() потока, выполняющего непосредственную загрузку файлов:
Метод запуска потока загрузки, внутри него создается HTTP
соединение с необходимыми параметрами и запускается скачивание.
public void run() {file = null;stream = null;
// Создает класс обработки файловparser = new
Parser();httpclient = new DefaultHttpClient();
try {
// Добавление перехвата запроса и ответа для правильной
обработки
// файлов, которые сжаты методом GZIP.addRequestInterceptor
(new HttpRequestInterceptor() {
public void process (HttpRequest
request,HttpContext context) throws HttpException, IOException {(!
request.containsHeader («Accept-Encoding»)) {.addHeader («Accept-Encoding»,
«gzip»);
}
}
});.addResponseInterceptor (new
HttpResponseInterceptor() {void process (HttpResponse response,HttpContext
context) throws HttpException, IOException {entity =
response.getEntity();(entity!= null) {ceheader =
entity.getContentEncoding();(ceheader!= null) {[] codecs =
ceheader.getElements();(int i = 0; i < codecs.length; i++)
{(codecs[i].getName().equalsIgnoreCase («gzip»)) {.setEntity
(GzipDecompressingEntity (response.getEntity()));
return;
}
}
}
}
}
});
// Формирование запроса на WEB-сервер с необходимыми
параметрами для
// возможности докачки файловhttpget = new HttpGet
(this.url.toString());
httpget.addHeader («Range»,
«bytes=» + downloaded +» -»);.addHeader
(«Accept», «text/html, application/xhtml+xml, application/xml; q=0.9,*/*;
q=0.8»);.addHeader («Pragma», «no-cache»);.addHeader («User-Agent»,
Common.USERAGENT);response = httpclient.execute(httpget);
// Проверка, что ответ сервера говорит об успешной обработке
запроса
if (response.getStatusLine().getStatusCode() /
100!= 2) {();
}
// Вычисление оставшейся части документа для дозагрузки
long contentLength = -1;(response.getHeaders
(«Content-Length»).length == 0)();{= Long.valueOf (response.getHeaders
(«Content-Length») [0].getValue());(contentLength < 1) {();
}
}
(size == -1) {= contentLength;();
}fullFileName;tempFileName;(getFileName(url.getUrl()).length()
< 2)= downloadManager.globalInfo.getSiteSaveTempPath() + File.separator +
Common.getTempfileName («index.html»);=
downloadManager.globalInfo.getSiteSaveTempPath() + File.separator + Common.getTempfileName
(getFileName(url.getUrl()));
// Проверка, необходим ли разбор файла на наличие вложенных
ссылок
if (Parser.isParseable
(response.getEntity().getContentType().getValue())) {= fullFileName +».tmp»;
} else {= fullFileName;
}.setTempFileName(fullFileName);= new
RandomAccessFile (tempFileName, «rw»);.seek(downloaded);=
response.getEntity().getContent();
// Скачивание файла(status == DOWNLOADING) {buffer[] = new byte
[MAX_BUFFER_SIZE];
// Чтение данных из потокаread = stream.read(buffer);(read
<= 0);
// Запись данных в файл
file.write (buffer, 0, read);+= read;
stateChanged();
}
// Выполнение действий после успешного скачивания файла
if (status == DOWNLOADING) {= COMPLETE;.setStatus
(DownloadURL.COMPLETE);.globalInfo.incrementCompletedPagesNumber();contentType
= response.getEntity().getContentType().getValue();(url.getLevel() <=
Common.DEFAULTLEVEL && Parser.isParseable(contentType))
{<DownloadURL> descendantPages = null;.out.println(contentType);(contentType.contains
(«text/html»))= parser.parseLinksInDocument (downloadManager, url,
tempFileName, fullFileName, Charset.defaultCharset().name());if
(contentType.contains («text/css»))= parser.parseCSSDocument (url,
tempFileName, fullFileName);(DownloadURL u: descendantPages) {
//System.out.println(«{» + u.getLevel() +»}» +
u.getUrl());.sleep(100);.globalInfo.incrementPagesNumber();.addDownload (new
Download (downloadManager, u, tableModel));
}.setNoDescendants(true);
} else.setNoDescendants(true);
();
}
} catch (Exception e) {.printStackTrace();();
} finally {
// Закрытие файла(file!= null) {{.close();
} catch (Exception e) {}
}
// Закрытие соединения с сервером(stream!= null) {
try {.close();
} catch (Exception e) {}
}
httpclient.getConnectionManager().shutdown();
}
}
.4 Java Swing
Первые Java программы страдали бедностью интерфейсов. Более
того, создание интерфейса, который запускался бы на любой платформе, часто было
сложной задачей. Однако библиотека Swing изменила все. Благодаря Swing ваши
приложения могут прекрасно выглядеть и прекрасно работать и под Windows, и под
Linux, и на любой другой платформе.это набор для создания богатого графического
интерфейса пользователя (GUI) для Java программ и апплетов. Вот основные
преимущества использования библиотеки Swing перед её аналогами:
· богатый набор
интерфейсных примитивов
· настраивающийся внешний
вид на различных платформах (look and feel)
· раздельная архитектура
модель-вид (model-view)
· встроенная поддержка HTML
Создание сложного GUI при помощи AWT (Abstract Window Toolkit - это первая оконная
подсистема) практически невозможно, поскольку в AWT нет основных интерфейсных
примитивов. Swing же предоставляет этот набор и не только. Он также делает
создание GUI более легким за счет применения набора настраиваемых границ
(Borders) и менеджеров размещения (LayoutManagers).
Практически все компоненты Swing начинаются с главенствующей
буквы J (JFrame, JTable, JMenu). Названия всех компонентов очевидны, и сходны с
теми, которые использовались в AWT. К примеру, если в AWT в роли окна верхнего
уровня использовалось Frame, в Swing используется в аналогичной роли JFrame.
Краткое описание некоторых важных элементов, которых не имела в своем активе
AWT приведены ниже.
JInternalFrame
|
Окно,
существующее внутри другого окна верхнего уровня, например в JFrame.
|
JProgressBar
|
Строка,
отображающая процесс проистечения какого-то события, например процесс
загрузки.
|
JSlider
|
«Ползунок»,
позволяющий пользователю выбирать предел отображения величин.
|
JTable
|
Компонент,
представляющий данные в виде таблиц.
|
JTree
|
Компонент,
представляющий данные в иерархическом виде.
|
SWING используется для построения графического
пользовательского интерфейса приложения. Графические элементы интерфейса
создаются в конструкторе класса DownloadManager:
Конструктор класса, вызывается при запуске приложения. Он
создает элементы графического интерфейса:
public DownloadManager() {
// Установка заголовка окна(«Offline browser»);
// Размер окна(640, 480);
// Обработка события закрытия окна
addWindowListener (new WindowAdapter() {void
windowClosing (WindowEvent e) {();
}
});
// Добавление менюmenuBar = new JMenuBar();fileMenu = new JMenu («Файл»);.setMnemonic
(KeyEvent.VK_F);fileExitMenuItem = new JMenuItem («Выход»,.VK_X);.addActionListener
(new ActionListener() {void actionPerformed (ActionEvent e) {();
}
});.add(fileExitMenuItem);.add(fileMenu);
setJMenuBar(menuBar);
// Верхняя панель с кнопками для ввода ссылки для загрузки
JPanel addPanel = new JPanel (new FlowLayout());=
new JTextField(30);.add(addTextField);addButton = new JButton («Загрузить»);.addActionListener
(new ActionListener() {void actionPerformed (ActionEvent e) {();
}
});.add(addButton);labelChooseDir = new JLabel («Путь сохранения файлов»);.add(labelChooseDir);dirField
= new JTextField();
addPanel.add(dirField);
// Таблица для отображения статуса загружаемых файлов
tableModel = new DownloadsTableModel();= new
JTable(tableModel);.getSelectionModel().addListSelectionListener (new() {void
valueChanged (ListSelectionEvent e) {();
}
});.setSelectionMode
(ListSelectionModel.SINGLE_SELECTION);renderer = new ProgressRenderer (0,
100);.setStringPainted(true); // show progress text.setDefaultRenderer
(JProgressBar.class, renderer);.setRowHeight(
(int) renderer.getPreferredSize().getHeight());
// Панель для отображения таблицы загрузокdownloadsPanel
= new JPanel();.setBorder (.createTitledBorder («Загрузки»));.setLayout (new
BorderLayout());.add (new JScrollPane(table),
BorderLayout.CENTER);
// Нижняя панель с кнопками управления загрузками
JPanel buttonsPanel = new JPanel();= new JButton
(«Пауза»);.addActionListener
(new ActionListener() {void actionPerformed (ActionEvent e) {();
}
});.setEnabled(false);.add(pauseButton);= new
JButton («Возобновление»);.addActionListener
(new ActionListener() {void actionPerformed (ActionEvent e) {();
}
});.setEnabled(false);.add(resumeButton);= new
JButton («Отмена»);.addActionListener
(new ActionListener() {void actionPerformed (ActionEvent e) {();
}
});.setEnabled(false);.add(cancelButton);= new
JButton («Очистка»);.addActionListener
(new ActionListener() {void actionPerformed (ActionEvent e) {();
}
});.setEnabled(false);.add(clearButton);
// Добавление панелей в окно приложения().setLayout
(new BorderLayout());().add (addPanel, BorderLayout.NORTH);().add
(downloadsPanel, BorderLayout.CENTER);().add (buttonsPanel,
BorderLayout.SOUTH);
}
3. Реализация программы
.1 Описание программы
Приложение представляет собой менеджер загрузок с
возможностью дозагрузки не полностью загруженных файлов. Перед загрузкой
необходимо выбрать директорию сохранения файлов и глубину их обработки.
Приложение поддерживает обработку содержащихся в файлах ссылок на другие
ресурсы, что позволяет скачивать содержимое сайта с заданным уровнем
вложенности. Обработка множества файлов происходит одновременно благодаря
поддержке многопоточной обработки - для каждого отдельного файла открывается
новый поток для скачивания.
Обработка файлов разных типов:
· HTML - файлы типа HTML разбираются на
наличие в них ссылок на другие ресурсы в следующих элементах документа:
· тэг base, атрибут href,
· тэг a, атрибут href,
· тэг img, атрибут src,
· тэг link, атрибут href,
· тэг script, атрибут src.
· CSS - внутри файлов с типом CSS происходит
поиск атрибутов содержащих значения типа url, указывающие на другие ресурсы.
В дальнейшем, если уровень вложенности, задаваемый перед
загрузкой, не превышает уровня вложенности текущего документа, приложение
докачивает файлы, на которые указывают ссылки.
Такой принцип работы дает возможность сохранения веб-сайтов
целиком. Поддерживается обработка сжатых методом GZIP ресурсов, которая часто
используется для уменьшения размера ресурсов.
Инструкции по использованию.
После запуска приложения открывается окно следующего вида:
Для загрузки WEB-ресурса необходимо указать следующие данные:
· Ссылку на документ, который необходимо
скачать.
· Выбрать директорию на компьютере, в
которую будут сохранены данные.
· Если необходимо изменить заполненный по
умолчанию уровень вложенности скачиваемых документов.
· Далее после нажатия на кнопку «Загрузить»
начнется загрузка документов.
После запуска загрузки вы можете непосредственно ими
управлять.
При выборе загрузки становятся активными кнопки управления
скачиванием:
· Кнопка «Пауза» предназначена для
приостановки загрузки.
· Кнопка «Возобновление» предназначена для
возобновления загрузки.
· Кнопка «Отмена» предназначена для отмены
загрузки.
· Кнопка «Очистка» удаляет выбранную
загрузку из таблицы.
3.2 Описание классов
Class Common
· java.lang. Object
· org.agu.fizmat.pm.offlinebrowser.
Common
public class Commonjava.lang. Object
Класс содержит общие методы и константы
· Поля класса
Модификатор
и тип
|
Поле и
описание
|
static
java.lang. String
|
CONTENTTYPECSS
Content-type документа, соответствующие CSS таблице стилей
|
static
java.lang. String
|
CONTENTTYPEHTML
Content-type документа, соответствующие HTML документу
|
static
java.lang. String
|
CONTENTTYPEJAVASCRIPT
Content-type документа, соответствующие JavaScript файлам
|
static int
|
DEFAULTLEVEL
Уровень вложенности по умолчанию при скачивании файлов
|
static
java.lang. String
|
DOWNLOADSPATH
|
static
java.lang. String
|
USERAGENT
User-Agent, которым подписывает HTTP клиент при скачивании данных
|
· Конструкторы
· Common
publicCommon()
· Методы
· getTempfileName
public staticjava.lang. StringgetTempfileName
(java.lang. Stringpage)
Метод формирует временное имя для файла из его адреса.
Использует алгоритм SHA1 для получения уникальной строки
Параметры:
page - HTTP адрес файла
Возвращает:
временное имя файла
Class
Download
· java.lang. Object
· java.util. Observable
· org.agu.fizmat.pm.offlinebrowser.
Download
· All Implemented Interfaces:
java.lang. Runnable
Класс представляет собой абстракцию потока скачивания.
Создается для каждого файла, который необходимо скачать, вне зависимости от его
типа
· Поля класса
Модификатор
и тип данных
|
Имя поля и
описание
|
static int
|
CANCELLED
Статус присваивается, если процесс скачивания отменен
|
static int
|
COMPLETE Статус
присваивается после удачного завершения процесса скачивания
|
static int
|
DOWNLOADING
Статус присваивается в процессе скачивания
|
static int
|
ERROR Статус
присваивается, если при скачивании произошла ошибка
|
static int
|
PAUSED Статус
присваивается после того как скачивание приостановлено
|
static
java.lang. String[]
|
STATUSES Список
статусов для ссылки
|
· Конструкторы
· Download
Public Download (DownloadManager dm,url,tableModel)
Конструктор класса, при создании автоматически запускается
процесс скачивания документа по ссылке url
Параметры:- экземпляр класса менеджера загрузки, который
инициировал скачивание- объект класса DownloadURL, содержит ссылку для
скачивания файла- графический элемент, содержащий информацию о процессе
скачивания
· Методы
· getUrl
public java.lang. String getUrl()
Метод получения строки, представляющей ссылку на документ
Возвращает:
ссылку на файл
· getSize
public long getSize()
Метод получения размера скачиваемого файла
Возвращает:
размер файла в байтах
· getProgress
public float getProgress()
Метод получения процентной доли скачанного от общего размера
файла
Возвращает:
число от 0 до 100, соответствующего процентной доли
скачанного файла
· getStatus
public int getStatus()
Получение текущего статуса загрузки
Возвращает:
статус загрузки
· pause
public void pause()
Метод приостановки загрузки
· resume
public void resume()
Метод возобновления загрузки
· cancel
public void cancel()
Метод отмены загрузки
· run
public void run()
Метод запуска потока загрузки, внутри него создается HTTP
соединение с необходимыми параметрами и запускается скачивание
Определен для: run in interface
java.lang. Runnable
Class
DownloadManager
· java.lang. Object
· java.awt. Component
· java.awt. Container
· java.awt. Window
· java.awt. Frame
· javax.swing.JFrame
· org.agu.fizmat.pm.offlinebrowser.
DownloadManager
· All Implemented Interfaces:
java.awt.image. ImageObserver, java.awt.
MenuContainer, java.io. Serializable, java.util. Observer, javax.accessibility.
Accessible, javax.swing. RootPaneContainer, javax.swing. WindowConstantsclass DownloadManagerjavax.swing.JFramejava.util.
Observer
Класс - главное окно приложения
Модификатор
и тип
|
Поле и
описание
|
GlobalInfo
|
globalInfo
Переменная, хранящая общую информацию, необходимую для скачивания и обработки
файлов
|
· Конструкторы
· DownloadManager
public DownloadManager()
Конструктор класса, вызывается при запуске приложения.
Создает элементы графического интерфейса
· Методы
· update
public void update (java.util. Observable o,
java.lang. Object arg)
Метод оповещения об изменении статуса загружаемых файлов
Определен для:in interface java.util.
Observer
· main
public static void main (java.lang. String[]
args)
Class DownloadsTableModel
· java.lang. Object
· javax.swing.table. AbstractTableModel
· org.agu.fizmat.pm.offlinebrowser.
DownloadsTableModel
· All Implemented Interfaces:
java.io. Serializable, java.util. Observer,
javax.swing.table. TableModelclass DownloadsTableModeljavax.swing.table.
AbstractTableModel
implements java.util. Observer
Класс реализует объект AbstractTableModel и предназначен для
отображения информации о скачиваемых файлах.
· Конструкторы
· DownloadsTableModel
public DownloadsTableModel()
· Методы
· addDownload
public void add Download (Download download)
Метод добавления загрузки
Параметры:- поток загрузки файлов
· getDownload
public Download getDownload (int row)
Метод получения объекта Download по номеру строки в таблице
Параметры:- идентификатор строки в таблице
Возвращает:
Объект Download представляющий поток загрузки, информация о
котором отображается на строке row
· clearDownload
public void clearDownload (int row)
Метод удаления загрузки для строки с номером row
Параметры:- номер строки
· getColumnCount
public int getColumnCount()
Метод получения числа столбцов в таблице
Определен для:in interface
javax.swing.table. TableModel
Возвращает:
число столбцов
· getColumnName
public java.lang. String getColumnName (int col)
Метод получения имени столбца по номеру
Определен для:in interface
javax.swing.table. TableModel
Переопределение:in class
javax.swing.table. AbstractTableModel
Параметры:- порядковый номер столбца в таблице
Возвращает:
имя столбца
· getColumnClass
public java.lang. Class getColumnClass (int col)
Метод получения класса по номеру столбца
Определен для:in interface
javax.swing.table. TableModel
Переопределение:in class
javax.swing.table. AbstractTableModel
Параметры:
col - номер столбца
Возвращает:
класс объекта, содержащегося в столбце с номером col
· getRowCount
public int getRowCount()
Метод получения количества строк в таблице
Определен для:in interface javax.swing.table.
TableModel
Возвращает:
кол-во строк в таблице
· getValueAt
public java.lang. Object getValueAt (int row,
int col)
Метод получения содержимого ячейки таблицы на строке row и
столбце col
Определен для:in interface
javax.swing.table. TableModel
Параметры:
row - номер строки
col - номер столбца
Возвращает:
объект, содержащийся в ячейке таблицы
· update
public void update (java.util. Observable o,
java.lang. Object arg)
Метод, вызываемый при обновлении каких-либо данных в таблице
Определен для:in interface java.util.
Observer
Параметры:- объект Observable- объект который необходимо
обновить
Class
DownloadURL
· java.lang. Object
· org.agu.fizmat.pm.offlinebrowser.
DownloadURL
· All Implemented Interfaces:
java.lang. Comparable<DownloadURL>class DownloadURLjava.lang.
Object
implements java.lang.
Comparable<DownloadURL>
Класс содержит необходимую информацию для обработки файлов
· Поля класса
Модификатор
и тип
|
Название
поля и описание
|
static int
|
COMPLETE
Статус, свидетельствующий том, что скачивание документа успешно завершено
|
static int
|
DOWNLOADING
Статус, свидетельствующий том, что документ в процессе скачивания
|
static int
|
ERROR Статус,
свидетельствующий том, что скачивание документа завершено с ошибкой
|
· Конструкторы
· DownloadURL
public DownloadURL (java.net.URL url,level,.lang.
String tempFileName, status)
Конструктор класса
Параметры:- ссылка на файл- уровень вложенности документа-
имя временного файла, в который сохраняется скачиваемый документ
status - статус обработки файла
· Методы
· toString
public java.lang. String toString()
Переопределение:in class
java.lang. Object
· equals
public boolean equals (java.lang. Object obj)
Метод проверки на равенство 2 объектов DownloadUrl.
Сравниваются значения DownloadUrl.getUrl() каждого объекта
Переопределение:in class
java.lang. Object
Параметры:- сравниваемый с текущим объект DownloadUrl
Возвращает:
· getUrl
public java.net.URL getUrl()
Метод получения ссылка на документ
Возвращает:url HTTP ссылка на документ
· setUrl
public void setUrl (java.net.URL url)
Метод устанавливает значение ссылки, указывающей на документ,
который необходимо скачать
Параметры:- URL для сохранения
· getLevel
public int getLevel()
Метод получения уровня вложенности документа
Возвращает:level уровень вложенности
· setLevel
public void setLevel (int level)
Метод установки уровня вложенности документа
Параметры:- уровень вложенности
· getStatus
public int getStatus()
Получение статуса обработки документа, доступного по ссылке
Возвращает:
статус обработки документа, доступного по ссылке
· setStatus
public void setStatus (int status)
Метод установки текущего статуса обработки документа
· getTempFileName
public java.lang. Strin ggetTempFileName()
Метод получения имени временного файла, в который сохраняется
загружаемый документ
Возвращает:
имя файла
· setTempFileName
public void setTempFileName (java.lang. String
tempFileName)
Метод установки значения имени временного файла, в который
сохраняется загружаемый документ
Параметры:
имя - файла
· isNoDescendants
public boolean isNoDescendants()
Проверка, существуют ли дочерние документы, которые
необходимо скачать
Возвращает:значение, true - есть дочерние элементы,
false - нет
· setNoDescendants
public void setNoDescendants (boolean
noDescendants)
Метод установки поля класса, указывающего есть ли у текущего
дочерние документы
Параметры:- если true - дочерние элементы есть, если false
- нет
· compareTo
public int compareTo (DownloadURL o)
Метод сравнения 2 объектов DownloadUrl. Сравниваются значения
DownloadUrl.getUrl() каждого объекта
Определен для:in interface java.lang.
Comparable<DownloadURL>
Параметры:- сравниваемый с текущим объект DownloadUrl
Class
GlobalInfo
· java.lang. Object
· org.agu.fizmat.pm.offlinebrowser.
GlobalInfo
public class GlobalInfojava.lang. Object
Класс хранит общую информацию для приложения, включающую в
себя список ссылок на файлы, кол-во загруженных файлов, путь для сохранения
данных и т.д.
· Методы
· addPageInfo
public void addPageInfo (DownloadURL page)
Метод добавления новой страницы в глобальный список скачиваемых
документов
Параметры:- объект DownloadURL, который будет загружен
· contains
public boolean contains (java.net.URL url)
Метод проверки, загружалась ли ранее эта страница.
Параметры:
url - URL страницы
Возвращает:- если страница уже загружалась, false если
нет
· incompletePages
public int incompletePages()
Метод возвращает число необработанных еще страниц
Возвращает:
число страниц
· getGlobalUrlsList
public java.util. Set getGlobalUrlsList()
Метод получения Set из скачиваемых страниц
Возвращает:скачиваемых страниц
· getInitialURL
public java.net.URL getInitialURL()
Метод получения начальной ссылки на страницу, с которой
начинается скачивание
Возвращает:initialURL начальный URL
· getSiteSaveAbsolutePath
public java.lang. String
getSiteSaveAbsolutePath()
Метод получения пути сохранения файлов
Возвращает:
путь сохранения файлов
· getSiteSaveTempPath
public java.lang. String getSiteSaveTempPath()
Метод получения пути для временного хранения файлов
Возвращает:
путь временного хранения файлов
· getAllPagesNumber
public int getAllPagesNumber()
Метод получения общего числа скачиваемых документов
Возвращает:
число всех скачиваемых файлов
· incrementPagesNumber
public void incrementPagesNumber()
Метод увеличения на 1 количества всех ссылок
· getCompletedPagesNumber
public int getCompletedPagesNumber()
Метод получения числа обработанных документов
Возвращает:
число обработанных документов
· incrementCompletedPagesNumber
public void incrementCompletedPagesNumber()
Метод увеличивает на 1 число обработанных документов
· getErrorPagesNumber
public int getErrorPagesNumber()
Метод возвращает число страниц, обработка которых завершилась
с ошибкой
Возвращает:
число страниц обработанных с ошибкой
· incrementErrorPagesNumber
public void incrementErrorPagesNumber()
Метод увеличивает на 1 число страниц, обработка которых
завершилась с ошибкой
· createSiteStructure
public void createSiteStructure()
Метод перемещает и переименовывает файлы из места временного
хранения и создает нужную структуру каталогов
Class
Parser
· java.lang. Object
· org.agu.fizmat.pm.offlinebrowser.parser.
Parser
public class Parserjava.lang. Object
Класс, содержит вспомогательные методы для обработки
документов и обновления ссылок в них
· Конструктор
· Parser
publicParser()
· Методы
· isParseable
public static boolean isParseable (java.lang.
String contentType)
Метод проверяет по свойству Content-type скачиваемого
документа необходимо ли выполнять разбор документа для обновления в нем ссылок
Параметры:
contentType - строка содержащая Content-type документа
Возвращает:
если true, то необходим разбор документа, если false то
разбор не требуется
· makeURL
public java.net.URL makeURL (java.lang. String
link,
java.net.URL page)
Метод создания объекта URL из ссылок различного вида
найденных в документе
Параметры:- строковое представление ссылки в документе- URL
текущей страницы
Возвращает:ссылки представленной в параметре link
· parseCSSDocument
public java.util. List<DownloadURL>
parseCSSDocument (DownloadUR Lpage,.lang. String sourceFileName,.lang. String
destFileName)
Метод разбора CSS документа и обновления в нем ссылок на
загруженные ресурсы. Замена ссылок происходит применением регулярных выражений
к аттрибутам типа url(link)
Параметры:- текущая страница- имя исходного файла- имя
файла с уже преобразованными ссылками
Возвращает:
список объектов DownloadURL, которые представляют собой
ссылки на дочерние страницы
· parseLinksInDocument
public java.util. List<DownloadURL>
parseLinksInDocument (DownloadManager dm,Lpage,.lang. String sourceFileName,.lang.
String destFileName,.lang. String charsetName)
Метод разбора исходного HTML документа. Считывает исходный
файл, загруженный по ссылке page и заменяет ссылки найденные в base[href],
a[href], img[src], link[href], script[src] на ссылке на загружаемые файлы. Для
обработки используется библиотеку Jsoup
Параметры:- объект DownloadManager, необходим для получения
доступа к глобальному списку ссылок- ссылка на текущую страницу- имя исходного
файла- имя файла, в котором исходные ссылки уже заменены на локальные-
кодировка исходного файла
Возвращает:
список ссылок найденных в файле
Class
ProgressRenderer
· java.lang. Object
· java.awt. Component
· java.awt. Container
· javax.swing.JComponent
· javax.swing.JProgressBar
· org.agu.fizmat.pm.offlinebrowser.
ProgressRenderer
· All Implemented Interfaces:
java.awt.image. ImageObserver, java.awt.
MenuContainer, java.io. Serializable, javax.accessibility. Accessible,
javax.swing. SwingConstants, javax.swing.table. TableCellRenderer
class ProgressRendererjavax.swing.JProgressBarjavax.swing.table.
TableCellRenderer
Класс расширяет JProgressBar для отображения статус загрузки
· Конструкторы
· ProgressRenderer
public ProgressRenderer (int min, int max)
Конструктор класса
· Методы
· getTableCellRendererComponent
public java.awt. Component
getTableCellRendererComponent (javax.swing.JTable table,.lang. Object
value,isSelected,hasFocus,row,column)
Метод возвращает JProgressBar для ячейки таблицы (row, column)
Определен для:in interface
javax.swing.table. TableCellRenderer
Параметры:- таблица отображающая статус загрузок
value - значение
isSelected - выбрано
hasFocus - активно
row - номер строки
column - номер столбца
Возвращает:
JProgressBar со статусом загрузки
Заключение
В рамках данной дипломной работы мы постарались создать
приложение, которое может быть использовано для сохранения данных с Интернет
страниц. Было разработано приложение, достоинствами которого является:
. Возможность дозагрузки не полностью загруженных
файлов.
. Обработка файлов различных типов.
. Поддержка многопоточной обработки.
. Кроссплатформенность.
. Поддержка обработки содержащихся в файлах ссылок на
другие ресурсы, что позволяет скачивать содержимое сайта с заданным уровнем
вложенности.
Помимо вышеперечисленного, приложение спроектировано таким
образом, что пользователь может изменять программу в соответствии со своими
требованиями.
Литература
1. Герберт Шилдт, Джеймс Холмс - Искусство
программирования на JAVA. Москва: издательский дом «Вильямс». 2005 г., 336 стр.
2. Брюсс Эккель - Философия Java. Библиотека
программиста. 4-е издание. Санкт-Петербург. 2009 г., 640 стр.
. Учебник по HTML: http://ru.html.net/tutorials/html/
. Герберт Шилдт - Полный справочник по JAVA. Под редакцией Т.Н.
Артеменко, В.Г. Павлютин. 7-е издание - Москва: Издательский дом «Вильямс»,
2007 г., 1024 стр.
5. Jonathan Hedley - «Jsoup: Java
HTML Parser». http://jsoup.org/
6. Майкл Эферган - Java: справочник.
Издательство «Питер Ком», 1998 г.
. Кен Арнольд, Джеймс Гослинг - Язык
программирования Java. Издательство «Питер-Пресс», 1997 г.
. Патрик Нотон, Герберт Шилдт - Полный
справочник по Java. Издательство «Диалектика», 1997 г.