C++: Обработка “мертвых” ссылок

Источник: wmate

Конечно, никто не спорит, что использование всякого рода Dreamweaver'ов удобно, но как правило ссылки пишутся (читай правятся), что называется, "руками", в "Блокноте" и других подобных редакторах. Но человеку свойственно ошибаться. И, как свидетельствует опыт, ошибается он довольно часто (по крайней мере, это касается моего случая). Причины ошибок могут быть самыми разными - начиная с банальных "очепяток" и заканчивая обыкновенной ленью (ну лень мне иногда через груду окошек лезть, смотреть на дерево каталогов для того, чтобы правильно прописать линк, пишу по памяти, а после приходится все перепроверять и заниматься различными другими "непотребными вещами"). Хорошо, если ссылок на страничке немного. А если это одна из индексных страниц? Здесь нам на помощь может прийти все тот же кремниевый дружок, которого вы наверняка видите каждый день, т.е. компьютер, конечно.

В данном материале я не буду затрагивать случай ссылок на другие серверы (за это я возьмусь, как за нить, в следующий раз) - будем исследовать "на вшивость" только локальные ссылки. Безусловно, все, кто занимается разработкой веб-сайтов, держат у себя на локальном компьютере т.н. "зеркало" - полную копию всех каталогов и файлов. Я считаю, что это очень удобно как с практической точки зрения лентяя (а вам не захочется ждать, пока ваш проект загрузится, а ждать все равно придется, какой бы ни был шустрый коннект, а со своего компьютера все равно гораздо быстрее), так и с точки зрения удобства обновления сайта: изменил все у себя дома, а после "залил" на сервер. Итак, давайте определимся: что нам необходимо?

Нам необходима программа, которую мы можем "натравить" на исследуемый HTML-файл и которая после его анализа выдаст нам отчет в удобной для анализа форме. Считайте меня продвинутым извращенцем, но использовать для таких целей методы визуального проектирования - это слишком. А посему предлагаю использовать старый добрый С++. За форму отчета выберем HTML-файл из-за удобства использования. По сути дела, мы получаем "голый" список ссылок без текста, причем мы можем тут же проверить правильность их работы (это бывает иногда необходимо, если ссылка прописана правильно, а заданного файла или директории не существует или он/она заданы неправильно). Итак, мы начинаем. Необходимо сказать, что программа была скомпилирована в С++ Borland 5.5 - консольном компиляторе. Я считаю, что для таких небольших задач лучшего инструмента не найти. Не лежит у меня душа гонять "огромный" Microsoft'овский Visual C++. А вообще программу в принципе можно писать в любом текстовом редакторе, обозвав тот опус, который получится, любым именем с расширением *.c. После чего "натравливаем" на него компилятор и наслаждаемся:-).

Итак, прописываем включаемые файлы:

#include <stdio.h>
#include <conio.h>
#include <direct.h>

Все, кто пользовался консолью, в курсе, что параметры в программу можно передавать при ее запуске, написав их через пробел после названия программы. В принципе, это справедливо не только для консольных приложений, но там это проявляется наиболее явно (что называется, цветет и пахнет).

Наверное, все писали в свойствах ярлыка для Quake 3Arena загрузку своего конфига при загрузке игрушки. Так вот, сейчас мы сделаем что-то подобное. А именно будем получать при старте программы имя анализируемого файла. Сделаем мы это при помощи параметров, которые передаются в функцию main:

void main (argc,argv)
int argc;
char *argv[];

Как вы, наверное, уже поняли, в argv мы будем иметь текст, который пользователь введет после имени программы в консоли. Будем надеяться, что это имя существующего файла, и далее будем проверять только наличие этого нашего единственного параметра (программа-то пишется для себя, но если кто вздумает ее продать, пусть сам эту проверку и пишет - у нас с вами другая задача:-)).

Для начала опишем переменные:

int i,len1,len2,len3;
char *buf[255],*buf1[255];
char dir[]="dir.txt",webot []="otchet.htm",ready[]="re-ady.txt";
FILE *dir_f,*ready_f,*web;
char *string1,*string2, *string3,*result1,*result2;
char pathbuf[51];

i нам необходима для использования в циклах в качестве счетчика, len1,len2,len3 будем пользоваться для хранения длин строк. Ниже этого задаем имена файлов, в которых будем хранить как промежуточные данные анализа, так и собственно наш отчет. dir[] - сохраняем линки с прямыми (/) слэшами (так как они пишутся в HTML-тегах), ready[] - здесь сохраняем линки с уже исправленными слэшами (т.е. / меняем на - по-моему, хранение этого всего в отдельных файлах - более простой и прозрачный способ работы, чем хранение в динамически выделяемых массивах, и вдобавок позволяет контролировать работу), webot[] - здесь сохраняем отчет. Далее описываем указатели на наши файлы. Я думаю, необходимости в пояснениях, какой указатель за какой файл будет отвечать, нет. После описываются указатели, просто используемые для хранения промежуточных значений. Массив pathbuf будет необходим как место хранения пути к рабочему месту программы.

Итак, получаем путь к месту работы (второй параметр в getcwd задает размер буфера) и производим проверку на наличие входного параметра - имени анализируемого файла:

getcwd(pathbuf,50);
if(strstr(argv[argc-1], "File_analizator.exe"))
{printf("ErroRR");
exit();
};

Функция производит поиск во входящем параметре argv строки File_analizator.exe - так будет называться (для определенности) наше детище. Если она данную строчку находит, выдается сообщение об ошибке, и программа завершает свою работу. Итак, подготовительные мероприятия закончены, теперь приступаем собственно к работе.

Для начала необходимо открыть анализируемый файл:

index_f=fopen(argv[argc-1],"r");
dir_f=fopen(dir,"w");

Заодно открываем файл для хранения найденных ссылок с флагом "w", что означает, что, если данного файла не существует (а его не существует:-)), то он будет создан и открыт на запись. Анализируемый файл (указатель index_f) открывается только на чтение.

Теперь входим в цикл считывания информации из анализируемого файла:

while(string1=fgets(buf,1024, index_f))
{
if(strstr(string1,"<a href="))
	{
	result1=strstr(string1, "<a href=");
	result2 = strstr(re-sult1,">");
	len2=strlen(result1);
	len3=strlen(result2);
	len1=len2-len3;
	for(i=9;i<=len1-2;i++)
		{
		fprintf(dir_f,"%c",re-sult1[i]);
		};
	fprintf(dir_f,"
");
	};
};

Цикл while будет выполняться до тех пор, пока не будет достигнут конец файла. Функция fgets считывает из файла index_f указанное количество символов либо до символа конца строки " ". Далее в теле цикла проверяем наличие в считанной строке тега "<a href=", которым, собственно, и обозначаются ссылки в тексте. Strstr() возвращает указатель на искомую строку, что мы и используем, вычисляя длины возвращаемых строк result1 и result2, а затем записываем уже вычлененную строку со ссылкой в файл dir_f, не забывая добавлять после каждой строки символ ввода :-). Теперь нам нужно заменить прямые слэши (/) на обратные (). Что мы и делаем, предварительно закрыв неиспользуемый теперь и фактически ненужный (можно удалять?:-)) анализируемый файл:

fclose(index_f);
fclose(dir_f);
dir_f=fopen(dir,"r");
ready_f=fopen(ready,"w");

Последней строкой мы создаем новый файл, куда записываем правленые ссылки. Таким образом мы получаем список ссылок, пригодных для использования в поиске на локальном компьютере, т.е. без обращения к веб-серверу. Именно это делается ниже:

while(string1=fgets(buf,2,dir_f))
{
if(strcmp(buf,"/")==0)
{fprintf(ready_f,"\");
}
else
{fprintf(ready_f,"%s",buf);};

};

Входим в цикл while, в котором считываем по одному символу (функция fgets в параметрах цикла). Далее производим сравнение, является ли прочитанный символ символом /, и, если является, производится его замена символом . После чего все остальные символы просто копируются в файл, соответствующий указателю ready_f.

Теперь осталось только сгенерировать файл отчета. В HTML-файл будем записывать все ссылки - и локальные (т.е. ссылающиеся на локальные файлы сайта), и глобальные (ведущие за его пределы). Как уже было сказано, такая форма отчета позволит легче контролировать работу.

fclose(dir_f);
fclose(index_f);
fclose(ready_f);
ready_f=fopen(ready,"r");
web=fopen(webot,"w");

А сначала закрываем неиспользуемые файлы и открываем (создаем файл отчета). Запишем заголовок:

fprintf(web,"<html> <head> <title>Отчет о живых и мертвых линках</title> </head> <body>
Проверяются только локальные линки,web-линки не проверяются<b> ");
strcpy(buf1,"");// Производим первоначальное обнуление buf1

Теперь входим в While, в котором будем считывать по одному символу из файла, который определен через указатель ready_f. В этом цикле нам необходимо выполнить собственно нашу основную задачу - проверить наличие записанных файлов и директорий. Считываемые символы накапливаем в buf1 до того момента, пока программа не встретит символ окончания строки " ". Производим проверку доступности для открытия в условии if(access(buf1,00)==0). Если проверка выполняется, в файле отчета цвет ссылки задается синим (т.е. она будет отображаться цветом по умолчанию), если не выполняется - цвет ссылки задается красным.

fprintf(web,"&lgt;br>Рабочая директория&lgt;br>%s&lgt;br>",path-buf);// Выводим в отчет //рабочую папку
while(fgets(buf,2,ready_f))
{
if(strcmp(buf," ")!=0)
strcat(buf1,buf);
else
{
if(access(buf1,00)==0)
{fprintf(web,"&lgt;a href=%s> %s&lgt;/a>&lgt;br> ",buf1,buf1);}
else
{fprintf(web,"&lgt;a href=%s> &lgt;fontcolor=#FF0000>%s&lgt;/a> &lgt;/font>&lgt;br> ",buf1,buf1);};
strcpy(buf1,"");
};
fclose(ready_f);
fclose(web);
}

Работа с программой выглядит следующим образом. Находим директорию, где лежат файлы, подвергаемые анализу, запускаем консоль и в качестве параметра в нашу программу передаем имя интересующего нас файла. В результате получаем 3 файла: HTML-файл - собственно отчет и 2 файла в TXT-формате со списком ссылок. При желании в текст программы можно добавить следующие строки:

remove(dir);
remove(ready);

Тем самым мы удалим временные файлы. Программу можно модифицировать таким образом, чтобы анализировать сразу много файлов. Для этого необходимо название файла отчета генерировать уникальным образом, т.е. так, чтобы оно не совпадало с именем ни одного из существующих. Делается это внесением следующих изменений:

#include <stdio.h>
…………
char *webot[255],index[]= "index.htm",dir[]="dir.txt",ready[]="ready.txt";
if(strstr(argv[argc-1], "st.exe"))
{printf("ErroRR");
exit();
};
strcpy(buf,"");
strcpy(buf1,"");
strcpy(buf,argv[argc-1]);
result1=strstr(buf,".");
len1=strlen(result1);
len2=strlen(buf);
strncat(buf1,buf,len2-len1);
strcat(buf1,"_otchet.htm");
printf("%s",buf1);
strcpy(webot,buf1);
…………

После последней правки программы мы добиваемся того, что файл отчета работы будет иметь следующий вид: имя_анализируемого_файла_otchet.htm. Таким образом мы сможем довольно простым способом организовать автоматическую обработку целой директории с индексными файлами. Допустим, необходимо обработать 5 файлов. Вручную в консоли прописывать название программы и через пробел - название анализируемого файла (даже при помощи волшебной кнопочки TAB, которая позволяет дополнять имена файлов: написал начальную букву - нажал TAB - получил полное название) довольно утомительно. Здесь на помощь нам может прийти скриптик всего-то из одной строчки, причем в самой программе менять ничего не придется - она все также будет пригодна для анализа отдельных файлов. Как известно, команду shell>dir можно давать с различными параметрами. Их довольно большое количество, но нас интересует dir вот в таком виде: shell>dir *.htm /B. Эта команда выдает список файлов с *.htm-расширением. Теперь ничего не стоит написать .bat-файл, который будет состоять всего из одной строки (открываем "блокнот", пишем в нем, а после сохраняем с расширением .bat):

for /F "tokens=1" %%d in ('dir путь_к_папке*.htm /B') do File_analizator.exe путь_к_ папке\%%d

Как это работает? Запускается цикл. Он будет работать таким образом, что для каждого имени файла в рабочей директории будет выполняться команда shell> File_analizator. exe путь_к_папке_Имя_ файла.htm, что, собственно, нам и необходимо. Работа этого уже пакета программ будет выглядеть так: меняем путь в скрипте к интересующей нас директории, после чего выполняем bat-файл. В результате получаем файлы отчетов. Недостатком является засорение файлами отчетов. Бороться с этой бедой можно изменив место создания файла отчета в тексте программы (надеюсь, объяснять, где, нет необходимости?).

Конечно, описанному методу нахождения "мертвых" ссылок не присуща оригинальность, да и, пожалуй, удобством работы он не отличается. Самым главным его достоинством, по моему мнению, является простота реализации и гибкость. Приведенные здесь тексты программ можно легко адаптировать практически под любую конкретную задачу вплоть до нахождения неправильных линков на картинки, например. Но ведь нами и не ставилась задача написания универсального инструмента, кардинально решающего поставленную проблему. Это всего лишь одна из множества маленьких заготовок, скапливающихся у любого, кто занимается подобными вещами.


Страница сайта http://test.interface.ru
Оригинал находится по адресу http://test.interface.ru/home.asp?artId=1944