【问题标题】:C# Scrape data from wiki page (screen-scraping)C# 从 wiki 页面抓取数据(屏幕抓取)
【发布时间】:2011-09-19 11:51:02
【问题描述】:

我想抓取一个 Wiki 页面。具体来说,this one.

我的应用程序将允许用户输入车辆的注册号(例如,SBS8988Z),它会显示相关信息(在页面上)。

例如,如果用户在我的应用程序的文本字段中输入 SBS8988Z,它应该在该 wiki 页面上查找该行

SBS8988Z (SLBP 192/194*) - F&N NutriSoy Fresh Milk: Singapore's No. 1 Soya Milk! (2nd Gen)

并返回 SBS8988Z (SLBP 192/194*) - F&N NutriSoy 鲜奶:新加坡排名第一的豆浆! (第二代)。

到目前为止,我的代码是(从各个网站复制和编辑的)...

WebClient getdeployment = new WebClient();
string url = "http://sgwiki.com/wiki/Scania_K230UB_(Batch_1_Euro_V)";

getdeployment.Headers["User-Agent"] = "NextBusApp/GetBusData UserAgent";
string sgwikiresult = getdeployment.DownloadString(url); // <<< EXCEPTION
MessageBox.Show(sgwikiresult); //for debugging only!

HtmlAgilityPack.HtmlDocument sgwikihtml = new HtmlAgilityPack.HtmlDocument();
sgwikihtml.Load(new StreamReader(sgwikiresult));
HtmlNode root = sgwikihtml.DocumentNode;

List<string> anchorTags = new List<string>();   

foreach(HtmlNode deployment in root.SelectNodes("SBS8988Z"))
{
    string att = deployment.OuterHtml;
    anchorTags.Add(att);
}

但是,我收到了一个 ArgumentException 未处理 - 路径中有非法字符。

代码有什么问题?有没有更简单的方法来做到这一点?我正在使用 HtmlAgilityPack,但如果有更好的解决方案,我很乐意遵守。

【问题讨论】:

标签: c# screen-scraping screen html-agility-pack


【解决方案1】:

代码有什么问题?坦率地说,一切。 :P

该页面的格式与您阅读时的方式不同。你不能希望以这种方式获得所需的内容。

页面的内容(我们感兴趣的部分)看起来像这样:

<h2>
<span id="Deployments" class="mw-headline">Deployments</span>
</h2>
<p>
    <!-- ... -->
    <b>SBS8987B</b>
    (SLBP 192/194*)
    <br>
    <b>SBS8988Z</b>
    (SLBP 192/194*) - F&amp;N NutriSoy Fresh Milk: Singapore's No. 1 Soya Milk! (2nd Gen)
    <br>
    <b>SBS8989X</b>
    (SLBP SP)
    <br>
    <!-- ... -->
</p>

基本上我们需要找到包含我们要查找的注册号的b 元素。一旦我们找到该元素,获取文本并将其放在一起形成结果。代码如下:

static string GetVehicleInfo(string reg)
{
    var url = "http://sgwiki.com/wiki/Scania_K230UB_%28Batch_1_Euro_V%29";

    // HtmlWeb is a helper class to get pages from the web
    var web = new HtmlAgilityPack.HtmlWeb();

    // Create an HtmlDocument from the contents found at given url
    var doc = web.Load(url);

    // Create an XPath to find the `b` elements which contain the registration numbers
    var xpath = "//h2[span/@id='Deployments']" // find the `h2` element that has a span with the id, 'Deployments' (the header)
              + "/following-sibling::p[1]"     // move to the first `p` element (where the actual content is in) after the header
              + "/b";                          // select the `b` elements

    // Get the elements from the specified XPath
    var deployments = doc.DocumentNode.SelectNodes(xpath);

    // Create a LINQ query to find the  requested registration number and generate a result
    var query =
        from b in deployments                 // from the list of registration numbers
        where b.InnerText == reg              // find the registration we're looking for
        select reg + b.NextSibling.InnerText; // and create the result combining the registration number with the description (the text following the `b` element)

    // The query should yield exactly one result (or we have a problem) or none (null)
    var content = query.SingleOrDefault();

    // Decode the content (to convert stuff like "&amp;" to "&")
    var decoded = System.Net.WebUtility.HtmlDecode(content);

    return decoded;
}

【讨论】:

  • 哈哈!假设只能以这种方式找到标签之间的信息是否正确?我将实现这一点,并尝试一下。非常感谢,杰夫!
  • n00b 问题:那么在这段代码之后会发生什么?我只是将它粘贴在我的私有 void getDeployment_Click (object sender, EventArgs e) 部分下吗?我也收到一个错误:由于 getDeployment_click 返回 void,return 关键字后面不能跟对象表达式。非常感谢! :)
  • 这只是一种方法。将其粘贴到您班级的某个位置,然后从您需要的任何地方调用它。
  • 感谢杰夫!这对我完全有用。如果可能的话,你能解释一下 var doc = web.Load(url) 部分之后的代码做什么吗?谢谢!
  • Jeff - 当我尝试查找 SBS1903P 和 sgwiki.com/wiki/Volvo_B10M_Mark_IV_(DM3500) 时,它不适用于此页面 sgwiki.com/wiki/Volvo_B10M_Mark_IV_(Walter_Alexander_Strider) 当我尝试查找 SBS2838M 时。通过阅读代码,我推断这个问题是由

    部署标题下方的额外标题引起的。有没有办法解决这个问题?

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-04
  • 1970-01-01
  • 1970-01-01
  • 2011-02-20
  • 1970-01-01
相关资源
最近更新 更多