【问题标题】:How to find text in specific nested tag wih lxml and python?如何使用 lxml 和 python 在特定的嵌套标签中查找文本?
【发布时间】:2015-03-06 21:03:45
【问题描述】:

假设html源码如下:

<html><body>
<div class="aname">
    <div class="bname">
        <h5><a href="url_a0" class="cname">aTitle</a></h5>
    </div>
    <div class="">
        <div><img src="url_a1"/>img_text<br /></div>
        <div><strong>label_a1:</strong>text_a1<br /></div>
        <div><strong>label_a2:</strong>text_a2<br /></div>
        <div><strong>label_spe:<a href="url_a2">*</a>:</strong>
            <span class="box-span" >spantext_a1</span>
            <span class="box-span" >spantext_a2</span>
            <span class="box-span" >spantext_a3</span><br />
        </div>              
    </div>
</div>

<div class="aname">
    <div class="bname">
        <h5><a href="url_a0" class="cname">aTitle</a></h5>
    </div>
    <div class="">
        <div><img src="url_a1"/>img_text<br /></div>
        <div><strong>label_a1:</strong>text_b1<br /></div>
        <div><strong>label_a2:</strong>text_b2<br /></div>
        <div><strong>label_a3:</strong>text_b3<br /></div>
        <div><strong>label_spe:<a href="url_b3">*</a>:</strong>
            <span class="box-span" >spantext_b1</span>
            <span class="box-span" >spantext_b2</span>
            <span class="box-span" >spantext_b3</span>
            <span class="box-span" >spantext_b4</span>
            <span class="box-span" >spantext_b5</span>
            <span class="box-span" >spantext_b6</span><br />
        </div>              
    </div>
</div>
</body></html>

如果我想要输出是:

aTitle
url_a0
label_a1:
text_a1
label_a2:
text_a2
label_spe:
spantext_a1
spantext_a2
spantext_a3

aTitle
url_a0
label_a1:
text_b1
label_a2:
text_b2
label_a3:
text_b3
label_spe:
spantext_b1
spantext_b2
spantext_b3
spantext_b4
spantext_b5
spantext_b6

我想在 python 中使用 lxml!请帮助我,我该怎么办? 由于 html 有多个 div,并且 span 的数量是可变的。 我已经尝试了很多次,但仍然无法获得正确的输出。 最后,我希望我能从这里得到一些有用的信息!! 我的代码如下:

# -*- coding:utf-8 -*-
import codecs
import lxml,re
import re
from lxml import etree
from lxml.html.clean import Cleaner

def main():
    pass

if __name__ == '__main__':
    main()

ff = codecs.open('test.html','r',errors='ignore',encoding='utf-8')

    html0 = ff.read()
    html1 = re.sub('<strong>', '',html0)
    html2 = re.sub('</strong>','',html1)
    html  = re.sub('class=\"box-span\"','',html2)

    spelabels = ['img_text', 'label_a1', 'label_a2', 'label_a3']

    root = lxml.html.fromstring(html)
    contents = root.xpath('.//div[@class="aname"]/div[@class=""]/div/text()')
    for content in contents:
         if content[0:8] in spelabels:
              print(content[0:8])
              print(content[9:])
         elif content == "label_spe:":
              print(content)
              nestedcontents = root.xpath('.//div[@class="aname"]/div[@class=""]/div[text()="label_spe:"]/following-sibling::span/text()')          
              print(nestedcontents)
              for nestedcontent in nestedcontents:
                   print(nestcontent)       

输出:

img_text

label_a1
text_a1
label_a2
text_a2
label_spe:
[]
img_text

label_a1
text_b1
label_a2
text_b2
label_a3
text_b3
label_spe:
[]

它似乎部分工作,但我不知道如何提取 url_a1。 span中的文字没有出现”

【问题讨论】:

    标签: python-3.x lxml


    【解决方案1】:

    这是我的尝试。它为您的样本输入提供所需的输出。我让它容忍某些标签更改,例如 divspan

    import xml.etree.cElementTree as etree # or: from lxml import etree
    
    body = etree.parse('test.html').find('body')
    
    for aname in body.iterfind('*[@class="aname"]'):
        cname = aname.find('*[@class="bname"]//a[@class="cname"]')
        print cname.text # title
        print cname.get('href') # url
    
        for div in aname.iterfind('div[@class=""]/div'):
            strong = div.find('strong')
            if strong is not None:
                print strong.text # label
                text = div[0].tail.strip() # http://stackoverflow.com/a/9674097/4323
                if text:
                    print text
                else:
                    for box in div.iterfind('*[@class="box-span"]'):
                        print box.text
    
        print
    

    【讨论】:

    • 太棒了!有用!!非常感谢!!我是编码界的新手。
    • 我将你的方式应用到我的程序并修改如下:ff = codecs.open('test.html',mode='r',errors='ignore',encoding=' utf-8') html = ff.read() body = etree.parse(html).find('body'),但出现error === > Traceback (last recent call last): File " ”,第 250 行,在 run_nodebug 文件“E:\Python\test1.py”中,第 24 行,在 body = etree.parse(html).find('body') 文件“”中,第62行,解析文件“”,第26行,解析IOError:[Errno 2]没有这样的文件或目录:(输出整个test1.html源),你能告诉我,怎么了?跨度>
    • @NormanWeng:那是因为parse() 采用文件名,而不是像您现在传递它的文件内容。你想要fromstring() 而不是parse()
    • 非常感谢您的回复。我应用您的代码并将文件名从 test.html 更改为 test1.html。出现错误消息:lxml.etree.XMLSyntaxError: EntityRef: expecting ';', line 31, column 71,。我将文件名更改为另一个 html 文件,然后我收到相同的错误消息。有什么问题?我该怎么办?
    • 我发现 html 源文件包含   这会导致错误,所以我使用 re.sub(' ','',html) 并更改 text = div[0].tail.strip() to text = div[0].tail ==> 终于成功了!!!
    【解决方案2】:
    import re
    file1 = open("input.txt",'r')
    
    for lines in file1:
        match = re.findall(">\w*:*<", lines)
        for ele in match:
    
           a = ele.split('>')
           for ele1 in a:
             b = ele1.split('<')
             for i in b:
               if i and (i !=":"):
                print i
    

    输出:

    aTitle
    img_text
    label_a1:
    text_a1
    label_a2:
    text_a2
    label_spe:
    spantext_a1
    spantext_a2
    spantext_a3
    aTitle
    img_text
    label_a1:
    text_b1
    label_a2:
    text_b2
    label_a3:
    text_b3
    label_spe:
    spantext_b1
    spantext_b2
    spantext_b3
    spantext_b4
    spantext_b5
    spantext_b6
    

    【讨论】:

    • 哇!!多么漂亮的代码啊!!非常感谢!!效果很好!
    • 很高兴听到这个消息。请关闭问题。
    • @NormanWeng:这段代码可能很漂亮,但从根本上来说也是错误的做事方式。请阅读我在上述评论中发布的链接,了解为什么使用正则表达式解析 HTML 不是一个好计划……或阅读数十篇相同的博客文章中的任何一篇。在你不去之后维护这段代码的人有好话要说。
    • @John Zwinck:感谢您的大力帮助。我已阅读您发布的链接。正如我提到的,我是编码世界的新手。我还有很多东西要学。任何短而美的东西都会很快引起我的注意。但是,我在我的情况下采用你的方式,因为真正的 html 源代码更复杂。无论如何,谢谢你的好意建议。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-09
    • 1970-01-01
    • 2018-10-11
    • 1970-01-01
    相关资源
    最近更新 更多