【问题标题】:Scraping framework with xpath support支持 xpath 的抓取框架
【发布时间】:2015-06-29 17:10:16
【问题描述】:

我正在寻找一个可以让我使用的网络抓取框架

  1. 点击给定端点并加载 html 响应
  2. 通过一些 CSS 选择器搜索元素
  3. 恢复该元素的 xpath

有什么建议吗?我见过很多让我通过 xpath 搜索的,但没有一个真正为元素生成 xpath。

【问题讨论】:

  • 您仅限使用哪些语言(如果有)?
  • 任何语言都可以。
  • 您有机会查看我发布的答案吗? JQuery 示例很简单,但需要在 Node.js 中实现,除了我链接到的材料解释了有关在该域中使用 JQuery 的一些内容之外,我无能为力。 Python 示例是完整的,但在技术上不是一个网络抓取框架。 C# 示例实际上来自 HTMLAgilityPack,它是一个完整的 Web 抓取框架。
  • 我还在努力;答案比我预期的要详细得多(质量也更高)。

标签: xpath css-selectors web-scraping


【解决方案1】:

似乎没有多少人通过 CSS 选择器搜索但希望将结果作为 XPath,但有一些选项可以实现。

首先,我使用 JQuery 加上一个附加功能来完成这项工作。这是因为 JQuery 有很好的选择并且很容易找到支持。您可以use JQuery in Node.js,因此您应该能够在该域(在服务器上)而不是在客户端(如我的简单示例中所示)中实现我的代码。如果这不是一个选项,您可以在下面查找我使用 Python 的其他潜在解决方案,或者在底部查找 C# starter。


对于 JQuery 方法,纯 JavaScript 函数返回 XPath 非常简单。在以下示例 (also on JSFiddle) 中,我使用 JQuery 选择器检索示例锚元素,获取剥离的 DOM 元素,并将其发送到我的 getXPath 函数:

<html>
<head>
<title>The jQuery Example</title>
   <script type="text/javascript" 
   src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
   <script type="text/javascript">
    function getXPath( element )
    {
        var xpath = '';
        for ( ; element && element.nodeType == 1; element = element.parentNode )
        {
            var id = $(element.parentNode).children(element.tagName).index(element) + 1;
            id > 1 ? (id = '[' + id + ']') : (id = '');
            xpath = '/' + element.tagName.toLowerCase() + id + xpath;
        }
        return xpath;
    }

    $(document).ready(function() {
        $("#example").click(function() {
            alert("Link Xpath: " + getXPath($("#example")[0]));
        });
    });

   </script>   
</head>
<body>
    <p id="p1">This is an example paragraph.</p>
    <p id="p2">This is an example paragraph with a <a id="example" href="#">link inside.</a></p>
</body>
</html>

如果您需要比我提供的复杂度更高的复杂性,有一个完整的库,用于更强大的 CSS 选择器到 XPath 转换,称为 css2xpath


Python (lxml): 对于 Python,您需要使用 lxml 的 CSS 选择器类 (see link for full tutorial and docs) 来获取 xml 节点。

CSSSelector 类

lxml.cssselect 模块中最重要的类是 CSSSelector。 它提供与 XPath 类相同的接口,但接受 CSS 选择器表达式作为输入:

>>> from lxml.cssselect import CSSSelector
>>> sel = CSSSelector('div.content')
>>> sel  #doctest: +ELLIPSIS <CSSSelector ... for 'div.content'>
>>> sel.css
'div.content'

选择器实际上编译为 XPath,你可以看到 通过检查对象来表达:

>>> sel.path
"descendant-or-self::div[@class and contains(concat(' ', normalize-space(@class), ' '), ' content ')]"

要使用选择器,只需使用文档或元素对象调用它:

>>> from lxml.etree import fromstring
>>> h = fromstring('''<div id="outer"> 
...   <div id="inner" class="content body"> 
...       text 
...   </div></div>''')
>>> [e.get('id') for e in sel(h)]
['inner']

使用 CSSSelector 相当于使用 cssselect 和 使用 XPath 类:

>>> from cssselect import GenericTranslator
>>> from lxml.etree import XPath
>>> sel = XPath(GenericTranslator().css_to_xpath('div.content'))

CSSSelector 带有一个翻译器参数让你选择哪个 翻译器使用。它可以是“xml”(默认)、“xhtml”、“html”或 翻译器对象。

如果您希望从 url 加载,您可以在构建 etree 时直接执行此操作:root = etree.fromstring(xml, base_url="http://where.it/is/from.xml")


C# 有一个名为 css2xpath-reloaded 的库,它只做 CSS 到 XPath 的转换。

String css = "div#test .note span:first-child";

String xpath = css2xpath.Transform(css);

// 'xpath' will contain:
// //div[@id='test']//*[contains(concat(' ',normalize-space(@class),' '),' note ')]*[1]/self::span

当然,使用 C# 实用程序类从 url 获取字符串非常容易,不需要讨论:

using(WebClient client = new WebClient()) {
   string s = client.DownloadString(url);
}

至于 CSS 选择器的选择,你可以试试Fizzler,它非常强大。这是首页示例,尽管您可以做更多的事情:

// Load the document using HTMLAgilityPack as normal
var html = new HtmlDocument();
html.LoadHtml(@"
  <html>
      <head></head>
      <body>
        <div>
          <p class='content'>Fizzler</p>
          <p>CSS Selector Engine</p></div>
      </body>
  </html>");

// Fizzler for HtmlAgilityPack is implemented as the 
// QuerySelectorAll extension method on HtmlNode

var document = html.DocumentNode;

// yields: [<p class="content">Fizzler</p>]
document.QuerySelectorAll(".content"); 

// yields: [<p class="content">Fizzler</p>,<p>CSS Selector Engine</p>]
document.QuerySelectorAll("p");

// yields empty sequence
document.QuerySelectorAll("body>p");

// yields [<p class="content">Fizzler</p>,<p>CSS Selector Engine</p>]
document.QuerySelectorAll("body p");

// yields [<p class="content">Fizzler</p>]
document.QuerySelectorAll("p:first-child");

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-10-24
    • 2011-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-13
    • 1970-01-01
    相关资源
    最近更新 更多