Выделение терминов словаря в документе HTML - PullRequest
1 голос
/ 03 декабря 2011

У нас есть глоссарий до 2000 терминов (где каждый термин глоссария может состоят из одного, двух или трех слов (либо разделенных пробелами или тире).

Теперь мы ищем решение для выделения всех терминов внутри (более длинный) HTML-документ (до 100 КБ разметки HTML) для создать статическую HTML-страницу с выделенными терминами.

Ограничения для рабочего решения: большое количество терминов глоссария и длинные HTML-документы ... что будет основой для эффективного решения (внутри Python).

Сейчас я думаю о синтаксическом анализе документа HTML с использованием lxml, итерации по всем текстовым узлам, а затем сопоставлении содержимого каждого текстового узла со всеми терминами глоссария.

Подсветка на стороне клиента (в браузере) не доступна, поскольку IE будет жаловаться на долго выполняющиеся скрипты с тайм-аутом скрипта ... так что он непригоден для производственного использования.

Есть идея получше?

Ответы [ 3 ]

2 голосов
/ 03 декабря 2011

Вы можете использовать синтаксический анализатор для рекурсивной навигации по дереву и замены только тегов, которые сделаны из текста.
При этом есть еще несколько вещей, которые вам необходимо учитывать:
- Не весь текст необходимо заменить (например, встроенный JavaScript)
- Некоторые элементы документа могут не нуждаться в разборе (например, заголовки и т. Д.)

Вот быстрый и непроизводственный готовый пример того, как вы могли бы достичь этого:

html = """The HTML you need to parse"""
import BeautifulSoup

IGNORE_TAGS = ['script', 'style']

def parse_content(item, replace_what, replace_with, ignore_tags = IGNORE_TAGS):
    for content in item.contents:
        if isinstance(content, BeautifulSoup.NavigableString):
            content.replaceWith(content.replace(replace_what, replace_with, ignore_tags))
        else:
            if content.name not in ignore_tags:
                parse_content(content, replace_what, replace_with, ignore_tags)
    return item

soup = BeautifulSoup.BeautifulSoup(html)
body = soup.html.body
replaced_content = parse_content(body, 'a', 'b')

Это должно заменить любое вхождение "a" на "b", однако оставляя содержимое, которое:
- Внутри встроенного JavaScript или CSS (хотя встроенные JS или CSS не должны появляться в теле документа).
- Ссылка в теге, например, img, a ...
- сам тег

Конечно, вам, в зависимости от вашего глоссария, потребуется убедиться, что вы не заменяете только часть слова чем-то другим; Для этого имеет смысл использовать регулярное выражение для content.replace.

0 голосов
/ 03 декабря 2011

Я думаю, что выделение с помощью клиентского JavaScript - лучший вариант. Это экономит ваше время обработки сервера и пропускную способность, и, что более важно, сохраняет HTML чистым и удобным для тех, кому не нужна ненужная разметка, например, при печати или преобразовании в другие форматы.

Чтобы избежать тайм-аутов, просто разбейте работу на куски и обрабатывайте их один за другим в поточной функции setTimeout. Вот пример такого подхода

function hilite(terms, chunkSize) {

    // prepare stuff

    var terms = new RegExp("\\b(" + terms.join("|") + ")\\b", "gi");

    // collect all text nodes in the document

    var textNodes = [];
    $("body").find("*").contents().each(function() {
        if (this.nodeType == 3)
            textNodes.push(this)
    });

    // process N text nodes at a time, surround terms with text "markers"

    function step() {
        for (var i = 0; i < chunkSize; i++) {
            if (!textNodes.length)
                return done();
            var node = textNodes.shift();
            node.nodeValue = node.nodeValue.replace(terms, "\x1e$&\x1f");
        }
        setTimeout(step, 100);
    }

    // when done, replace "markers" with html

    function done() {
        $("body").html($("body").html().
            replace(/\x1e/g, "<b>").
            replace(/\x1f/g, "</b>")
        );
    }

    // let's go

    step()
}

Используйте это так:

$(function() {
    hilite(["highlight", "these", "words"], 100)
})

Дайте мне знать, если у вас есть вопросы.

0 голосов
/ 03 декабря 2011

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

...