В Python, используя красивый суп — как мне получить текст XML-тега, содержащего дефис

#python #xml #web-scraping #beautifulsoup #tags

Вопрос:

Я пытаюсь получить текстовое содержимое тега «Идентификатор события» в XML, но дефис не распознается как элемент в файле, я знаю, что скрипт работает хорошо, потому что, если заменить дефис на подчеркивание в XML и запустить скрипт, он работает, кто-нибудь знает, в чем может быть проблема?

 
<?xml version="1.0" encoding="UTF-8"?>
<eventsUpdate xmlns="http://nateng.com/xsd/NETworks">
    <fullEventsUpdate xmlns="">
        <fullEventUpdate xmlns="">
            <event-reference xmlns="">
                <event-id xmlns="">24425412</event-id>
                <event-update xmlns="">34</event-update>
            </event-reference>
        </fullEventUpdate>
        <fullEventUpdate xmlns="">
            <event-reference xmlns="">
                <event-id xmlns="">24342548</event-id>
                <event-update xmlns="">34</event-update>
            </event-reference>
        </fullEventUpdate>
    </fullEventsUpdate>
</eventsUpdate> 



from bs4 import BeautifulSoup

dir_path = '20211006085201.xml'

file = open(dir_path, encoding='UTF-8')
contents = file.read()
soup = BeautifulSoup(contents, 'xml')

events = soup.find_all('fullEventUpdate')


print(' n-------', len(events), 'events calculated on ', dir_path, '--------n')

idi = soup.find_all('event-reference')

for x in range(0, len(events)):
    idText = (idi[x].event-id.get_text())
    print(idText)
 

Ответ №1:

Проблема в том, что вы имеете дело с xml с пространством имен, и для этого типа документа вместо этого следует использовать селекторы css:

 events = soup.select('fullEventUpdate')
for event in events:
    print(event.select_one('event-id').text)
 

Выход:

 24425412
24342548
 

В более общем плане, при работе с xml-документами вам, вероятно, лучше использовать что-то, что поддерживает xpath (например, lxml или ElementTree).

Ответ №2:

Для синтаксического анализа XML идиоматический подход заключается в использовании селекторов xpath.

В python это может быть легко достигнуто с parsel помощью пакета, который аналогичен beautifulsoup , но построен поверх lxml для полной поддержки xpath:

 body = ...
from parsel import Selector
selector = Selector(body)
for event in sel.xpath("//event-reference"):
    print(event.xpath('event-id/text()').get())
 

результаты в:

 24425412
24342548
 

Ответ №3:

Без какой-либо внешней библиотеки (только ElementTree)

 import xml.etree.ElementTree as ET


xml = '''<?xml version="1.0" encoding="UTF-8"?>
<eventsUpdate xmlns="http://nateng.com/xsd/NETworks">
    <fullEventsUpdate xmlns="">
        <fullEventUpdate xmlns="">
            <event-reference xmlns="">
                <event-id xmlns="">24425412</event-id>
                <event-update xmlns="">34</event-update>
            </event-reference>
        </fullEventUpdate>
        <fullEventUpdate xmlns="">
            <event-reference xmlns="">
                <event-id xmlns="">24342548</event-id>
                <event-update xmlns="">34</event-update>
            </event-reference>
        </fullEventUpdate>
    </fullEventsUpdate>
</eventsUpdate> '''

root = ET.fromstring(xml)
ids = [e.text for e in root.findall('.//event-id')]
print(ids)
 

выход

 ['24425412', '24342548']