Как вы перебираете несколько элементов в xml, используя красивый soup4

#python #xml #beautifulsoup

Вопрос:

Что я хочу сделать, так это извлечь элементы из xml-объекта и перечислить отдельные атрибуты (например, в реальном мире я сделал резервную копию sms-сообщений со своего телефона в формате xml и хочу переписать их в формате csv).

Я искал в Интернете помощь, чтобы сделать это, и нашел прекрасный суп. Кажется, он делает именно то, что я хочу. Используя примеры в Интернете, я могу извлечь информацию из первого элемента. Но я ни за что на свете не могу понять, как продвинуться дальше первого тега в группе. Из того, что я могу сказать, приведенный ниже код должен дать мне:

5555555555 — 30 августа 2019 11:10:09 ВЕЧЕРА

6666666666 — 30 августа 2019 11:10:09 ВЕЧЕРА

7777777777 — 01 сентября 2019 07:50:09 УТРА

но вместо этого я получаю следующую ошибку

allsms = суп.найди все(‘sms’) Ошибка типа: объект «Нетип» не может быть вызван

Я чувствую, что упускаю какой-то шаг. Может ли кто-нибудь здесь помочь мне понять, что я делаю не так

 lt;?xml version='1.0' encoding='UTF-8' standalone='yes' ?gt;   lt;sms address="555555555" type="1" subject="null" body="hello world" t sub_id="-1" readable_date="Aug 30, 2019 11:10:09 PM" contact_name="Mr. X" /gt;  lt;sms address="6666666666" type="2" subject="null" body="world says hello" sub_id="-1" readable_date="Aug 30, 2019 11:10:09 PM" contact_name="Mrs. Y" /gt;   lt;sms address="7777777777" type="1" subject="null" body="relatable fact: carrots are not all orange" sub_id="-1" readable_date="Sep 01, 2019 07:50:09 AM" contact_name="Mr. Z" /gt;   ################ from bs4 import BeautifulSoup with open('texts.xml', 'r') as f: data = f.read()  soup = BeautifulSoup(data, "xml") allsms = soup.findall('sms') for i in allsms: sms=soup.find('sms') address=sms.get('address') realDate=sms.get('readable_date') print(address   ' - '   realDate)  

Комментарии:

1. sms=soup.find('sms') всегда будет первым элементом sms, потому что вы снова и снова запрашиваете исходный объект soup… вы хотите ссылаться i внутри цикла (или еще лучше… переименуйте i в sms , а затем удалите свою sms=soup.find('sms') строку…

2. это find_all или findAll, но не findall

3. @diggusbickus findAll устарел уже целую вечность … просто не удаляйте, так как в данный момент это, скорее всего, сломает слишком много вещей… так что да… Я бы рекомендовал find_all

4. @Джон Клементс — спасибо, это сработало!

5. что это за т -gt; gt; body="hello world" t sub_id="-1" . Это делает XML недействительным

Ответ №1:

Удаление лишней буквы t в первом sms элементе, обертывание xml с помощью root и использование встроенной xml-библиотеки python

 import xml.etree.ElementTree as ET  xml = '''lt;rgt;  lt;sms address="555555555" type="1" subject="null" body="hello world" sub_id="-1" readable_date="Aug 30, 2019 11:10:09 PM" contact_name="Mr. X" /gt;  lt;sms address="6666666666" type="2" subject="null" body="world says hello" sub_id="-1" readable_date="Aug 30, 2019 11:10:09 PM" contact_name="Mrs. Y" /gt;  lt;sms address="7777777777" type="1" subject="null" body="relatable fact: carrots are not all orange" sub_id="-1" readable_date="Sep 01, 2019 07:50:09 AM" contact_name="Mr. Z" /gt; lt;/rgt;'''  root = ET.fromstring(xml) for sms in root.findall('sms'):  print(f'{sms.attrib["address"]} {sms.attrib["readable_date"]}')  

выход

 555555555 Aug 30, 2019 11:10:09 PM 6666666666 Aug 30, 2019 11:10:09 PM 7777777777 Sep 01, 2019 07:50:09 AM