The CSS selector you have doesn't even have a syntactically valid selector:
[class~=odd even]
Values containing spaces should always be specified, so the correct way to write this selector would be:
[class~="odd even"]
However, this selector cannot really match anything: the selector of the attribute values [attr~=val] matches ...
an element with the attribute att , whose value is a list of words separated by spaces, one of which is exactly equal to "val" . If "val" contains spaces, it will never represent anything (since words are separated by spaces)
Since words are separated by spaces, this means that they can never contain spaces. But the word you are looking for ( "odd even" ) contains spaces, so it cannot match anything.
Presumably, what you are looking for is an OR combinator, but it does not exist. So what you are looking for cannot be expressed using CSS selectors.
Well, actually, this is not so: it can be expressed using CSS selectors. You can simply use selector groups that give you a set of match joins, which is equivalent to using the OR combinator:
table.data tr.odd, table.data tr.even
Remember: CSS is set-based, so order doesn't matter. In your case, order matters, which means CSS is really the wrong tool to work with:
report.xpath('//table[@class="data"]//tr[@class="odd" or @class="even"')
Although I have to admit that I'm not sure why you are not just using something like this:
report.css('table.data tr')
After all, does not select all the odd and all the even lines the same as selecting all the lines? I mean, what else did you get there, irrational lines?