#python #arrays #xml #beautifulsoup #attributes
Вопрос:
любая помощь будет признательна! Используя приведенный ниже пример XML-файла, я получаю неверный вывод.
Incorrect output: Emp_F_Name: Jill Emp_M_Name: H Emp_L_Name: Jones Desired output: Emp_F_Name: Jill Emp_M_Name: None or NULL Emp_L_Name: Jones
Я не уверен, почему функция find_next выходит за рамки объявленного атрибута (сотрудник).
lt;?xml version="1.0" encoding="utf-8"?gt; lt;org value="Tech"gt; lt;employeegt; lt;namegt; lt;familygt;Joneslt;/familygt; lt;givengt;Jilllt;/givengt; lt;/namegt; lt;/employeegt; lt;managergt; lt;namegt; lt;familygt;Fisherlt;/familygt; lt;givengt;Juniorlt;/givengt; lt;givengt;Hlt;/givengt; lt;/namegt; lt;/managergt; lt;/orggt;
Вот код, который я использую.
employee = soup.find("employee") for i in employee.find_all('name'): fname = employee.find('given') print("Emp_F_Name: ", fname.get_text()) mname = fname.find_next('given') print("Emp_M_Name: ", mname.get_text()) lname = employee.find('family') print("Emp_L_Name: ", lname.get_text())
Когда я запускаю тот же код, но для менеджера, он, кажется, работает.
manager = soup.find("manager")
Комментарии:
1. Поскольку вы имеете дело с xml, вам, вероятно, лучше использовать синтаксический анализатор xml, такой как lxml.
Ответ №1:
Если структура почти идентична, вы можете попробовать «найти все ()» все элементы given
и проверить, есть ли только один или два.
given= i.find_all('given') fname = given[0] print("Emp_F_Name: ", fname.get_text()) mname = given[1].get_text() if len(given) gt; 1 else None print("Emp_M_Name: ", mname)
Думаю, нет необходимости повторять employee
, но если это так, вам следует использовать свой i
Пример
import requests from bs4 import BeautifulSoup xml='''lt;?xml version="1.0" encoding="utf-8"?gt; lt;org value="Tech"gt; lt;employeegt; lt;namegt; lt;familygt;Joneslt;/familygt; lt;givengt;Jilllt;/givengt; lt;/namegt; lt;/employeegt; lt;managergt; lt;namegt; lt;familygt;Fisherlt;/familygt; lt;givengt;Juniorlt;/givengt; lt;givengt;Hlt;/givengt; lt;/namegt; lt;/managergt; lt;/orggt;''' soup = BeautifulSoup(xml, 'lxml') employee = soup.find("employee") for i in employee.find_all('name'): given= i.find_all('given') fname = given[0] print("Emp_F_Name: ", fname.get_text()) mname = given[1].get_text() if len(given) gt; 1 else None print("Emp_M_Name: ", mname) lname = i.find('family') print("Emp_L_Name: ", lname.get_text())
Выход
Emp_F_Name: Jill Emp_M_Name: None Emp_L_Name: Jones
Alternativ
Изолировать employee
как отдельное дерево для работы с find_next()
:
employee = BeautifulSoup(str(soup.find("employee")), 'lxml') for i in employee.find_all('name'): fname = i.find('given') print("Emp_F_Name: ", fname.get_text()) mname = fname.find_next('given').get_text() if fname.find_next('given') else None print("Emp_M_Name: ", mname) lname = i.find('family') print("Emp_L_Name: ", lname.get_text())
Комментарии:
1. Оба сценария сработали! Это чрезвычайно полезно. Спасибо!
Ответ №2:
Использование синтаксического анализатора XML:(нет необходимости во внешней библиотеке)
import xml.etree.ElementTree as ET xml = '''lt;?xml version="1.0" encoding="UTF-8"?gt; lt;org value="Tech"gt; lt;employeegt; lt;namegt; lt;familygt;Joneslt;/familygt; lt;givengt;Jilllt;/givengt; lt;/namegt; lt;/employeegt; lt;managergt; lt;namegt; lt;familygt;Fisherlt;/familygt; lt;givengt;Juniorlt;/givengt; lt;givengt;Hlt;/givengt; lt;/namegt; lt;/managergt; lt;/orggt;''' attrs = {'Emp_F_Name':'given', 'Emp_L_Name':'family', 'Emp_M_Name': None} root = ET.fromstring(xml) name = root.find('.//name') for k,v in attrs.items(): print(f'{k}: {name.find(v).text if v else None}')
выход
Emp_F_Name: Jill Emp_L_Name: Jones Emp_M_Name: None
Комментарии:
1. Это потрясающе. Спасибо за пример ElementTree!
2. @Jaytee Рад, что мне удалось помочь. Пожалуйста, примите ответ.