Xpath scrapy result not as expected

Viewed 51

I've being trying to get the values of a preceding tag. Here's what I'm doing:

The struct of html page:

...
<tr class="destaque no-hover">
    <td class="periodo" colspan="6">2020.1</td>
</tr>
<tr class="linhaPar">
    <td>Text1</td>
    <td align="center">01</td>
    <td align="right">312h</td>
    <td align="center">3T12</td>
</tr>
<tr class="linhaImpar">
    <td>Text2</td>
    <td align="center">01</td>
    <td align="right">12h</td>
    <td align="center">5M12</td>
</tr>
...
<tr class="destaque no-hover">
    <td class="periodo" colspan="6">2016.1</td>
</tr>
<tr class="linhaPar">
    <td>Text7</td>
    <td align="center">01</td>
    <td align="right">2h</td>
    <td align="center">2N12</td>
</tr>
<tr class="linhaImpar">
    <td>Text8</td>
    <td align="center">01</td>
    <td align="right">32h</td>
    <td align="center">4T12</td>
</tr>
...
<tr class="destaque no-hover">
    <td class="periodo" colspan="6">2014.2</td>
</tr>
<tr class="linhaPar">
    <td>TextN-1</td>
    <td align="center">01</td>
    <td align="right">2h</td>
    <td align="center">2N12</td>
</tr>
<tr class="linhaImpar">
    <td>TextN</td>
    <td align="center">01</td>
    <td align="right">32h</td>
    <td align="center">4T12</td>
</tr>

So, I'm trying to get the infos of each one of those tr classes="linhaPar|linhaImpar"

for i in response.xpath('//tr[@class="linhaPar" or @class="linhaImpar"]')
    _aux = i.xpath('./td[1]')

However, I also need those td[@class="periodo"] so, I'm stucked with xpath

# I've tried this, but return a list of elements that matches, not the close one, as I want
    _p = _aux.xpath('./preceding::tr[td[@class="periodo"]')

# I've also tried this, but won't work
    _p = _aux.xpath('./preceding::tr[td[@class="periodo"] and position()=1]')

Solved

Maybe when I was making this question I wasn't clearly enough. The periodo change in different amounts of tr placed together. Every way that I've tried to search for, return me a list of possible results or nada. To solve the problem, I've tried the solution proposed to consider the periodo in the "for loop xpath":

_p = ""
for i in response.xpath('//tr[@class="linhaPar" or @class="linhaImpar" or @class="destaque no-hover"]'):
    # Check if it's a td with period
    if 'destaque no-hover' == i.xpath('./@class').get():
        _p = i.xpath('./td/text()').get()
        continue # Force to go to the next one
2 Answers

This XPath:

'//tr[@class="linhaPar" or @class="linhaImpar" or td[@class="periodo"]]' 

Assuming you want this stored in _p (one periodo for each tr context nodes) :

['2020.1'], ['2020.1'], ['2020.1'], ['2020.1']

use :

./preceding::td[@class="periodo"][1]

Assuming you want this stored in _p (one periodo for each group of data) :

['2020.1'], [], ['2020.2'], []

use :

./preceding-sibling::tr[1]/td[1][@class="periodo"]

If you need to remove empty elements from the created list, do it afterwards with filter.

For this second case you could also, as stated by @Gilles Quenot, change your context nodes for :

//tr[@class="linhaPar" or @class="linhaImpar" or @class="destaque no-hover"]

And fill your lists with :

_aux = ./td[1][not(@class="periodo")]
_p = ./td[1][@class="periodo"]

Or :

_aux = ./td[1][not(starts-with(text(),"2020."))]
_p = ./td[1][starts-with(text(),"2020.")]
Related