Scrapy: выберите тег с неразрывным пробелом с помощью xpath

В моем scrapy spider я хочу выбрать только <p> с текстовым содержимым:

item['Description'] = response.xpath('//*[@id="textepresentation"]//p[string(.)]').extract()

Он работает нормально, но, к сожалению, при этом я также получаю пустой <p> с неразрывным пробелом

u'<p>\xa0</p>',

Как избежать выбора <p> с неразрывным пробелом с помощью xpath?


person jacquesseite    schedule 12.02.2016    source источник


Ответы (2)


Для этого вы можете использовать строковую функцию normalize-space() XPath с парой предикаты:

  • [normalize-space()], чтобы вы получали элементы с непустым строковым представлением, исключая начальные и конечные пробелы
  • [not(contains(normalize-space(), "\u00a0"))], потому что NO-BREAK SPACE не удаляется (см. этот другой ответ, где я проверил, какие из них работают, вы можете добавить другие символы для проверки)

Образец:

>>> import scrapy
>>> selector = scrapy.Selector(text=u'''
... <html>
...     <p>&nbsp;</p>
...     <p>something</p>
...     <p>  </p>
...     <p><a href="http://example.com">some link</a></p>
... </html>
... ''')
>>> selector.xpath(u'''
...     //p[normalize-space()]
...        [not(contains(normalize-space(), "\u00a0"))]
... ''').extract()
[u'<p>something</p>', u'<p><a href="http://example.com">some link</a></p>']
>>> 

Редактировать:

после ответа @ Kimmy, вот альтернатива с 1 предикатом, а также для других символов пробела:

  • взять пробельные символы, которые не заменяются на normalize-space()
  • и поместите их в вызов XPath translate() с помощью ''
  • нормализовать пробелы, обрезая ведущие и конечные

Вот оно:

>>> chars = '''
... #CHARACTER TABULATION
... #LINE FEED
... #LINE TABULATION
... #FORM FEED
... #CARRIAGE RETURN
... #SPACE
... #NEXT LINE
... NO-BREAK SPACE
... OGHAM SPACE MARK
... MONGOLIAN VOWEL SEPARATOR
... EN QUAD
... EM QUAD
... EN SPACE
... EM SPACE
... THREE-PER-EM SPACE
... FOUR-PER-EM SPACE
... SIX-PER-EM SPACE
... FIGURE SPACE
... PUNCTUATION SPACE
... THIN SPACE
... HAIR SPACE
... ZERO WIDTH SPACE
... ZERO WIDTH NON-JOINER
... ZERO WIDTH JOINER
... LINE SEPARATOR
... PARAGRAPH SEPARATOR
... NARROW NO-BREAK SPACE
... MEDIUM MATHEMATICAL SPACE
... WORD JOINER
... IDEOGRAPHIC SPACE
... ZERO WIDTH NO-BREAK SPACE
... '''
>>> import unicodedata
>>> wsp = [unicodedata.lookup(c)
...        for c in chars.splitlines()
...        if c.strip() and not c.startswith('#')]
>>> 
>>> # somehow NEXT LINE (U+0085) does not work with unicodedata
... wsp.append(u'\u0085')
>>> 
>>> selector.xpath(u'''
...     //p[normalize-space(translate(., "%(in)s", "%(out)s"))]
...     ''' % {'in': ''.join(wsp),
...            'out': ' '*len(wsp)
...     }).extract()
[u'<p>something</p>', u'<p><a href="http://example.com">some link</a></p>']
>>> 
person paul trmbrth    schedule 12.02.2016
comment
Спасибо за это ценное подробное объяснение! Работает как положено. Спасибо ! - person jacquesseite; 12.02.2016

person    schedule
comment
Хорошая попытка, но item['Description'] = response.xpath('//*[@id="textepresentation"]//p[translate(string(.),'\xa0','')]').extract() SyntaxError: unexpected character after line continuation character - person jacquesseite; 12.02.2016
comment
@jacquesseite Конфликт разделителей строк. Последовательно используйте двойные кавычки в выражении XPath, т.е. translate(string(.),"\xa0","") - person har07; 12.02.2016
comment
Отредактировано для использования двойных кавычек. - person Kim Homann; 12.02.2016
comment
Спасибо @ har07 На этот раз ValueError: All strings must be XML compatible: Unicode or ASCII, no NULL bytes or control characters Пытаюсь понять ... - person jacquesseite; 12.02.2016