1

私の要件は、さまざまな HTML ページをダウンロードしてスクレイピングし、そのページで探しているオブジェクトの種類に応じて、ページ上のコードからオブジェクトのリストを抽出することです。たとえば、あるページには医師の手術の埋め込みリストが含まれ、別のページには主要な信頼のリストが含まれる場合があります。ページを 1 つずつ表示し、最終的に適切なオブジェクト タイプのリストを表示する必要があります。

これを行うために私が選択した方法は、ジェネリッククラスを呼び出すことですHTMLParser<T> where T : IEntity, new()

IEntityは、スクレイピングできるすべてのオブジェクト タイプが実装するインターフェイスですが、インターフェイス メンバーがどうなるかはまだわかりません。

だからあなたは効果的に言うことができるでしょう

HTMLParser<Surgery> parser = new HTMLParser<Surgery>(URL, XSD SCHEMA DOC);
IList<Surgery> results = parser.Parse();

Parse()URL からダウンロードされた HTML 文字列に、提供された XSD ドキュメントに準拠するブロックが含まれていることを検証し、このテンプレートを何らかの形で使用List<Surgery>して、HTML 文字列の XML ブロックに対応する Surgery オブジェクトを抽出します。

私が抱えている問題は

  1. 各オブジェクト タイプのテンプレートを適切な方法で指定する方法がわかりません。それ以外HTMLParser<Surgery> parser = new HTMLParser<Surgery>(new URI("...."), Surgery.Template);は、少し不格好です。.NET 3.0/4.0 を使用してより良い方法を提案できる人はいますか?

  2. ジェネリックな方法で、HTML 文字列を取得し、XSD または XML テンプレート ドキュメントを取得して、ジェネリック タイプの構築されたオブジェクトのジェネリック リストを返す方法がわかりません。誰でもこれを行う方法を提案できますか?

  3. 最後に、非常に複雑に見え始めているため、ジェネリックがこの問題の正しい解決策であるとは確信していません。ここでの私の解決策の選択に同意しますか、それとも非難しますか? そうでない場合、代わりに何をしますか?

4

2 に答える 2

2

ジェネリックが正しい解決策であるとは確信していません。古き良き継承を使用して、これと非常によく似たものを実装しましたが、それは今でもこの仕事に適したツールだと思います。

ジェネリックは、異なる型に対して同じ操作を実行する場合に便利です。たとえばコレクションは、ジェネリックが非常に便利な例です。

一方、継承は、オブジェクトに共通の機能を継承させたいが、その機能を拡張および/または変更したい場合に役立ちます。ジェネリックでそれを行うのは面倒です。

私のスクレーパー基本クラスは次のようになります。

public class ScraperBase
{
    // Common methods for making web requests, etc.

    // When you want to download and scrape a page, you call this:
    public List<string> DownloadAndScrape(string url)
    {
        // make request and download page.
        // Then call Scrape ...
        return Scrape(pageText);
    }

    // And an abstract Scrape method that returns a List<string>
    // Inheritors implement this method.
    public abstract List<string> Scrape(string pageText);
}

ロギング、エラー報告などのために他にもいくつかありますが、それが要点です。

ここで、Wordpress ブログ スクレーパーがあるとします。

public class WordpressBlogScraper : ScraperBase
{
    // just implement the Scrape method
    public override List<string> Scrape(string pageText)
    {
        // do Wordpress-specific parsing and return data.
    }
}

また、Blogspot スクレーパー、または任意のページ、サイト、またはデータ クラスのカスタム スクレーパーを作成するために同じことを行うことができます。

実際に似たようなことをしようとしましたが、継承を使用するのではなく、スクレイパー コールバック関数を使用しました。何かのようなもの:

public delegate List<string> PageScraperDelegate(string pageText);

public class PageScraper
{
    public List<string> DownloadAndScrape(string url, PageScraperDelegate callback)
    {
        // download data to pageText;
        return callback(pageText);
    }
}

次に、次のように記述できます。

var myScraper = new PageScraper();
myScraper.DownloadAndScrape("http://example.com/index.html", ScrapeExample);

private List<string> ScrapeExample(string pageText)
{
    // do the scraping here and return a List<string>
}

これはかなりうまく機能し、スクレイパーの種類ごとに新しいクラスを作成する必要がなくなります。しかし、私の状況ではそれはあまりにも限定的であることがわかりました。ほぼすべてのタイプのスクレーパーに異なるクラスが必要になったので、先に進んで継承を使用しました。

于 2011-12-30T15:53:40.060 に答える
1

パーサー/ベリファイア クラスを適切に設計することは、将来の使いやすさにとって非常に重要であるため、私はむしろあなたのパーサー/ベリファイア クラスに焦点を当てたいと思います。入力に基づいてどのパーサー/ベリファイアを使用するかをメカニズムがどのように決定するかがより重要だと思います。

また、たとえばInvoiceエンティティなど、さらに別のタイプの Web サイトを解析する必要があると言われた場合はどうなりますか? そのような要件を処理するために、2 つの簡単な手順でメカニズムを拡張できますか?

于 2011-12-30T16:20:35.960 に答える