Scrapy — используйте CSS для поиска элементов, которые могут содержать разные подэлементы

Я использую Scrapy для очистки https://www.hillhappenings.com/ ряда полей данных, связанных с политическими событиями: имя, время, данные и местоположение. Я понял, что HTML для поля местоположения использует два разных формата:

<li class = "eventlist-meta-item eventlist-meta-address event-meta-item">
    2168 Rayburn House Office Building
</li>

...а также ...

<li class = "eventlist-meta-item eventlist-meta-address event-meta-item">            
    <span class = "eventlist-meta-address-line">A St.</span>
    <span class = "eventlist-meta-address-line">Washington, DC, 20002</span>
    <span class = "eventlist-meta-address-line">United States</span>
</li>

Я использую следующий код для получения названий и мест событий:

events = Selector(response=response).css('div.eventlist-column-info a.eventlist-title-link::text').getall()
addresses = Selector(response=response).css('div.eventlist-column-info li.eventlist-meta-item.eventlist-meta-address::text').getall()

Проблема в том, что из 80 событий 76 используют формат №1, а 4 используют формат №2, поэтому я получаю 80 событий, но только 76 адресов. Я хотел бы получить многострочные адреса, которые используют формат № 2 выше, в одной строке, например формат № 1. Сегодня утром я новичок в Scrapy, и мне интересно: «Как я могу использовать Scrapy для поиска элементов адреса, под которыми есть тег span, чтобы я мог объединить их в однострочный адрес?».

Вы пробовали addresses = ' '.join(Selector(...).css('... .eventlist-meta-address-line::text').getall())?

abdusco 10.07.2019 18:22

Спасибо за ваш ответ. 'join' на самом деле не совсем выполняет то, что мне нужно. Позвольте мне посмотреть, смогу ли я объяснить проблему немного лучше. Когда я выполняю getall() для получения адресов, мне не хватает адресов в формате № 2 выше, потому что эти адреса находятся внутри тега span, в отличие от формата № 1. Мои вопросы: могу ли я динамически очищать элементы в зависимости от того, содержат ли они подэлемент <span>?

jkovba 10.07.2019 18:33

Ах я вижу. Смотри мой ответ

abdusco 10.07.2019 18:46

Хм, ты имеешь в виду def my_func(a_param: param_type) -> return_type:? Это называется аннотацией типа, в основном, чтобы помочь редакторам/IDE для автодополнения кода. Вы можете просто удалить его, конечно, это не повлияет на код.

abdusco 10.07.2019 19:01
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
4
82
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Может быть, попробовать атрибут [attr] или селекторы подстановочных знаков *? Поскольку оба формата содержат текст в элементе с классом eventlist-meta-address-*, вы можете использовать [class* = "eventlist-meta-address"]::text или просто .eventlist-meta-address *::text

from parsel import Selector

def extract_address(sel: Selector) -> str:
    # this one works too
    # metas = s.css('.eventlist-meta-address *::text').getall()
    metas = s.css('[class* = "eventlist-meta-address"]::text').getall()
    return ' '.join(m.strip() for m in metas if m.strip())

if __name__ == '__main__':
    format1 = '''
    <li class = "eventlist-meta-item eventlist-meta-address event-meta-item">
        2168 Rayburn House Office Building
    </li>
    '''
    format2 = '''
    <li class = "eventlist-meta-item eventlist-meta-address event-meta-item">
        <span class = "eventlist-meta-address-line">A St.</span>
        <span class = "eventlist-meta-address-line">Washington, DC, 20002</span>
        <span class = "eventlist-meta-address-line">United States</span>
    </li>
    '''
    for f in [format1, format2]:
        s = Selector(f)
        print(extract_address(s))

выход:

2168 Rayburn House Office Building
A St. Washington, DC, 20002 United States

Другие вопросы по теме