Найти - Пользователи
Полная версия: lxml + xpath + <p>
Начало » Python для новичков » lxml + xpath + <p>
1
kappa-sama
Народ, подскажите…

На странице есть тег <p> вида:

<p xmlns="http://www.w3.org/1999/xhtml">Текст<br/>Текст2<br/>Текст3 и т.д.<br/><p>

сам тег я вытаскиваю с помощью lxml + xpath
doc = lxml.html.document_fromstring(getPage(URL,getCookies(PARAMETERS)))
pages = doc.xpath(PATHPOSTBOX)

Собственно, проблема:
Как вывести содержимое тега? Я пробовал через
pages[0].text
- в этом случае он выводит только до первого “<br/>” (В данном примере только - “Текст”)
reclosedev
pages[0].text_content()
Но тогда <br/> будут удалены совсем. Нужно их заменить на ‘\n’ до передачи в lxml.
Или еще есть вариант
texts = doc.xpath('НЕИЗВЕСТНО//text()') 
text = '\n'.join(texts)
но если внутри кроме <br/> есть какие-то тэги, то все будет поделено ‘\n’.
odnochlen
Тоже как раз возился с этой темой. .text - текст внутри тега. Просто текст вводится через tag.tail, tag - идущий перед текстом тег.
Т.е. как я понимаю, весь текст должен быть доступен или через .text, или через .tail.

lxml, видимо, интерпретирует дерево так:

p--| text = "текст1"
br tail = "тескт2"
br tail = "текст3"

Какая-то слишком сложная и ублюдошная эта lxml. Сидишь над ней и думаешь - может ну его нах и уже регекспами все сделать?

Из последнего - как сделать, чтобы подряд шли не больше 2 тегов <br> без текста после тега? В конце концов загнал дерево в строку и прошелся регекспом - и все.
kappa-sama
reclosedev
Спасибо, второй вариант - то что нужно.

odnochlen
Я тоже уже об этом подумывал, но, к счастью, обошлось)
odnochlen
Тогда я свое здесь оставлю.

Как удалить определенную разметку и оставить текст? Например, таблицы?

Как заменить больше 2 <br> подряд без текста между ними? Регекспами - элементарно.

В чем разница между Element и lxml.etree._ElementTree и почему parse() возвращает tree, а document_fromstring() - корневой Element?

Это баг?
from lxml.html import builder as E
print lxml.etree.tostring(E.HTML(E.BR(), E.BR()))
# <html><br/><br/></html>
br = E.BR()
print lxml.etree.tostring(E.HTML(br, br))
# <html><br/></html>

Можно сделать как-то так?
E.BR(tail='text')
reclosedev
odnochlen
Как удалить определенную разметку и оставить текст? Например, таблицы?

Как заменить больше 2 <br> подряд без текста между ними? Регекспами - элементарно.
# -*- coding: utf-8 -*-
import lxml.html
from lxml.html.clean import Cleaner
 
html = """
<html>
<body>
    <div id="remove_table">
        before table
        <table>
            <tr>
                <td>11</td>
                <td>12</td>
            </tr>
            <tr>
                <td>21</td>
                <td>22</td>
            </tr>
        </table>
        after table
    </div>
    <div id="remove_br">
        line1<br/>
        line2<br/>
        text
        <br/><br/><br/>
    </div>
</body>
</html>
"""
# Как удалить определенную разметку и оставить текст? Например, таблицы?
cleaner = Cleaner(remove_tags=['table', 'td', 'tr'])
print cleaner.clean_html(html)
 
# Как заменить больше 2 <br> подряд без текста между ними? 
doc = lxml.html.fromstring(html)
elements = doc.xpath('//br[count(preceding-sibling::br) >= 2]')
for el in elements:
    if not el.tail:
        el.getparent().remove(el)
print lxml.html.tostring(doc)
odnochlen
В чем разница между Element и lxml.etree._ElementTree и почему parse() возвращает tree, а document_fromstring() - корневой Element?
http://lxml.de/tutorial.html#the-elementtree-class
An ElementTree is mainly a document wrapper around a tree with a root node. It provides a couple of methods for parsing, serialisation and general document handling. One of the bigger differences is that it serialises as a complete document, as opposed to a single Element. This includes top-level processing instructions and comments, as well as a DOCTYPE and other DTD content in the document

odnochlen
Это баг?
Наверное нет, нужно новый элемент создавать.

odnochlen
Можно сделать как-то так?
E.BR(tail='text')
в конструкторе текст, аттрибуты или дети, придется писать на строчку больше
br = E.BR()
br.tail = 'text'

odnochlen
Сидишь над ней и думаешь - может ну его нах и уже регекспами все сделать?
В ситуации когда регекспы проще и понятней, почему бы их не использовать?

upd: if not el.tail
Согласен, что br проще регекспом, только для универсальности нужно будет учитывать разные варианты написания br: <br>, <br/>, <br />, </br>. Хотя можно перед заменой нормализовать все с помощью lxml.html.tostring.
odnochlen
reclosedev
в конструкторе текст, аттрибуты или дети, придется писать на строчку больше
В таком случае - ощутимо больше.
lxml.etree.tostring(E.HTML(
                                      E.BR(), E.BR()
))
reclosedev
odnochlen
В таком случае - ощутимо больше.
Если реальная необходимость есть, можно функцию-помощник написать: def BR(tail=''): …
odnochlen
reclosedev
elements = doc.xpath('//br[count(preceding-sibling::br) >= 2]')
Интересно, но я до этого еще не дошел. Как я понял, на отсутствие текста между br оно не проверяет?

reclosedev
http://lxml.de/tutorial.html#the-elementtree-class
An ElementTree is mainly a document wrapper around a tree with a root node. It provides a couple of methods for parsing, serialisation and general document handling. One of the bigger differences is that it serialises as a complete document, as opposed to a single Element. This includes top-level processing instructions and comments, as well as a DOCTYPE and other DTD content in the document
Это не совсем ответ на мой вопрос.

Как я уже понял методом тыка, через Element можно итерировать только по детям (через .iter() или foreach), а через tree - по всему дереву (через .iterchildren()). xpath есть и там, и там.

reclosedev
odnochlen
Это баг?
Наверное нет, нужно новый элемент создавать.
И это можно узнать опять же методом тыка.

reclosedev
Согласен, что br проще регекспом
Ну вот, а то чуть что, так сразу дают ссылку.
odnochlen
reclosedev
br = E.BR()
br.tail = 'text'
С хвостом проще, но аттрибуты - только через костыли.
E.BR(), text, E.BR()
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB