使用泛型完成HTML刮板.对或错

本文关键字:刮板 HTML 泛型 | 更新日期: 2023-09-27 18:19:02

我的要求是下载和抓取各种HTML页面,根据我们在该页上寻找的对象类型从页面上的代码提取对象列表。例如,一页可能包含一个嵌入的医生手术列表,另一页可能包含一个主要信任列表等。我必须一个一个地查看页面,最后得到适当对象类型的列表。

我选择这样做的方式是有一个称为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块。

我的问题是

  1. 我不知道如何以一种很好的方式指定每个对象类型的模板,除了HTMLParser<Surgery> parser = new HTMLParser<Surgery>(new URI("...."), Surgery.Template);,这有点笨拙。谁能提出一个更好的使用。net 3.0/4.0的方法?

  2. 我不知道如何以通用的方式我可以采取HTML字符串,采取XSD或XML模板文档,并返回泛型类型的构造对象的通用列表。有人能告诉我怎么做吗?

  3. 最后,我不相信泛型是这个问题的正确解决方案,因为它开始看起来非常复杂。你会同意还是谴责我选择的解决方案,如果不同意,你会怎么做?

使用泛型完成HTML刮板.对或错

我也不相信泛型是正确的解决方案。我使用良好的旧继承实现了与此非常相似的东西,我仍然认为这是适合这项工作的工具。

当你想对不同的类型执行相同的操作时,

泛型很有用。例如,集合就是一个很好的例子,在这里泛型非常方便。

另一方面,当您希望对象继承公共功能,但随后扩展和/或修改该功能时,

继承非常有用。用泛型做这些是很麻烦的。

我的scraper基类看起来像这样:

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抓取器,或者为任何页面、站点或数据类自定义抓取器。

我实际上尝试做类似的事情,但不是使用继承,而是使用scraper回调函数。比如:

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>
}

工作得相当好,并且不必为每个scraper类型创建一个新类。然而,我发现在我的情况下,这太局限了。最后我发现几乎每种类型的scraper都需要一个不同的类,所以我直接使用继承。

我宁愿把重点放在解析器/验证器类上,因为正确设计它们对于将来使用的便利性至关重要。我认为更重要的是机制将如何根据输入决定使用哪个解析器/验证器。

另外,当你被告知你需要解析另一种类型的网站时,比如说Invoice实体,你能在2个简单的步骤中扩展你的机制来处理这样的要求吗?