#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