Книга: C# 4.0: полное руководство
Практический пример создания программы MiniCrawler
Практический пример создания программы MiniCrawler
Для того чтобы показать, насколько просто программировать для Интернета средствами классов WebRequest
и WebReponse
, обратимся к разработке скелетного варианта поискового робота под названием MiniCrawler
. Поисковый робот представляет собой программу последовательного перехода от одной ссылки на сетевой ресурс к другой. Поисковые роботы применяются в поисковых механизмах для каталогизации содержимого. Разумеется, поисковый робот MiniCrawler
не обладает такими развитыми возможностями, как те, что применяются в поисковых механизмах. Эта программа начинается с ввода пользователем конкретного адреса URI, по которому затем читается содержимое и осуществляется поиск в нем ссылки. Если ссылка найдена, то программа запрашивает пользователя, желает ли он перейти по этой ссылке к обнаруженному сетевому ресурсу, найти другую ссылку на имеющейся странице или выйти из программы. Несмотря на всю простоту такого алгоритма поиска сетевых ресурсов, он служит интересным и наглядным примером доступа к Интернету средствами С#.
Программе MiniCrawler
присущ ряд ограничений. Во-первых, в ней обнаруживаются только абсолютные ссылки, указываемые по гипертекстовой команде href="http. Относительные ссылки при этом не обнаруживаются. Во-вторых, возврат к предыдущей ссылке в программе не предусматривается. И в-третьих, в ней отображаются только ссылки, но не окружающее их содержимое. Несмотря на все указанные ограничения данного скелетного варианта поискового робота, он вполне работоспособен и может быть без особых хлопот усовершенствован для решения других задач. На самом деле добавление новых возможностей в программу MiniCrawler
— это удобный случай освоить на практике сетевые классы и узнать больше о сетевом подключении к Интернету. Ниже приведен полностью исходный код программы MiniCrawler
.
/* MiniCrawler: скелетный вариант поискового робота.
Применение: для запуска поискового робота укажите URI в командной строке. Например, для того чтобы начать поиск с адреса www.McGraw-Hill.com, введите следующую команду:
MiniCrawler http://McGraw-Hill.com
*/
using System;
using System.Net;
using System.IO;
class MiniCrawler {
// Найти ссылку в строке содержимого,
static string FindLink(string htmlstr,
ref int startloc) {
int i;
int start, end;
string uri = null;
i = htmlstr.IndexOf("href="http", startloc,
StringComparison.OrdinalIgnoreCase);
if (i != -1) {
start = htmlstr.IndexOf('"', i) + 1;
end = htmlstr.IndexOf('"', start);
uri = htmlstr.Substring(start, end - start);
startloc = end;
}
return uri;
}
static void Main(string[] args) {
string link = null; string str; string answer;
int curloc; // содержит текущее положение в ответе
if (args.Length != 1) {
Console.WriteLine("Применение: MiniCrawler <uri>");
return;
}
string uristr = args[0]; // содержит текущий URI
HttpWebResponse resp = null;
try {
do {
Console.WriteLine("Переход по ссылке " + uristr);
// Создать объект запроса типа WebRequest по указанному URI.
HttpWebRequest req = (HttpWebRequest)
WebRequest.Create(uristr);
uristr = null; // запретить дальнейшее использование этого URI
// Отправить сформированный запрос и получить на него ответ,
resp = (HttpWebResponse)req.GetResponse();
Stream istrm = resp.GetResponseStream();
// Заключить поток ввода в оболочку класса StreamReader.
StreamReader rdr = new StreamReader(istrm);
// Прочитать всю страницу,
str = rdr.ReadToEnd();
curloc = 0;
do {
// Найти следующий URI для перехода по ссылке,
link = FindLink(str, ref curloc);
if (link != null) {
Console.WriteLine("Найдена ссылка: " + link);
Console.Write("Перейти по ссылке, Искать дальше, Выйти?");
answer = Console.ReadLine();
if (string.Equals(answer, "П", StringComparison.OrdinalIgnoreCase)) {
uristr = string.Copy(link); break;
}
else if (string.Equals(answer, "B", StringComparison.OrdinalIgnoreCase)) {
break;
}
else if (string.Equals(answer, "И", StringComparison.OrdinalIgnoreCase)) {
Console.WriteLine("Поиск следующей ссылки.");
}
}
else {
Console.WriteLine("Больше ссылок не найдено.");
break;
}
} while (link.Length > 0);
// Закрыть ответный поток,
if (resp != null) resp.Close();
} while (uristr != null);
}
catch (WebException exc) {
Console.WriteLine("Сетевая ошибка: " + exc.Message +
"Код состояния: " + exc.Status);
}
catch (ProtocolViolationException exc) {
Console.WriteLine("Протокольная ошибка: " + exc.Message);
}
catch (UriFormatException exc) {
Console.WriteLine("Ошибка формата URI: " + exc.Message);
}
catch (NotSupportedException exc) {
Console.WriteLine("Неизвестный протокол: " + exc.Message);
}
catch (IOException exc) {
Console.WriteLine("Ошибка ввода-вывода: " + exc.Message);
}
finally {
if (resp != null) resp.Close();
Console.WriteLine("Завершение программы MiniCrawler.");
}
}
}
Ниже приведен пример сеанса поиска, начиная с адреса www .McGraw-Hill. com. Следует иметь в виду, что конкретный результат поиска зависит от состояния содержимого на момент поиска.
Переход по ссылке http://mcgraw-hill.com
Найдена ссылка: http://sti.mcgraw-hill.com:9000/cgi-bin/query?mss=search&pg=aq
Перейти по ссылке, Искать дальше, Выйти? И
Поиск следующей ссылки.
Найдена ссылка: http: //investor .mcgraw-hill. com/phoenix. zhtml?c=96562&p=irol-irhome
Перейти по ссылке,Искать дальше, Выйти? П
Переход по ссылке http://investor.mcgraw-hill .com/phoenix. zhtml?c=96562&p=irol-irhome
Найдена ссылка: http://www.mcgraw-hill.com/index.html
Перейти по ссылке, Искать дальше, Выйти? П
Переход по ссылке http://www.mcgraw-hill.com/index.html
Найдена ссылка: http://sti.mcgraw-hill.com:9000/cgi-bin/query?mss=search&pg=aq
Перейти по ссылке, Искать дальше, Выйти? В
Завершение программы MiniCrawler.
Рассмотрим подробнее работу программы MiniCrawler. Она начинается с ввода пользователем конкретного URI в командной строке. В методе Main()
этот URI сохраняется в строковой переменной uristr
. Затем по указанному URI формируется запрос, и переменной uristr
присваивается пустое значение, указывающее на то, что данный URI уже использован. Далее отправляется запрос и получается ответ. После этого содержимое читается из потока ввода, возвращаемого методом GetResponseStream()
и заключаемого в оболочку класса StreamReader
. Для этой цели вызывается метод ReadToEnd()
, возвращающий все содержимое в виде строки из потока ввода.
Далее программа осуществляет поиск ссылки в полученном содержимом. Для этого вызывается статический метод FindLink()
, определяемый в программе MiniCrawler. Этот метод вызывается со строкой содержимого и исходным положением, с которого начинается поиск в полученном содержимом. Эти значения передаются методу FindLink()
в виде параметров htmlstr
и startloc
соответственно. Обратите внимание на то, что параметр startloc
относится к типу ref
. Сначала в методе FindLink()
создается копия строки содержимого в нижнем регистре, а затем осуществляется поиск подстроки href="http, обозначающей ссылку. Если эта подстрока найдена, то URI копируется в строковую переменную uri
, а значение параметра startloc
обновляется и становится равным концу ссылки. Но поскольку параметр startloc
относится к типу ref
, то это приводит к обновлению соответствующего аргумента метода Main()
, активизируя поиск с того места, где он был прерван. В конечном итоге возвращается значение переменной uri
. Эта переменная инициализирована пустым значением, и поэтому если ссылка не найдена, то возвращается пустая ссылка, обозначающая неудачный исход поиска.
Если ссылка, возвращаемая методом FindLink()
, не является пустой, то она отображается в методе Main()
, и далее программа запрашивает у пользователя очередные действия. Пользователю предоставляются одна из трех следующих возможностей: перейти по найденной ссылке, нажав клавишу <П>, искать следующую ссылку в имеющемся содержимом, нажав клавишу <И>, или же выйти из программы, нажав клавишу <В>. Если пользователь нажмет клавишу <П>, то программа осуществит переход по найденной ссылке и получит новое содержимое по этой ссылке. После этого поиск очередной ссылки будет начат уже в новом содержимом. Этот процесс продолжается до тех пор, пока не будут исчерпаны все возможные ссылки.
В качестве упражнения вы сами можете усовершенствовать программу MiniCrawler, дополнив ее, например, возможностью перехода по относительным ссылкам. Сделать это не так уж и трудно. Кроме того, вы можете полностью автоматизировать поисковый робот, чтобы он сам переходил по найденной ссылке без вмешательства со стороны пользователя, начиная со ссылки, обнаруженной на самой первой странице полученного содержимого, и продолжая переход по ссылкам на новых страницах. Как только будет достигнут тупик, поисковый робот должен вернуться на один уровень назад, найти следующую ссылку и продолжить переход по ссылке. Для организации именно такого алгоритма работы программы вам потребуется стек, в котором должны храниться идентификаторы URI и текущее состояние поиска в строке URL С этой целью можно, в частности, воспользоваться коллекцией класса Stack
. В качестве более сложной, но интересной задачи попробуйте организовать вывод ссылок в виде дерева.
- Члены пространства имен System.Net
- Универсальные идентификаторы ресурсов
- Основы организации доступа к Интернету
- Обработка сетевых ошибок
- Обработка исключений
- Класс Uri
- Доступ к дополнительной информации, получаемой в ответ по протоколу HTTP
- Практический пример создания программы MiniCrawler
- Применение класса WebClient
- Практический пример
- Пример установочного скрипта
- Пример из практики
- СТРУКТУРА ПРОСТОЙ ПРОГРАММЫ
- ПРИМЕР ПРОСТОЙ ПРОГРАММЫ НА ЯЗЫКЕ СИ
- Примеры получения статистики
- Пример применения метода «пять почему»
- Пример 12-8. Частота встречаемости отдельных слов
- 1.2.5. Пример программы
- Пример 17-10. Блочный комментарий
- 24.7. Использование программы-твикера
- Примеры