Bob Swart - Интернет решения от доктора Боба. Страница 14

Заметим, что программа игнорирует все "file://", "ftp://", "mailto:", "news:" and ".exe?" значения если они встретятся внутри "HREF" части. Конечно, вы свободны в расширить HTMLINKS для проверки и этих случаев, можно также реализовать проверку и внешних ссылок. Для информации я написал и детектор внешних мертвых ссылок в статье для The Delphi Magazine, подробности можно найти на моем web сайте. Для анализа мертвых локальных ссылок код следующий:

  {$APPTYPE CONSOLE}

  {$I-,H+}

  uses

    SysUtils;

  var

    Path: String;

    procedure CheckHTML(const Path: String);

    var

      SRec: TSearchRec;

      Str: String;

      f: Text;

    begin

      if FindFirst('*.htm', faArchive, SRec) = 0 then

      repeat

        Assign(f,SRec.Name);

        Reset(f);

        if IOResult = 0 then { no error }

        while not eof(f) do

        begin

          readln(f,Str);

          while (Pos('<A HREF="',Str)  0) or

                (Pos('FRAME SRC="',Str)  0) do

          begin

            if Pos('<A HREF="',Str)  0 then

              Delete(Str,1,Pos('HREF="',Str)+8-3)

            else

              Delete(Str,1,Pos('FRAME SRC="',Str)+10);

            if (Pos('#',Str) <> 1) and

               (Pos('http://',Str) <> 1) and

               (Pos('mailto:',Str) <> 1) and

               (Pos('news:',Str) <> 1) and

               (Pos('ftp://',Str) <> 1) and

               (Pos('.exe?',Str) = 0) then { skip external links & exe }

            begin

              if Pos('file:///',Str) = 1 then Delete(Str,1,8);

              if (Pos('#',Str)  0) and

                 (Pos('#',Str) < Pos('"',Str)) then Str[Pos('#',Str)] := '"';

              if not FileExists(Copy(Str,1,Pos('"',Str)-1)) then

                writeln(Path,'\',SRec.Name,': [',Copy(Str,1,Pos('"',Str)-1),']')

            end

          end

        end;

        Close(f);

        if IOResult <> 0 then { skip }

      until FindNext(SRec) <> 0;

      FindClose(SRec);

      // check sub-directories recursively

      if FindFirst('*.*', faDirectory, SRec) = 0 then

      repeat

        if ((SRec.Attr AND faDirectory) = faDirectory) and

            (SRec.Name[1] <> '.') then

        begin

          ChDir(SRec.Name);

          CheckHTML(Path+'\'+SRec.Name);

          ChDir('..')

        end

      until FindNext(SRec) <> 0;

      FindClose(SRec)

    end {CheckHTML};

  begin

    writeln('HTMLinks 4.0 (c) 1997-2000 by Bob Swart (aka Dr.Bob - www.drbob42.com)');

    writeln;

    FileMode := $40;

    GetDir(0,Path);

    CheckHTML(Path)

  end.

3.4.4. FTP Upload/Download

Иногда вам просто нужно загружать файлы из Интернета. В терминах Интернета, это означает, что вам нужно использовать FTP клиента. И если вы не желаете, подобно мне использовать настоящего FTP клиента, то просто напишите, как и я своего собственного клиента…

3.4.4.1. FTP

Как я сказал во введении, FTP означает File Transfer Protocol, который описан в which RFC 959. Модель связи FTP может быть реализована с помощью сокетов, но это более низкоуровневое решение и если вы посмотрите спецификацию, то поймети, что написание программы FTP клиента с нуля не такая уж простая задача. С другой стороны, мы можем использовать NetManage TFTP компонент из Delphi 2.01 (и выше) и C++Builder. Я пробовал использовать этот компонент несколько раз, и нашел его просто глюкавым, особенно для файлов свыше 10 Kb. Я могу понять, почему Microsoft (первый разработчик Internet Solutions Pack) не захотела использовать его и продала затем NetManage, которая тоже не справилась с ним и продала далее фирме NetMasters. Проблема в том, что Internet Solutions Pack – хотя и бесплатный – основан на наборе с ограничениями ActiveX, и каждая компания которая использует его также имеет более лучшее решение (обычно не бесплатно). Поддержка и документация всегда отвратительная…

Так что же, назад к низкоуровневому программированию? Ни в коем случае. Как всегда на помощь приходит Microsoft

3.4.4.2. WinInet

Некоторое время назад, Microsoft выпустила WinInet, который ни что иное, как промежуточный слой между высоким и нижним уровнем программирования Internet API специально для Win32 программистов. WinInet Является интерфейсом высокого уровня для протоколов нижнего уровня, таких как HTTP и FTP. Использование его действительно просто, и хорошо, что модуль WinInet.PAS с API определениями уже включен в Delphi 2.x и выше!

Имеется также большой документ, описывающий все детали WinInet API, который может быть найден на сайте Microsoft (но его местонахождение постоянно меняется, так что нужно использовать систему поиска, для загрузки последней версии документа).

От переводчика: можно взять на моем сайте со страницы http://nps.vnet.ee/internet.html

3.4.4.3. DrBob FTP

WinInet использует не что, что они назвали Интернет хендл "internet handle" (очень похоже на windows handles), и все api функции или нуждаются или возвращают Интернет хендл. Например, что бы открыть новую WinInet сессию, нам нужно вызвать функцию InternetOpen, которая вернет Интернет хендл, который мы должны использовать до конца сессии (и передавать другим API функциям). Для освобождения хендла, мы всегда должны вызывать функцию InternetCloseHandle (после получения хендла мы можем его использовать, но мы обязаны написать блок try-finally, где должны освободить хендл в разделе finally).

Для открытия удаленного файла (или URL) в Интернете, мы должны вызвать функцию InternetOpenURL, которая опять вернет нам хендл. Теперь, для загрузки удаленного файла (URL) на нашу локальную машину, нам осталось сделать только некоторое количество вызовов функции InternetReadFile, очень похожей на функцию BlockRead, которая копирует данные из удаленного файла в буфер данных. Мы можем использовать BlockWrite для записи из буфера в локальный файл, и все это с помощью всего лишь трех WinInet функций (четыре, если считать функцию InternetCloseHandle), мы можем написать простую, но очень быструю FTP программу следующим образом:

program DrBobFTP;

  {$APPTYPE CONSOLE}

  {$I+}

  uses

    Windows, WinInet;

    procedure CopyURL(const URL, OutputFile: String);

    const

      BufferSize = 1024;

    var

      hSession, hURL: HInternet;

      Buffer: Array[0..Pred(BufferSize)] of Byte;

      BufferLength: DWORD;

      f: File;

    begin

      hSession := InternetOpen('DrBob',INTERNET_OPEN_TYPE_PRECONFIG,nil,nil,0);

      try

        hURL := InternetOpenURL(hSession, PChar(URL), nil,0,0,0);

        try

          Assign(f, OutputFile);

          Rewrite(f,1);

          repeat

            InternetReadFile(hURL, @Buffer, BufferSize, BufferLength);

            write('.');

            BlockWrite(f, Buffer, BufferLength)

          until BufferLength = 0;

          Close(f);

          writeln('OK') { if we get here, we succeeded }

        finally

          InternetCloseHandle(hURL)

        end

      finally

        InternetCloseHandle(hSession)

      end

    end;

  begin

    if ParamCount <2 >then

    begin

      writeln('Usage: DrBobFTP URL Filename');

      writeln('Example: DrBobFTP http://www.drbob42.com/ftp/headconv.zip hc.zip')

    end

    else

      CopyURL(ParamStr(1), ParamStr(2))

  end.

Конечно, для выполнения данной программы мы также обязаны иметь WinInet.DLL, которая также может быть найдена на Microsoft web сайте.

3.4.4.4.Улучшения?

Если вы читали документацию по WinInet, вы заметили что, там есть функция FindFile, так что вы можете сделать обзор удаленных файлов. И базируясь на этой информации, вы можете написать своего web робота, который может загрузить часть a web сайта (например, те файлы, которые изменились после последнего посещения данного сайта). Все автоматически и без GUI (зато быстро). Для информации, Я работал над подобным сортом инструментария, названного мной RobotBob, который наложил свой глаз на Борландовский web сайт, помогая мне отслеживать новости и события по Борландовским средствам разработки…