HTMLから、情報の抜き出し。

解決


のど飴  2009-09-07 05:55:28  No: 35587

<input type="text" name="Data" value="00000" />
から、type,name,valueの値を抜き出したいんですが・・・、Delphi先生は正規表現が苦手みたいですから、四苦八苦しています。
ような、text,Data,00000を抜き出したい。

文字をキーで分割するSplit関数は、昔自作したので、="で分割させてはいるんですが、どうもスマートではないような気が。^^;

input type
="  ←ここでまず、分解。
text" name  ←  これをさらに" で分割させる、とtextだけにしている。
="
Data" value  ←  これをさらに" で分割させる、とDataだけにしている。
="
"00000" /> ←  これをさらに" で分割させる、と00000だけにしている。

にしてるんだけど、最後が"00000">だったりすると、まぁ、Pos検索して、削除する必要があるんだけど。

コンポーネントを入れてもいいけど、delphi6っていう制限はあります。
みなさん、お知恵をお貸しください。


igy  2009-09-07 07:15:41  No: 35588

試していませんが、
タグ内の値を取り出すには
https://www.petitmonte.com/bbs/answers?question_id=2013
は、いかがですか?


のど飴  2009-09-07 08:44:35  No: 35589

unit追加で、ここまでは出来たんですが・・・、

type="text"
name="ID"
value="00000"

NextToken(var TagName: String; Values: TStrings): THtmlParseType;
こいつの戻り値が分かりません。

THtmlParseType=(hptTag, hptPlain, hptEof);
unit内のこれなんですが・・・。

じっくりと見てみようかと思います。

こいつを改造しちゃおうかなー?と思ったのですが、ポイントが分からなくって。
http://delfusa.main.jp/delfusafloor/archive/www.nifty.ne.jp_forum_fdelphi/samples/00953.html

ありがとうございます。


通りすがり  2009-09-07 10:43:53  No: 35590

正規表現は、RegExpr  でいかが?

これを使えば一般的な、split(SplitRegExpr)も楽に使えます。


のど飴  2009-09-07 15:56:38  No: 35591

RegExpr  は、昔入れていたし、今も入れてみたんですが、抜き出しに関してはわかなくって。
単に、よけいなコンポーネントを入れたくなかった・使いたくなかった、という理由もあります。

TAWKStr.Match 文字列のパターンマッチ, 
TAWKStr.Sub 文字列の置換 (Substitude) 
TAWKStr.GSub 文字列の置換 (Global Substitute) 
TAWKStr.Split 文字列の分割 

余分な部分を、正規表現させて、空に置換させるって感じでしょうか?


通りすがり  2009-09-07 17:53:01  No: 35592

TRegExprは少し癖がありますが、取敢えず以下のように・・・
(内容によってはいろいろと手を加える必要が出てきますが)

procedure TForm1.Button1Click(Sender: TObject);
var
  s1,s2:string;
  i:integer;
  slist1:Tstringlist;
begin
  slist1:=TStringList.Create;
  Memo1.Clear;

  s1 := '<a href="http://www.google.co.jp">';
  s2 := '<a href="|">';

  SplitRegExpr(s2,s1,slist1);
  if slist1.Count>=1 then
     for i:=0 to slist1.Count-1 do begin
         Memo1.Lines.Add(slist1.Strings[i]);
     end;
  slist1.free;
end;


通りすがり  2009-09-07 17:55:14  No: 35593

尚、TRegExprはインストールしなくとも、Usesに加えるだけで
一応動きます。
(私も標準以外のコンポーネントは出来るだけインストールしない方です)


monaa  2009-09-07 22:31:40  No: 35594

のど飴さんは最初に正規表現が使いたくても使えない様なこと書いてますよね?
目的を達成するための第一手段が正規表現であれば外部コンポーネントを使うしかありません。非GUIですので基本インストール不要です。
途中から、Delphiコーディングの方向に向かってるようですが、
こちらですと、書き方次第では正規表現より数倍早い実行速度が期待できます。ですが、早いコードってのは如何せん難読コードになりがちなので頑張そこは頑張るしかないとおもいます。
目的が動作達成であり、かつ正規表現に精通していて、igyさんの示したリンク先のコードが読めないのであれば選択肢は限られてくると思います。


おも  2009-09-08 04:38:55  No: 35595

>> <input type="text" name="Data" value="00000" />

のようなHtmlはどうやって取得されていますか?

手作業でブラウザのソース表示を行って、それをMemo1へコピー&ペーストして処理という感じならば力にはなれませんが、プログラムから直接的にHtmlを取得しているのであれば、その方法によってはスマートな方法があります。


のど飴  2009-09-08 06:04:09  No: 35596

>正規表現が使いたくても使えない
とは、書いていないつもりです。
>Delphi先生は正規表現が苦手  とは書きましたが。

値が習得出来ればいいので、正規表現だろうが、コンポーネントだろうが、ちょっと大げさですが、htmlをXMLさせて〜ってのも、正直アリです。
XML化は、汎用的で魅力的に思えたので、一応、探しましたが、私は見つけられなくって。
XMLの読み取りのコンポーネントは見つかったのですが。
HTMLの取得方法は、EmbeddedWB1からです。

それと、やはり、私はクラスはまだしも、ポインタに関して決定的に知識が足りないようです。
一応、一番最初に書いた私の方法で、曲がりなりにも、ソフトは完成しているので、あとは完成度を少しでも上げたいと思った次第です。

もうしばらくお知恵を拝借したく、解決は後日にしたいと思います。
大変申し訳ありません。


おも  2009-09-08 14:26:56  No: 35597

TEmbeddedWBはコンポーネントを今回始めて使ってみました。インストールで少し手間取ったのですが、たぶん、特別な設定はしていないと思います。Delphi Personal 6 + Win2000/XPで動作は確認しました。

TFormにTEmbeddedWB、TMemo、TButtonをそれぞれ一つずつ置いてイベントを割り当ててください。あとは、Unit1.pasへそのままコピーでいいと思います。

立ち上げると、このページが表示されます。ボタンを押すと、メモにこのページの投稿欄付近のtype,name,valueの値の情報が記録されます。また、認証キーと確認入力部分に関する情報がメッセージ表示されます。認証キー(確認入力用)に何らかの入力を行って、ボタンを押すとその入力も反映されます。

これを応用すればのど飴さんのご希望に近い形になるのではないかと思います。

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, OleCtrls, SHDocVw_EWB, EwbCore, EmbeddedWB;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    EmbeddedWB1: TEmbeddedWB;
    Button1: TButton;
    procedure FormShow(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormShow(Sender: TObject);
begin
    //ここのページを表示しています。
    EmbeddedWB1.Go('https://www.petitmonte.com/bbs/answers?question_id=6516');
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  i,j,ItemNo,iEnd:Integer;
  s,sName:String;
  GetPlace:Boolean;
begin
    iEnd:=0;
    GetPlace:=False;
    Memo1.Clear;
    Memo1.ScrollBars:=ssVertical;

    //Htmlを1つずつの要素(Item)毎にスキャンしていきます。
    for i:=0 to EmbeddedWB1.OleObject.document.all.Length-1 do begin

        //Itemの名前をチェックしていきますが、
        //名前がついていないItemの場合の例外処理を入れます
        try
            s:=EmbeddedWB1.OleObject.document.all.Item(i).Name;
        except
        end;

        //このページの投稿欄のメールアドレスのItemのNameが'EMAIL'です。
        if (not GetPlace) and (s='EMAIL') then begin
            GetPlace:=True;
            ItemNo:=i+1;
            iEnd:=i+20;
        end;

        //Memo1への表示は投稿欄付近のみに制限します。
        if not GetPlace then Continue;
        if i=iEnd then Break;

        //HtmlをItem番号とともにMemo1に表示します。
        s:=EmbeddedWB1.OleObject.document.all.Item(i).outerHtml;
        Memo1.Lines.Add(IntToStr(i)+' '+s);

        //続けて、そのItemでのTag/Type/Name/ValueをItem番号とともにMemo1に表示します
        //該当情報情報がない場合は表示しません。
        for j:=1 to 4 do begin
            try
                case j of
                    //ここでは、そのItemに指定した情報タイプが存在しない場合
                    //エラーとなるので例外処理が必要です
                    1:s:=EmbeddedWB1.OleObject.document.all.Item(i).tagName;
                    2:s:=EmbeddedWB1.OleObject.document.all.Item(i).type;
                    3:s:=EmbeddedWB1.OleObject.document.all.Item(i).Name;
                    4:s:=EmbeddedWB1.OleObject.document.all.Item(i).Value;
                end;

                case j of
                    1:sName:='Tag';
                    2:sName:='Type';
                    3:sName:='Name';
                    4:sName:='Value';
                end;
                Memo1.Lines.Add(IntToStr(i)+' '+sName+' = '+s);
            except
            end;
        end;
    end;

    //ここまでの部分はキーワード等により取得すべき情報の位置を調べて
    //情報を取得するような方法で処理しました。

    //予め欲しい情報のItemのNameがわかっている場合には、直接的に
    //その情報を取りにいくことが可能です。
    //ここでは、認証キーと認証キー(確認入力用)の情報を取得します。
    //なお、同一ページ内に同じNameのItemがある場合にはもう一工夫必要であったり、
    //また、この方式では指定できないような文字を含んだNameのItemもあります。

    for i:=0 to 1 do begin
        case i of
            //Nameが'NINSYOU_MOTO'と'NINSYOU'であることは予め調べておきます。
            0:ItemNo:=EmbeddedWB1.OleObject.document.all.NINSYOU_MOTO.sourceIndex;
            1:ItemNo:=EmbeddedWB1.OleObject.document.all.NINSYOU.sourceIndex;
        end;

        ShowMessage('Tag = '+EmbeddedWB1.OleObject.document.all.Item(ItemNo).tagName);
        ShowMessage('type = '+EmbeddedWB1.OleObject.document.all.Item(ItemNo).type);
        ShowMessage('Name = '+EmbeddedWB1.OleObject.document.all.Item(ItemNo).Name);
        ShowMessage('Value = '+EmbeddedWB1.OleObject.document.all.Item(ItemNo).Value);
    end;
end;

end.


おも  2009-09-08 14:31:55  No: 35598

下記の部分の ' ItemNo:=i+1 'は不要ですね。失礼しました。
>>
        //このページの投稿欄のメールアドレスのItemのNameが'EMAIL'です。
        if (not GetPlace) and (s='EMAIL') then begin
            GetPlace:=True;
            ItemNo:=i+1;
            iEnd:=i+20;
        end;
>>


のど飴  2009-09-11 05:11:13  No: 35599

おもさん、丁寧な回答ありがとうございます。
いずれ使ってみようかと思います。
他の方も大変参考になりました。

・・・、結果。
教えていただいたアドレスや他のを参考にして、簡易なhtml→XMLを作っちゃいました。
ポインタを勉強して、これほど便利とは思いませんでした。
皆さんありがとうございます。


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

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






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