在C#中实现动态Web Scraper的逻辑

时间:2010-01-23 04:44:05

标签: c# dom web-crawler bots web-scraping

我希望用C#窗体开发一个Web scraper。我想要完成的工作如下:

  1. 从用户处获取网址。
  2. 将网页加载到WINForms中的IE UI控件(嵌入式浏览器)中。
  3. 允许用户选择文本(连续,小(不超过50个字符))。来自加载的网页。
  4. 当用户希望保留位置( HTML DOM位置)时,必须将其持久存储到数据库中,以便用户可以在该位置使用该位置获取该位置的数据随后的访问。
  5. 假设加载的网站是一个价格网站,并且引用的费率不断变化,我们的想法是坚持DOM层次结构,这样我下次就可以遍历它。

    如果所有HTML元素都有自己的id属性,我就能做到这一点。在id为null的情况下,我无法完成此操作。

    有人可以建议一个有效的想法(如果可能的话,这是一个最低限度的代码片段。)

    即使您可以共享一些在线资源,它也会有所帮助。

    感谢,

    维杰

2 个答案:

答案 0 :(得分:2)

一种方法是在您要选择的元素下构建一堆标签/样式/ id。

从您想要的元素,遍历到最近的id元素。通过这种方式,您将摆脱大多数顶部标题等。然后构建一个序列来查找。

示例:

<html>
  <body>
    <!-- lots of html -->
    <div id="main">
       <div>
          <span>
             <div class="pricearea">
                <table> <!-- with price data -->

对于exmaple,您将在数据库中存储以下序列: [id = main],div,span,div,table 或者 div [class = pricearea],table < /强>

使用样式/类也可用于创建路径。您可以选择标记,标记属性或组合。您希望尽可能使用尽可能少的元素使其更加稳定。

如果布局很少更改,则每次都可以导航到同一位置。

我还建议您使用HTML Agility Pack或类似的东西进行DOM解析,因为IE控件很慢。

屏幕抓取很有趣,但很难为所有页面获得100%的抓取效果。祝你好运!

答案 1 :(得分:0)

经过一番谷歌搜索后,我遇到了一个相当简单的解决方案。下面附带的是示例代码段。

if (webBrowser.Document != null)
        {
            IHTMLDocument2 HtmlDoc = (IHTMLDocument2)webBrowser.Document.DomDocument;// loads the HTML DOM
            IHTMLSelectionObject selection = HtmlDoc.selection;// Fetches the currently selected HTML Element.
            IHTMLTxtRange range = (IHTMLTxtRange)selection.createRange();
            IHTMLElement parentElement = range.parentElement();// Identifies the parent element
            targetSourceIndex = parentElement.sourceIndex;               
            //dataLocation = range.parentElement().id;                
            MessageBox.Show(range.text);//range.parentElement().sourceIndex
        }

我在Winforms应用程序中使用了嵌入式Web浏览器,它加载了当前网页的HTML DOM。

IHTMLElement 实例公开了一个名为“SourceIndex”的属性,该属性为每个html元素分配一个唯一ID。

可以将此SourceIndex存储到数据库并查询该位置的内容。使用以下代码。

if (webBrowser.Document != null)
            {
                IHTMLDocument2 HtmlDoc = (IHTMLDocument2)webBrowser.Document.DomDocument;
                IHTMLElement targetElement = null;
                foreach (IHTMLElement domElement in HtmlDoc.all)
                {
                    if (domElement.sourceIndex == int.Parse(node.InnerText))// fetching the persisted data from the XML file.
                    {
                        targetElement = domElement;
                        break;
                    }
                }

                MessageBox.Show(targetElement.innerText); //range.parentElement().sourceIndex
            }