【问题标题】:Logic for Implementing a Dynamic Web Scraper in C#在 C# 中实现动态 Web Scraper 的逻辑
【发布时间】:2011-01-08 11:50:24
【问题描述】:

我希望在 C# 窗口窗体中开发一个 Web 抓取工具。我要完成的工作如下:

  1. 从用户那里获取 URL。
  2. 在 WINForms 的 IE UI 控件(嵌入式浏览器)中加载网页。
  3. 允许用户选择文本(连续、小(不超过 50 个字符))。从加载的网页。
  4. 当用户希望保存位置(HTML DOM 位置)时,必须将其保存到 DB 中,以便用户可以使用该位置在他的过程中获取该位置中的数据后续访问。

假设加载的网站是一个价格列表网站,并且报价不断变化,想法是保持 DOM 层次结构,以便我下次可以遍历它。

如果所有 HTML 元素都有其 id 属性,我将能够做到这一点。在 id 为 null 的情况下,我无法做到这一点。

有人可以提出一个有效的想法吗(如果可能的话,一个最低限度的代码 sn-p)。

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

谢谢,

维杰

【问题讨论】:

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


    【解决方案1】:

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

    从你想要的元素,向上遍历到最近的 id 元素。这样,您将摆脱大部分顶部标题等。然后构建一个要查找的序列。

    例子:

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

    例如,您可以在数据库中存储以下序列:[id=main],div,span,div,table 或者可能是 div[class=pricearea],table。

    也可以使用样式/类来创建路径。您可以选择查找标签、标签的属性或组合。您希望它尽可能准确,使用尽可能少的元素以使其健壮。

    如果布局很少更改,这将让您每次都导航到相同的位置。

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

    屏幕抓取很有趣,但很难对所有页面都做到 100%。祝你好运!

    【讨论】:

    • @Mikael 。感谢您清晰的解释米凯尔。甚至我也有类似的想法。但是在尝试访问废弃的元素(向下遍历)时,即使是兄弟姐妹也被获取了。例如,如果 div 'pricearea' 中有两个表,或者第一个表中有两行,则持久化最近的父级的逻辑不起作用。
    • 您可以在解析 div,table[class=something,no=2] 中添加索引器逻辑。与将标签/样式附加到路径的方式相同,您也可以添加索引器。如果你粘贴一些示例html和你想要抓取的元素,我可以尝试写一个例子。
    【解决方案2】:

    经过一番谷歌搜索,我遇到了一个相当简单的解决方案。下面附上示例 sn-p。

    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
                }
    

    【讨论】:

    • 这会起作用,但很容易出错。一个新标签,并且索引更改。使用 mshtml 也很慢,我不建议在服务器端代码上使用它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-09
    • 2015-08-16
    • 1970-01-01
    • 2021-04-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多