Scrapy / XPath: заменить встроенные теги в абзаце - PullRequest
0 голосов
/ 28 июня 2018

Я пытаюсь использовать Scrapy для извлечения и очистки некоторого текста из p, который содержит встроенные значки и другие теги. В частности, я хочу заменить теги изображений текстом, извлеченным из атрибута image src:

from scrapy.selector import Selector
text = '''
<p id="1"><b><br></b>For service <i>to </i>these stations, take the <img src="images/1.png"> to 72 St or Times Sq-42 St and transfer
    <br>to an uptown <img src="images/1.png"> or <img src="images/2.png"> <i>local</i>.
    <br>
    <br>For service <i>from </i>these stations, take the <img src="images/1.png"> or <img src="images/2.png"> to 72 St or 96 St and transfer
    <br>to a South Ferry-bound <img src="images/1.png">.
    <br><b>______________________________<br></b>
</p>
'''
sel = Selector(text=text)
# do stuff

В результате я ищу строку:

Для обслуживания на этих станциях возьмите (1) до 72 St или Times Sq-42 St и отправьтесь в местный (1) или (2) город. Для обслуживания от этих станций, возьмите (1) или (2) до 72 St или 96 St и перейдите к Южной паромной переправе (1).

Я могу извлечь текст из src, используя:

node.css('img').xpath('@src').re_first(r'images/(.+).png')

но я застрял на том, как перебирать дочерние узлы и определять, является ли это текстовым узлом / как отфильтровывать другие встроенные теги. Вот где я нахожусь:

description = sel.css('p#1')

def clean_html(description):
    for n in description.xpath('node()'):
        if (n.xpath('self::img')):
            yield n.xpath('@src').re_first(r'images/(.+).png')
        if (n.xpath('self::text()')):
            yield n.css('::text')

text = ''.join(clean_html(description))

Ответы [ 2 ]

0 голосов
/ 29 июня 2018

Вот как я бы сделал это без какой-либо дополнительной внешней библиотеки:

  1. Получение путей для текста и изображений:

    results = selector.xpath('.//text()|.//img/@src').extract()

  2. Удалить лишние пробелы, новые строки и подчеркивания:

    results = map(lambda x: x.strip('\n_ '), results)

  3. Удалить пустые строки:

    results = filter(None, results)

  4. Объедините результаты в один абзац и исправьте точки:

    raw_paragraph = " ".join(results).replace(' .', '.')

  5. Заменить images/{Number}.png на ({Number}):

    paragraph = re.sub('images/(?P<number>\d+).png', '(\g<number>)', raw_paragraph)

Результат: For service to these stations, take the (1) to 72 St or Times Sq-42 St and transfer to an uptown (1) or (2) local. For service from these stations, take the (1) or (2) to 72 St or 96 St and transfer to a South Ferry-bound (1).

0 голосов
/ 29 июня 2018

В этом случае я не думаю, что selectors особенно полезны.

Попробуйте обработать это в два этапа.

  1. Используйте re.sub для замены всего тега img на строку, которую вы хочу.
  2. Используйте BeautifulSoup, чтобы удалить оставшийся HTML из результирующей строки.

Как это:

from scrapy.selector import Selector
import re
from bs4 import BeautifulSoup

# manually construct a selector for demonstration purposes
DATA = '''
<p id="1"><b><br></b>For service <i>to </i>these stations, take the <img src="images/1.png"> to 72 St or Times Sq-42 St and transfer
    <br>to an uptown <img src="images/1.png"> or <img src="images/2.png"> <i>local</i>.
    <br>
    <br>For service <i>from </i>these stations, take the <img src="images/1.png"> or <img src="images/2.png"> to 72 St or 96 St and transfer
    <br>to a South Ferry-bound <img src="images/1.png">.
    <br><b>______________________________<br></b>
</p>
'''
sel = Selector(text=DATA)

# get the raw source string to work with
text = sel.extract()

# replace image tag with text from extracted file name
image_regex = re.compile('(<img src="images/)(.+?)(.png">)', re.MULTILINE)
replaced = re.sub(image_regex, r'(\2)', text)

# remove html and return clean text
soup = BeautifulSoup(replaced, 'lxml')
print(soup.get_text())

Результаты:

Для обслуживания этих станций возьмите от (1) до 72 St или Times Sq-42 St и перевод в жилой район (1) или (2) местного жителя.

Для обслуживания с этих станций возьмите (1) или (2) до 72 ст. Или 96 ст. и перевод в южном пароме (1). ______________________________

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...