Интерпретация вложенных HTML-блоков в Python?

У меня есть веб-приложение, которое читает из Tumblr API и переформатирует способ форматирования «цепочек реблогов».

В Tumblr комментарии к сообщению хранятся в виде блок-кавычек HTML. Когда пользователи отвечают на комментарий выше, к цепочке цитат добавляется еще один уровень, что в конечном итоге приводит к множеству вложенных цепочек реблогов.


Вот пример того, как «цепочка реблогов» выглядит в простом HTML:

<p><a class="tumblr_blog" href="http://chainsaw-police.tumblr.com/post/96158438802/example-tumblr-post">chainsaw-police</a>:</p><blockquote>

    <p><a class="tumblr_blog" href="http://example-blog-domain.tumblr.com/post/96158384215/example-tumblr-post">example-blog-domain</a>:</p><blockquote>
        <p>Here is an example of a Tumblr post.</p> <p>It can have multiple &lt;p&gt; elements sometimes. It may only have one, though, at other times.</p>
    </blockquote>

    <p>This is an example of a user “reblogging” a post. As you can see, the previous comment is stored above as a &lt;blockquote&gt;.</p>
</blockquote>

<p>This is another reblog. As you can see, all of the previous comments are stored as blockquotes, with earlier ones being residing deeper in the nest of blockquotes.</p>

И вот как это выглядит при рендеринге.


Я хочу иметь возможность переформатировать цепочку реблогов, чтобы она выглядела примерно так:

example-blog-domain: вот пример сообщения Tumblr.

Иногда он может иметь несколько элементов ‹p›. Однако в другое время у него может быть только один.

chainsaw-police: это пример того, как пользователь «реблогирует» сообщение. Как видите, предыдущий комментарий хранится выше как ‹blockquote›.

example-blog-domain: это еще один реблог. Как видите, все предыдущие комментарии хранятся в виде цитат, а более ранние находятся глубже в гнезде цитат.


Я знаю, это невероятно запутанная структура, поэтому я пытаюсь написать что-то, чтобы сделать ее более читабельной.

Есть ли способ интерпретировать HTML и разделить реблоги на отдельные «комментарии»? Например, наличия массива или словаря с именем пользователя и комментарием будет более чем достаточно. Однако, после нескольких месяцев возни с lxml и BeautifulSoup, я в отчаянии.

Если бы был даже способ сделать это в CSS, в чем я очень сомневаюсь, это было бы прекрасно.

Заранее спасибо всем!


person Joshua Merriman    schedule 30.08.2014    source источник
comment
Почему бы не использовать встроенный в python парсер HTML? Вы можете использовать это для преобразования HTML.   -  person Oliver    schedule 30.08.2014
comment
Я уже использовал BeautifulSoup и lxml, но безрезультатно. Не думаю, что дело здесь в инструменте. У меня возникли проблемы с последовательным разделением комментариев и имен пользователей.   -  person Joshua Merriman    schedule 30.08.2014
comment
Итак, вы хотите изменить структуру HTML? Если да, можете ли вы опубликовать структуру до и после с минимальным количеством шума (например, вы можете поставить ... для ссылки, поскольку содержание ссылки не имеет значения; то же самое касается текста, только текст, поэтому он короткий, и мы можем см. структуру). Также вы должны описать хотя бы одну вещь, которую вы пробовали, чтобы мы могли понять, почему это не сработало. Если вы не сохранили его, попробуйте еще раз и добавьте в свой пост.   -  person Oliver    schedule 30.08.2014


Ответы (2)


Я думаю, что CSS не имеет такой функциональности. Вам нужно проанализировать структуру с помощью lxml, ... и отобразить ее. Это более легкий способ. Вы также можете создать фильтр с помощью регулярного выражения, который не пропускает неправильные элементы html-кода.

person Victor Shelepen    schedule 30.08.2014
comment
Я уже пытался использовать lxml и регулярное выражение, и у меня нет идей. И я подумал, что с помощью CSS я смогу изменить положение блок-кавычек, чтобы они больше походили на то, что я хочу. - person Joshua Merriman; 30.08.2014
comment
У меня ничего не сохранилось, так как все они ужасно провалились. - person Joshua Merriman; 30.08.2014

пользователь Reddit /u/joyeusenoelle ответил на мой вопрос по адресу / r/LearnPython с использованием тонны запутанных регулярных выражений, которые в конечном итоге больше похожи на магическое заклинание вуду, чем на сценарий манипулирования текстом.

Много регулярных выражений позже, я думаю, что решил это для сколь угодно глубокой цепочки комментариев.

import re

with open("tcomment.txt","r") as tf:
    text = ""
    for line in tf:
        text += line
tf.close()
text = text.replace("\n","")
text = text.replace(">",">\n")
text = text.replace("<","\n<")
text = re.sub("</p>\s*<p>","<br><br>", text)
text = text.replace("<p>\n", "")
text = text.replace("</p>\n","\n")
text = re.sub("<[/]{0,1}blockquote>","<chunk>",text)
text = re.sub("<a class=\"tumblr_blog\"[^>]+?>","<chunk>",text)
text = text.replace("</a>","")
text = re.sub("\n+","", text)
text = re.sub("\s{2,}"," ", text)
text = re.sub("<chunk>\s*<chunk>","<chunk>",text)
bits = text.split("<chunk>")
bits[0] = "Latest:"
comments = []
for i in range(len(bits)):
    temp = ""
    j = 0 - (i+1)
    if (len(bits)-i) > i:
        temp = "<b>" + bits[i] + "</b> " + bits[j]
        comments.append(temp)

comments.reverse()
for comment in comments:
    print("<p>%s</p>" % (comment))
    print()

Строка bits[0] = "Latest:" может быть изменена на то, что вы хотите, чтобы отображался самый последний комментарий, и вы, вероятно, захотите изменить способ ввода текста в скрипт.

Для предоставленного вами текста это дает мне:

<p><b>example-blog-domain:</b>  Here is an example of a Tumblr post.<br><br>It can have multiple &lt;p&gt; elements sometimes. It may

есть только один, хотя, в другое время.

<p><b>chainsaw-police:</b>  This is an example of a user "reblogging" a post. As you can see, the previous comment is stored

выше как ‹блок-цитата›.

<p><b>Latest:</b> This is another reblog. As you can see, all of the previous comments are stored as blockquotes, with earlier ones

находясь глубже в гнезде блок-кавычек.

e: Некоторые мысли: это в Python 3, но все, кроме операторов печати, должно работать в Python 2, я думаю. Я использовал text.split(), когда это было возможно, потому что прямая работа со строками обычно быстрее, чем регулярные выражения, но здесь это может быть неуместно. И, наконец, возможно, я делаю для себя больше работы, чем мне нужно, в разделе замен, но на данный момент я слишком долго просматривал код, чтобы понять, можно ли его похудела.

person Joshua Merriman    schedule 31.08.2014