HTMLソースからURLのみを取得するには?

解決


YUI  2007-11-17 04:55:03  No: 28459

delphi初心者です。よろしくお願いします。

delphiを用いて、Webプログラムをつくっています。
簡単なWebブラウザなどは作成することができたのですが、

1.googleなどの検索エンジンを用いて、検索を行い、
リストアップされた検索結果のHTMLソースを取得する。
2.取得したHTMLソースからURL部分のみを抜き出し、保持する。
3.保持したそれぞれのURLを子ウィンドに反映させて表示させる。

というようなことを行うプログラムを作成したくて、
いろいろ試したのですが、delphi初心者なものでどうもうまくいきません。
すみませんが教えて頂けないでしょうか?よろしくお願いします。


KHE00221  2007-11-19 17:45:34  No: 28460

簡単に出来ますが、

1,2,3のどのあたりができないのですか?


YUI  2007-11-20 07:30:25  No: 28461

KHE00221様

ご指摘ありがとうございます。そうですよね。どの部分がわかっていないか明確に書かなくてはいけませんよね。申し訳ありません。

1の部分はなんとかできそうなのですが、2と3の部分がどのようにすればいいのか全く検討がつかない状況なのです。。

いろいろ調べてはいるのですが、なかなか参考になるものが見つからなくて、困っている状況です。なにかアドバイスを頂けたら嬉しいのですが、
よろしくお願いします。


さなみ  2007-11-20 08:33:40  No: 28462

正直、初心者の方には少し難しいプログラムだと思いますけど。

抽出したいURLは<a href></a>タグなどでリンクされてるものだけでよいでしょうか?それとも、ソースの中で"http://…"の形式になっている文字列は全部拾う必要がありますか?
あと相対的なURL指定(<a href="./abc/def.html">みたいな形式)のものも抽出する必要がありますか?
その辺でプログラムの書き方が変わってくるのですけど。

>3.保持したそれぞれのURLを子ウィンドに反映させて表示させる。

これも意味がよくわかりません。子ウィンドウにブラウザみたいなもので表示したいのですか?


YUI  2007-11-20 09:10:26  No: 28463

さなみ様

やはりちょっとハードルが高いですか、、
難しいとは思うのですが、なんとかがんばってみたいと思っています。

私が作成したいプログラムは、googleであるワードの検索を行い、その検索結果のURLを取得・保存し、そのURLを子ウインドに反映するということを書いているのですが、、

例えば、googleで「delphi」と検索した場合、
1.Delphi
2.Delphi - Wikipedia
3.フリーのTurbo Delphiで始めるWindowsプログラミング:ITpro
     ・
  (中略)
     ・
10.クジラ式 Delphi 資料

というようにリスト化された検索結果が出ると思いますが、この1〜10
のそれぞれURLを取得・保存して、それぞれを子ウインドのブラウザで表示
できるようなプログラムです。

このプログラムのURL取得の方法はさなみ様が言われた「<a href></a>タグなどでリンクされてるもの」の方法でいけると考えているのですが。。
いろいろ方法があれば、勉強したいと思いますので、アドバイス等ありましたら、よろしくお願いします。


KHE00221  2007-11-21 00:27:58  No: 28464

すべでの <a の中から リンク先のみをどう探すかが問題になると思いますが、

1つの検索結果は

<div class="g">
<h2 class=r>
<a href="リンク先">サイト名</a>
</h2>
<table>
サイトの中身
</table>
</div>

となっているようです

この辺を考慮して作成すれば良いでしょう。


KHE00221  2007-11-21 00:35:38  No: 28465

>それぞれを子ウインドのブラウザで表示できるようなプログラムです。

これはつまり IE を10個起動したような状態  にするという事ですか?

それならば TWebBrowser を貼り付けたフォームを作成し

 WebBrowser1.Navigate('http://www.google.co.jp/'); 等とすれば
 表示する事が可能となります(実際には取得したアドレスを設定)

 ShellExecute( Application.Handle,'','http://www.google.co.jp/',
'','',1);

 として直接ブラウザを起動させる方法もありますが


YUI  2007-11-21 05:37:00  No: 28466

KHE00221様

アドバイスありがとうございます。
そうなんですよね。リンク先のみをどう取得するかが課題なんです。
URLを取得できたとしても、検索結果以外のリンクも取得してしまうと思われるので、検索結果のURLだけを取得するような、いい方法がないか考えているところです。。

それぞれを子ウインドのブラウザで表示できるようなプログラム。
これは、MDIの機能を用いて行いたいと考えています。
KHE00221様が書かれているように、IEを10個起動したようなものですね。
取得・保存したURLをMDIのchildに反映できればと考えているのですが、
この部分もなかなかいい方法が見つからない状態です・・・
またアドバイス等ありましたら、よろしくお願いします。


さなみ  2007-11-21 06:10:13  No: 28467

>YUI様

1と2についてのサンプルです。

正規表現ライブラリを使っていますが、
http://delwiki.info/?%A5%B3%A5%F3%A5%DD%A1%BC%A5%CD%A5%F3%A5%C8%2FTRegExpr
の「TRegExpr クラスを使う」を参考にしてください。

環境 : Del6 Pro

<準備>

http://www.regexpstudio.com/Downloads/regexpr.zip
をダウンロード・解凍し、"Sorce"フォルダの中にある"RegExpr.pas"をプロジェクトフォルダの中にコピーしてください。


uses節に、「RegExpr」と「HTTPApp」を追加してください。
>Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
>Dialogs,RegExpr,HTTPApp;


"FastNet"タブにあるTNMHTTPコンポーネントをフォームの上に貼り付けてください。名前は"NMHTTP1"のままでよいです。

<サンプル>
//検索結果のURLリストをダイアログで表示します
procedure TForm1.Button1Click(Sender: TObject);
var
  KensakuWord:string;
  URL:string;
  Source:string;
  r:TRegExpr;
  Kekka:string;
begin

//Googleで検索する単語を指定
  KensakuWord:='プログラミング';

//ソースを取得するURL
  URL:='http://www.google.co.jp/search?hl=ja&q='+HTTPEncode(KensakuWord);

//NTHTTPコンポーネントでソースを取得
  NMHTTP1.Get(URL);
  Source:=NMHTTP1.Body;

//TRegExprクラスを使ってURLを抽出
  Kekka:='';
  r := TRegExpr.Create;
  try
    r.Expression :='<h2 class=r><a href="([^"]+)"';
    if r.Exec(Source) then
    begin
      repeat
        Kekka:=Kekka + r.Match[1] + #13#10;
      until not r.ExecNext;
    end;
  finally
    r.Free;
  end;

//結果を表示
  ShowMessage(Kekka);
end;


KHE00221  2007-11-21 07:39:29  No: 28468

UNIT1 を MDIForm UNIT2 を MDIChild にして下さい。

UNIT2 と UNIT99 を プロジェクトから削除して下さい。

ディスク上に保存した google の検索結果の HTML を対象にしています

--------------------------------------------------------

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StrUtils, StdCtrls;

type
  TForm1 = class(TForm)
    OpenDialog1: TOpenDialog;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses Unit2,Unit99;

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
    I,J1,J2,J3,J4,Index : Integer;
    StringList : TStringList;
    S : String;
    F0 : Boolean;
begin
    if OpenDialog1.Execute = True then
    begin
      StringList := TStringList.Create;
      StringList.LoadFromFile(OpenDialog1.FileName);
      for I:=0 to StringList.Count -1 do
      begin
        Index := 1;
        S := StringList[I];
        F0 := False;
        while F0 = False do
        begin
          F0 := True;
          J1 := PosEx('<h2 class=r>',S,Index);
          if J1 <> 0 then
          begin
            J2 := PosEX('<a href="',S,J1+12);
            if J2 <> 0 then
            begin
              J3 := PosEx('" class=l',S,J2+9);
              if J3 <> 0 then
              begin
                Form2 := TForm2.Create(Self);
                Form2.WebBrowser1.Navigate(Copy(S,J2+9,J3-J2-9));
                J4 := PosEx('</h2>',S,J3+9);
                if J4 <> 0 then
                begin
                  Index := J4;
                  F0 := False;
                end;
              end;
            end;
          end;

        end;

      end;
      StringList.Free;
    end;

end;

end.

----------------------------------------------------------

unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, OleCtrls, SHDocVw;

type
  TForm2 = class(TForm)
    WebBrowser1: TWebBrowser;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormDestroy(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

implementation

{$R *.dfm}

uses
   Unit99;

procedure TForm2.FormCreate(Sender: TObject);
begin
    FormList.Add(Pointer(Self));
    Exit;
end;

procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
    Release;
end;

procedure TForm2.FormDestroy(Sender: TObject);
var
    I : Integer;
begin
    I := FormList.IndexOf(Pointer(Self));
    if I <> -1 then
    begin
      FormList.Delete(I);
    end;
end;

end.

----------------------------------------------------------------

unit Unit99;

interface

uses
  Classes,Unit1,Unit2;
var
  Form2 : TForm2;
  FormList : TList;

implementation

initialization
   FormList := TList.Create;
finalization
   FormList.Free;
end.


YUI  2007-11-22 05:42:35  No: 28469

さなみ様

アドバイスありがとうございます。返事が遅くなり申し訳ありません。
さなみ様にアドバイスして頂いた方法で、プログラムを作成しようとしたのですが、私のdelphiには「FastNet」のタブがなく、googleでいろいろ調べたのですが、このコンポーネントをどうインストールしたらいいのかわからない状態です。。。
環境はdelphi7のproなんですが、7には「FastNet」はないのでしょうか??
質問ばかりですみません。


YUI  2007-11-22 06:00:56  No: 28470

KHE00221様

アドバイスありがとうございます。非常に参考になるプログラムなので、頂いたソースでプログラムを1度作成してみようと試みたのですが、やり方がおかしいのか、どうもうまくいきません。。。

頂いたプログラムをMDIアプリケーションとして、作っていけばいいと思っていたのですが、、
前回のコメントで
>UNIT1 を MDIForm UNIT2 を MDIChild にして下さい。
この部分の意味は理解できるのですが、、
unit1はMAIN、unit2はCHILDWINとして扱うという意味ですよね??

>UNIT2 と UNIT99 を プロジェクトから削除して下さい。
この部分はどういう意味なのでしょうか??

質問ばかりで本当に申し訳ありませんが、アドバイスお願い致します。


にしの  2007-11-22 06:11:48  No: 28471

Yahooであれば、Yahoo検索APIなどを使えばXML形式で取得できますよ。
http://developer.yahoo.co.jp/

GoogleだとGoogle Web APIsです。
名称が変わっているかもしれませんが。
http://code.google.com/intl/ja/apis/


KHE00221  2007-11-22 09:42:15  No: 28472

>UNIT1 を MDIForm UNIT2 を MDIChild にして下さい。
この部分の意味は理解できるのですが、、
unit1はMAIN、unit2はCHILDWINとして扱うという意味ですよね??

FormStyle を Unit1 は fsMDIForm Unit2 は fsMDIChild にして下さい

>UNIT2 と UNIT99 を プロジェクトから削除して下さい。
この部分はどういう意味なのでしょうか??

質問ばかりで本当に申し訳ありませんが、アドバイスお願い致します

メニューの プロジェクト -> プロジェクトの削除 を実行すると
ユニットの一覧が表示されますので、Unit2 と Unit99 を選択して OK
を押してくださいそうすると  プロジェクト -> ソース表示 で表示されるソースが

uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1},
  Unit2 in 'Unit2.pas' {Form2},
  Unit99 in 'Unit99.pas';

{$R *.res}

begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.CreateForm(TForm2, Form2);
  Application.Run;
end.

から

uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1};

{$R *.res}

begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

変更されます。

削除しないと正常に動作しません


さなみ  2007-11-22 09:43:00  No: 28473

>YUI様
では、NetFastの代わりにIndyを使いましょう。
Del7にも入っていると思います。

上の書き込みの<準備>のTNMHTTPコンポーネントの代わりに「Indy Clients」タブにあるIdHTTPコンポーネントをフォームに貼り付けてください。
名前は「IdHTTP1」のままで良いです。
その後、IdHTTP1のRequestプロパティのUserAgentプロパティを
Mozilla/3.0 (compatible; Indy Library)
↓から
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)
に書き換えておいてください。

上の書き込みの<サンプル>を以下のように修正してください。

---修正前---
//NTHTTPコンポーネントでソースを取得
  NMHTTP1.Get(URL);
  Source:=NMHTTP1.Body;

---修正後---
//IdHTTPコンポーネントでソースを取得
  Source:=IdHTTP1.Get(URL);


YUI  2007-11-23 18:44:27  No: 28474

にしの様

アドバイスありがとうございます。API、とても勉強になりました。いろいろ勉強していきたいと思っているので、またアドバイス等ありましたら、よろしくお願いします。


YUI  2007-11-23 18:45:22  No: 28475

さなみ様

アドバイスありがとうございます。ご指摘頂いた方法で、URLを取得することができました。
何度もアドバイスしていただき、本当にありがとうございます。また質問することがあるかもしれませんが、その時はよろしくお願いします。


YUI  2007-11-23 18:46:09  No: 28476

KHE00221様

何度も親切にありがとうございます。頂いたプログラムを完成することができました。非常に参考になるプログラムでした。本当にありがとうございます。
これから保存したものではなく、ブラウザから直接操作できるようにしていきたいと思っています。また質問等することがあるかもしれませんが、その時はアドバイスよろしくお願いします。


KHE00221  2007-11-24 22:26:51  No: 28477

自分なりに作ってみました

http://khe00221.image.coocan.jp/index.php?FrontPage%2FApplication%2FGoogle%B8%A1%BA%F7%B7%AF

ソース付きでダウンロード可能です

BDS2006


迷惑投稿には、もう一工夫必要  2008-03-22 17:43:19  No: 28480

迷惑投稿防止対策で半角文字だけの投稿は出来ないはずなのに...ナゼ?と思って内容をヨク見てみたら、
これ↓があるからチェックをすり抜けたのかな...

>citt鐃ス
>societ鐃ス


スパム対策その一  2008-03-23 04:03:14  No: 28482

最近この手のスパムが多い。

phpだったら...
strlen と mb_strlen の合わせ技なんかの組み合わせではねたり
更にリンク(http://)の数を制限するとか..にするけど

ここはperlみたいだから何か似たような
手を打たないと最近は半角文字のみでは多分無理と思う・・・


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加