我们有一个最多2000个术语的词汇表(每个词汇表术语可以 由一个,两个或三个单词组成(用空格分隔 或短划线)。
现在我们正在寻找突出显示内部所有术语的解决方案 (更长)HTML文档(最多100 KB的HTML标记)以便 使用突出显示的术语生成静态HTML页面。
工作解决方案的限制因素是:大量词汇表术语 和长HTML文档......什么是有效解决方案的蓝图 (在Python中)。
现在我正在考虑使用lxml解析HTML文档,迭代所有文本节点,然后将每个文本节点中的内容与所有术语表术语进行匹配。
客户端(浏览器)动态突出显示不是一个选项,因为IE会抱怨脚本超时的长时间运行脚本...因此无法用于生产。
有更好的主意吗?
答案 0 :(得分:2)
您可以使用解析器以递归方式导航树,并仅替换由文本组成的标记。
在这样做时,您仍需要考虑以下几项事项:
- 并非所有文本都需要替换(例如内联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')
这应该用“b”替换“a”的任何出现,但留下的内容是:
- 内联内嵌javascript或css(尽管内联JS或CSS不应出现在文档的正文中)
- 标签中的引用,例如img,a ...
- 标签本身
当然,根据您的词汇表,您需要确保不要仅用其他内容替换部分单词;要做到这一点,使用内容的正则表达式是有意义的。
答案 1 :(得分:0)
我认为使用客户端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)
})
如果您有疑问,请告诉我。
答案 2 :(得分:-1)
如何浏览词汇表中的每个术语,然后对于每个术语,使用正则表达式查找HTML中的所有匹配项?您可以使用包含在带有“突出显示”类的范围中的术语替换每个匹配项,这些类将被设置为具有背景颜色。