“<i>”中断正确的节点选择</i>

时间:2014-01-27 18:52:49

标签: xpath scrapy

我正在尝试选择具有以下结构的表字段:

<td class='postac'>proszek do sporz. roztworu do wlewu <I>i.v.</I>
                    1,5 g
                1 fiol. typu Monovial
</td>

使用xpath表达式sel.xpath("//table[@class='table-postaci']/tbody/tr/td[2]/text()").extract()后,我得到两个值而不是一个:

u'proszek do sporz. roztworu do wlewu ',
                u'\r\n                            1,5 g\r\n                        1 fiol. typu Monovial\r\n        '

将这个“td”字段作为单个值,是否有一些干净的xpath方法?我知道我可以使用//table[@class='table-postaci']/tbody/tr/td[2]获取字段,然后在scrapy管道中删除标记。但是,我正在寻找一些更简单的解决方案。谢谢

3 个答案:

答案 0 :(得分:2)

出于这个原因,你应该避免使用/ text()。通常你不需要单独的文本节点,你需要元素的字符串值,你可以使用string()函数获得。目前尚不清楚您从哪个编程语言调用XPath,或者它是XPath 1.0还是2.0 - 会影响细节,例如:是否在XPath表达式或宿主语言中获取元素的字符串值。

答案 1 :(得分:2)

您可以遍历每个表格行tr,并为每一行加入第二个td单元格的所有文本节点后代:

In [13]: from scrapy.selector import Selector

In [14]: selector = Selector(text="""<table class='table-postaci'>
   ....:        <thead><th>Nazwa preparatu</th><th>Postać i dawka</th><th>Producent</th><th>Cena 100%</th>
   ....:                        <th>Odpłatność po refundacji</th>
   ....:        </thead>
   ....:        <tbody>
   ....: 
   ....:                        <tr>
   ....:                <td class='postac'>Zinacef </td>
   ....:                <td class='postac'>proszek do sporz. roztworu do wlewu <I>i.v.</I>
   ....:                             1,5 g
   ....:                         1 fiol. typu Monovial
   ....:         </td>
   ....:                <td>GlaxoSmithKline – Wielka Brytania</td>
   ....:                <td class='cena'> b/d </td>
   ....:                                <td>
   ....:                                </td>
   ....:                </tr>
   ....:                        <tr>
   ....:                <td class='postac'>Zinacef </td>
   ....:                <td class='postac'>proszek do sporz. roztworu do wlewu <I>i.v.</I>
   ....:                             750 mg
   ....:                         1 fiol. typu Monovial
   ....:         </td>
   ....:                <td>GlaxoSmithKline – Wielka Brytania</td>
   ....:                <td class='cena'> b/d </td>
   ....:                                <td>
   ....:                                </td>
   ....:                </tr>
   ....:                </tbody>
   ....:        </table""")

In [15]: selector.xpath('//table/tr')
Out[15]: []

In [16]: selector.xpath('//table//tr')
Out[16]: 
[<Selector xpath='//table//tr' data=u'<tr><td class="postac">Zinacef </td>\n\t\t<'>,
 <Selector xpath='//table//tr' data=u'<tr><td class="postac">Zinacef </td>\n\t\t<'>]

In [17]: for row in selector.xpath('//table//tr'):
   ....:     print row.xpath('td[2]//text()').extract()
   ....:     
[u'proszek do sporz. roztworu do wlewu ', u'i.v.', u'\n                            1,5 g\n                        1 fiol. typu Monovial\n        ']
[u'proszek do sporz. roztworu do wlewu ', u'i.v.', u'\n                            750 mg\n                        1 fiol. typu Monovial\n        ']

In [18]: [u''.join(row.xpath('td[2]//text()').extract()) for row in selector.xpath('//table//tr')]
Out[18]: 
[u'proszek do sporz. roztworu do wlewu i.v.\n                            1,5 g\n                        1 fiol. typu Monovial\n        ',
 u'proszek do sporz. roztworu do wlewu i.v.\n                            750 mg\n                        1 fiol. typu Monovial\n        ']

In [19]: 

答案 2 :(得分:1)

问题中的td节点有三个子节点 - 首先是一个包含内容的文本节点:

proszek do sporz. roztworu do wlewu 

第二个I元素节点,它有自己的子文本节点,最后一个文本节点包含内容:

\n                    1,5 g\n                1 fiol. typu Monovial\n

您的查询(其末尾看起来像td[2]/text())仅选择td元素的直接文本节点子节点,因此它不会选择I元素节点或其文本节点子。结果是您看到的两个文本节点。

您可以使用td选择{{1>}元素的所有文本节点decedents(请注意双斜杠td[2]//text())。这将在结果中返回三个文本节点 - 两个如上所述,第三个在它们之间包含//。然后你可以在XPath之外加入他们(我不熟悉scrapy,所以在这种情况下我不能告诉你如何)。

据我所知,你无法直接使用XPath 1.0加入这三个节点,但XPath 2.0可能会加入。