我正在尝试在XML文件中获取某些标记的属性键和值(使用scrapy和xpath)。
标签类似于:
<element attr1="value1" attr2="value2 ...>
我不知道键“attr1”,“attr2”等等,它们可以在两个元素之间切换。我没有弄清楚如何用xpath获取键和值,还有其他好的做法吗?
答案 0 :(得分:7)
简短版
>>> 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):
name 函数返回一个字符串,其中包含一个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']
(这里,我在name()
选择的结果上链接//element
,将函数应用于所有选定的元素节点.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 :(得分:1)
我正在尝试在XML文件中获取某些标记的属性键和值(使用scrapy和xpath)。
您需要//element/@*
,这意味着“任何属性”。 XPath表达式element
将为您提供元素{{1}}的所有属性,以及属性及其值。