1

テーブルからデータを抽出できるように、html ファイルを解析しようとしています。
それで、私はいくつかのグーグルマジックを行い、ここで同様の質問が行われました。

その質問で、彼らは HTML の解析に HTMLP を使用することを提案しました。ユニットをダウンロードして試してみました。

それは機能しますが、何かが足りないと思います。要素から実際のテキストを取得する方法についてはまったくわかりません。

ソースを調べましたが、これについては何も見つかりません。だから私はここに誰かが答えを知っていることを望んでいました.

前もって感謝します。

編集

要求に応じて: 取得しようとしているデータはここ
にあります。このデータを取得し、各行をオブジェクトに変換して保存し、さまざまなプラクティス、資格、人種を比較できるようにします。

4

1 に答える 1

4

あなたのコードの問題は、このqで元に戻すことができますが、次の行にあります:

for i:=0 to doc.body.all.length-1 do

これが実行されると、無効なバリアント操作が発生します。これを調査するために使用したコードは次のとおりです。

procedure GetTable2(FSource : TStrings);
var
  Doc : IHtmlDocument2;
  Body : IHtmlElement;
  All : IHtmlElementCollection;
begin
  Doc := coHTMLDocument.Create as IHTMLDocument2;
  Doc.Write(PSafeArray(FSource.Text));
  Doc.Close;
  Assert(Doc <> Nil);
  Body := Doc.body;
  Assert(Body <> Nil);
  All := Body.All as IHtmlElementCollection;
  Assert(All <> Nil);
  Assert(All.Length <> 0);
end;

これには、ローカルに保存されたレース結果ページのコピーが読み込まれた TStringlist が渡されます。

MS Dom パーサーと対話するために、「遅延バインディング」、つまりバリアントを使用してきました。先ほど引用したコードのように事前バインディングを使用するよりも少し遅い場合は問題ありませんが、ある種のエラーを隠したり隠したりすることができます。

私のコードは、解析された HTML へのアクセスをいくつかの段階に分割し、Assert() を使用して DOM オブジェクトが実際に存在することを確認します。それらはすべて Assert テストに合格しますが、All コレクションの長さがゼロではないという最後の Assert は失敗します。

上記のコードを実行して、Body オブジェクトの OuterHtml プロパティを調べてみてください。'' にいくつかの埋め込み CRLF を追加しただけです。(この回答の元のバージョンはここで停止しました)。

更新:もう少し掘り下げると、問題の原因が明らかになりました。それを確認するには、問題の Web ページをローカルに保存してから、新しい VCL プロジェクトを作成し、そのフォームに TWebBrowser、2 つの TMemo、および TButton を追加してから、次のコードを貼り付けます (明らかに、フォームを調整する必要があります。ページのローカル コピーをロードするために作成します):

procedure GetTable(All : IHtmlElementCollection; Output : TStrings);
var
  el:OleVariant;
  i,tdc,mc:integer;
  tst,v:string;
begin
  v:='';
  mc:=4;
  tdc:=0;
  for i:=0 to all.length -1 do
  begin
    el:= All.item(i, '');
    if el.tagname='TD' then
    begin
      inc(tdc);
      if tdc>mc then
      begin
        Output.Add(v);
        v:='';
        tdc:=1;
      end;
      if v='' then v:=el.InnerText
      else v:=v+'^'+el.InnerText;
    end;
  end;
end;

procedure ProcessDoc(Doc : IHtmlDocument2; Output : TStrings);
var
  Body : IHtmlElement;
  All : IHtmlElementCollection;
  V : OleVariant;
begin
  Assert(Doc <> Nil);
  Body := Doc.Body;
  Assert(Body <> Nil);
  All := Body.All as IHtmlElementCollection;
  Assert(All <> Nil);
  Assert(All.Length <> 0);
  GetTable(All, Output);
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  Memo1.Lines.LoadFromFile('D:\aaad7\html\race.htm');
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  V : OleVariant;
begin
  WebBrowser1.Navigate('about:blank');  //  This line is so that the WebBrowser
    // has a Doc object
  Doc := WebBrowser1.Document as IHTMLDocument2;
  V := VarArrayCreate([0, 0], varVariant);
  V[0] := Memo1.Lines.Text;
  try
    Doc.Write(PSafeArray(TVarData(V).VArray));
  finally
    Doc.Close;
  end;  
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  ProcessDoc(Doc, Memo2.Lines);
end;

Button1 をクリックすると、すぐに問題の原因 (私のように IE11 を使用していると仮定しますが、以前のバージョンで発生する可能性があります)、つまり 7 つの Javascript エラー ポップアップのカスケードが表示されます。[はい] をクリックすると、2 番目のメモがコードのわずかに変更されたバージョンの出力を受け取ることがわかります。

したがって、コードの問題は、GUI を使用せずに IHTMLDocument オブジェクトを作成していたため、スクリプト エラーが発生する方法がなかったことだと思います。COMオブジェクトのMS仕様であるIIRCでは、例外がCOMホストとそのクライアントの間の境界を越えて伝播しないことが要求されているため、GUI以外のDocオブジェクトでは問題が隠されていると思います。そのため、エラーについて知ることはできません。明らかな回避策は、ページを TWebBrowser にロードし、そこから Doc オブジェクトを使用することです。

更新 #2:この回答を最初に書いたときに気付いていなかったのは、IHtmlDocument に JavaScript エラーのポップアップを試行しないように指示して、拒否する代わりにロードすることができるということです。あなたがする必要があるのは置くだけです

Doc.DesignMode := 'On';

たとえば、その .Write メソッドを呼び出して、何かをロードしようとする前に。TWebBrowser の Silent プロパティを True に設定すると、同様のことができます。

ところで、テーブルを解析してデータを取得しようとしている場合は、私の以前の回答をご覧ください。

Delphi: この HTML テーブルを解析するためのヒントはありますか?

于 2014-08-22T15:59:58.230 に答える