【问题标题】:lxml-alternative for a BS-codelxml-alternative 用于 BS 代码
【发布时间】:2013-09-02 00:13:31
【问题描述】:

我有以下代码:

soup = BeautifulSoup(text)
for elem in soup.find_all('span', 'finereader'):
    elem.replace_with(elem.string or '')

我想使用 lxml,因为我无法使用 BS 产生的缩进。 是否有任何使用 lxml 的等效代码?或者BS的缩进怎么可以省略?

非常感谢您的帮助:)

编辑: BS 产生如下输出:

<html>
 <body>
  <table border="0" cellpadding="0" cellspacing="0" class="main" frame="box" rules="all" style="table-layout:fixed; width:324.72pt; height:518.64pt;">
   <tr class="row">
    <td class="cell" style=" width:0.00pt; height:0.00pt;" valign="top">
    </td>
    <td class="cell" style=" width:169.44pt; height:0.00pt;" valign="top">
    </td>

但我想要这样的输出:

<html>
<body>
<table border="0" cellpadding="0" cellspacing="0" class="main" frame="box" rules="all" style="table-layout:fixed; width:324.72pt; height:518.64pt;">
<tr class="row">
<td class="cell" style=" width:0.00pt; height:0.00pt;" valign="top">
</td>
<td class="cell" style=" width:169.44pt; height:0.00pt;" valign="top">
</td>

编辑: 目前,我的整个代码看起来像这样。

output = codecs.open("test.html", "a", "utf-8")

def myfunct():
    for i in range(1, 11):

        root = lxml.html.parse('http://xyz.xy'+str(nr)+'?action=source').getroot()

        for elem in root.xpath("//span[@class='finereader']"):
                text = (elem.text or "") + (elem.tail or "")
            if elem.getprevious(): # If there's a previous node
                previous = elem.getprevious()
                previous.tail = (previous.tail or "") + text # append to its tail
            else:
                 parent = elem.getparent() # Otherwise use the parent
                 parent.text = (parent.text or "") + text # and append to its text
            elem.getparent().remove(elem)

        for empty in root.xpath('//*[self::b or self::i][not(node())]'):
            empty.getparent().remove(empty)

        tables = root.cssselect('table.main') #root.xpath('//table[@class="main" and not(ancestor::table[@class="main"])]') #
        tables = root.xpath('//table[@class="main" and not(ancestor::table[@class="main"])]')

        txt = []

        txt += ([lxml.html.tostring(t, method="html", encoding="utf-8") for t in tables])

        text = "\n".join(re.sub(r'\[:[\/]?T.*?:\]', '', el) for el in txt) #.splitlines())

        output.write(text.decode("utf-8"))

【问题讨论】:

  • “缩进”是什么意思?你有什么问题?
  • 我指定了问题。
  • 如果我的回答有帮助,请告诉我... lxml 有时可能很挑剔。
  • 您的回答非常有帮助,请参阅 cmets。非常感谢! :)

标签: python beautifulsoup lxml


【解决方案1】:

要解析,请创建一个lxml.etree.HTMLParser 并使用lxml.etree.fromstring:

import lxml.etree

parser = lxml.etree.HTMLParser()
html = lxml.etree.fromstring(text, parser)

您现在可以使用 xpath 来选择您想要的东西:

for elem in html.xpath("//span[@class='finereader']"):

那么,由于 lxml 不允许你添加文本节点,而是处理节点的 text 和 tail 内容,我们必须做一些魔术来用字符串替换节点:

    text = (elem.text or "") + (elem.tail or "")
    if elem.getprevious() is not None: # If there's a previous node
        previous = elem.getprevious()
        previous.tail = (previous.tail or "") + text # append to its tail
    else:
        parent = elem.getparent() # Otherwise use the parent
        parent.text = (parent.text or "") + text # and append to its text
    elem.getparent().remove(elem)

然后,您可以使用lxml.etree.tostring(html) 获取文本。

【讨论】:

  • 非常感谢这段代码!它部分工作。如果我正确实现了代码,它确实会删除“”的所有外观。但不幸的是,如果我有类似的内容:“text1...一些其他文本text2...”,上面的代码将返回以下内容:“text1.. ."。但我应该保留(直接附加)“其他一些texttext2 ...”。如何做到这一点?
  • 也许 strip_tags() 是一种可能性?
  • @MarkF6 糟糕,我的代码中有错字,我忘了添加!现在就试试。此外,&lt;span class="finereader"&gt; 中是否会有任何标签?
  • 不,如果有的话,那只是字母或数字。我现在试试。 Maaan ...我也应该看到错字:(
  • 该代码适用于 95% :)。代码有一些问题的特殊情况:如果我有这样的事情:“TEXT1 TEXT2LETTER1 TEXT3LETTER2 TEXT4”,代码返回:“TEXT1 LETTER2 TEXT4”。我们如何处理这种情况?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-11-07
  • 1970-01-01
  • 2023-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多