2015-09-25 169 views
1

我试图在XML文件(使用scrapy和xpath)中获取某些标记的属性值和键值。使用Scrapy获取属性名称XPATH

的标签是这样的:

<element attr1="value1" attr2="value2 ...> 

我不知道钥匙“attR1位”,“attR2位”等等,它们可以在两个元素之间改变。我没有弄清楚如何用xpath获取键和值,还有其他的好做法吗?

回答

5

短版

>>> for element in selector.xpath('//element'): 
...  attributes = [] 
...  # loop over all attribute nodes of the element 
...  for index, attribute in enumerate(element.xpath('@*'), start=1): 
...   # use XPath's name() string function on each attribute, 
...   # using their position 
...   attribute_name = element.xpath('name(@*[%d])' % index).extract_first() 
...   # Scrapy's extract() on an attribute returns its value 
...   attributes.append((attribute_name, attribute.extract())) 
... 
>>> attributes # list of (attribute name, attribute value) tuples 
[(u'attr1', u'value1'), (u'attr2', u'value2')] 
>>> dict(attributes) 
{u'attr2': u'value2', u'attr1': u'value1'} 
>>> 

龙版

的XPath有name(node-set?) function得到节点名称(an attribute is a node, an attribute node):

˚F (...)如果它省略的参数为,它默认为一个节点集,其中包含一个QName,它代表参数node-set中节点的展开名称, 上下文节点作为其唯一成员。

(来源:http://www.w3.org/TR/xpath/#function-name

>>> import scrapy 
>>> selector = scrapy.Selector(text=''' 
...  <html> 
...  <element attr1="value1" attr2="value2">some text</element> 
...  </html>''') 
>>> selector.xpath('//element').xpath('name()').extract() 
[u'element'] 

(在此,我//element选择的结果链式name(),给函数应用到所有选定元素节点Scrapy选择的一个方便的功能。)

一个想要做同样的属性节点,对不对?但它不工作:

>>> selector.xpath('//element/@*').extract() 
[u'value1', u'value2'] 
>>> selector.xpath('//element/@*').xpath('name()').extract() 
[] 
>>> 

注:我不知道,如果它是lxml/libxml2的限制,这Scrapy引擎盖下使用,或如果XPath规范禁止它。 (我不明白为什么会这样)

你可以做的是使用name(node-set)形式,即以非空节点集作为参数。如果仔细阅读的XPath的部分1.0规格我上面粘贴,与其他字符串的功能,name(node-set)仅考虑在节点集合(按文档顺序)的第一节点

>>> selector.xpath('//element').xpath('@*').extract() 
[u'value1', u'value2'] 
>>> selector.xpath('//element').xpath('name(@*)').extract() 
[u'attr1'] 
>>> 

属性节点也有位置,所以你可以通过它们的位置循环所有属性。在这里,我们有2个(共count(@*)上下文节点上的结果):

>>> for element in selector.xpath('//element'): 
...  print element.xpath('count(@*)').extract_first() 
... 
2.0 
>>> for element in selector.xpath('//element'): 
...  for i in range(1, 2+1): 
...   print element.xpath('@*[%d]' % i).extract_first() 
... 
value1 
value2 
>>> 

现在,你能猜到是什么,我们可以这样做:叫name()每个@*[i]

>>> for element in selector.xpath('//element'): 
...  for i in range(1, 2+1): 
...   print element.xpath('name(@*[%d])' % i).extract_first() 
... 
attr1 
attr2 
>>> 

如果你把所有这些组合起来,并假定@*将让你在文档顺序属性(在XPath 1.0规范,我认为不说,但它是我所看到的与lxml发生),你结束了这一点:

>>> attributes = [] 
>>> for element in selector.xpath('//element'): 
...  for index, attribute in enumerate(element.xpath('@*'), start=1): 
...   attribute_name = element.xpath('name(@*[%d])' % index).extract_first() 
...   attributes.append((attribute_name, attribute.extract())) 
... 
>>> attributes 
[(u'attr1', u'value1'), (u'attr2', u'value2')] 
>>> dict(attributes) 
{u'attr2': u'value2', u'attr1': u'value1'} 
>>> 
1

我想在XML文件(使用scrapy和xpath)中获取某些标记的属性值的键和值。

您需要@*,这意味着“任何属性”。 XPath表达式//element/@*将为您提供元素element的所有属性以及属性及其值。