الحصول على نص غير متجانس مع LXML / ElementTree
-
02-10-2019 - |
سؤال
لنفترض أن لدي هذا النوع من HTML الذي أحتاج منه لتحديد "Text2" باستخدام LXML / ElementTree:
<div>text1<span>childtext1</span>text2<span>childtext2</span>text3</div>
إذا كان لدي بالفعل عنصر DIV كـ MyDiv ، فإن MyDiv.Text يعيد فقط "Text1".
يبدو استخدام itertext () مشكلة أو مرهقة في أحسن الأحوال لأنه يمشي الشجرة بأكملها تحت Div.
هل هناك أي طريقة بسيطة/أنيقة لاستخراج جزء من النص غير الأول من عنصر؟
المحلول
حسنًا ، يوفر LXML.etree دعم XPATH الكامل ، والذي يتيح لك معالجة عناصر النص:
>>> import lxml.etree
>>> fragment = '<div>text1<span>childtext1</span>text2<span>childtext2</span>text3</div>'
>>> div = lxml.etree.fromstring(fragment)
>>> div.xpath('./text()')
['text1', 'text2', 'text3']
نصائح أخرى
سيكون مثل هذا النص في tail
سمات أطفال العنصر الخاص بك. إذا كان عنصرك في elem
ومن بعد:
elem[0].tail
سوف يعطيك نص الذيل للطفل الأول داخل العنصر ، في حالتك "text2"
أنت تبحث عن.
كما قال Llasram ، أي نص ليس في text
ستكون السمة في tail
سمات العقد الفرعية.
على سبيل المثال ، إليك أبسط طريقة للاستخراج الكل من قطع النص (أولاً وغيرها) في العقدة:
html = '<div>text1<span>childtext1</span>text2<span>childtext2</span>text3</div>'
import lxml.html # ...or lxml.etree as appropriate
div = lxml.html.fromstring(html)
texts = [div.text] + [child.tail for child in div]
# Result: texts == ['text1', 'text2', 'text3']
# ...and you are guaranteed that div[x].tail == texts[x+1]
# (which can be useful if you need to access or modify the DOM)
إذا كنت تفضل التضحية بهذه العلاقة من أجل منع texts
من احتواء سلاسل فارغة ، يمكنك استخدام هذا بدلاً من ذلك:
texts = [div.text] + [child.tail for child in div if child.tail]
لم أختبر هذا مع elementtree القديم البسيط ، لكن يجب أن يعمل مع ذلك أيضًا. (شيء لم يحدث لي إلا بمجرد أن رأيت محلول LXML الخاص بشين هولواي) أنا أفضل فقط LXML لأنه يحصل على دعم أفضل لـ HTML IDEOSYNCRACIS lxml.html.clean
يستخدم node.text_content()
للحصول على كل النص أسفل العقدة كسلسلة واحدة.