在 Python 中使用 XPath

作者: 焉知非鱼 | 来源:发表于2016-09-22 00:12 被阅读4926次

    根据字节点中的属性值提取父节点

    </br>

    今天使用 Python 的 lxml 模块来提取网页中的内容, 有一个 XPath 的用法不明白, 问题是, table 子节点下有一系列 tr 子节点, 每个 tr 子节点里有 3 列 (td), 如果 td 中 style 属性的值为 color: 0, 那么就不提取它所属的这一 tr 子节点。

    查了很久 stackoverflow 才解决, 方法一:

    from lxml import etree
    
    html = '''
    <html>
    <table>
    <tr id="id_l107" class="new nick nick_cxreg">
        <td class="time" ><a href="/perl6/2016-09-21>05:07</a></td>
        <td style="color: #8d8100" class="nick">cxreg</td>
        <td class="msg">probably useful</a></td>
    </tr>
        
    <tr id="id_l108" class="new nick nick_mask">
        <td class="time" ><a href="/perl6/2016-09-21>05:09</a></td>
        <td style="color: #8d8100" class="nick">mask</td>
        <td class="msg">maybe better directed at <a href="/moarvm/today">#moarvm</a></td>
    </tr>
    
    <tr id="id_l74" class="cont special dark">
        <td class="time" ><a href="/perl6/2016-09-21>02:37</a></td>
        <td style="color: 0" class="nick"></td>
        <td class="msg">mcmillhj joined <a href="/perl6/today">#perl6</a></td>
    </tr>
    <table>
    </html>
    '''
    
    
    selector = etree.HTML(html)
    content = selector.xpath('//tr[descendant::td[@style!="color: 0"]]/td/text()')
    
    for each in content:
        print(each)
    

    打印出:

    cxreg
    probably useful: 
    mask
    maybe better directed at 
    

    说明得到我们想要的结果了。怎么验证我们取得的是两个 tr 呢?

    content = selector.xpath('//tr[descendant::td[@style!="color: 0"]]')
    

    打印出

    <Element tr at 0x139c3b0>
    <Element tr at 0x139c368>
    

    说明的确提取出了 2 个 tr 元素。descendant 是后代的意思。上面那句代码意思是

    过滤 tr 元素, 如果 tr 的后代元素 td 的属性 style 值不为 "color: 0", 那么就提取这个 tr 子节点。否则不提取。

    方法二,先过滤掉 td 然后使用 .. 语法返回到父级元素:

    content = selector.xpath('//tr/td[starts-with(@style,"color: #")]/../td/text()')
    

    这里找到 td 元素中属性以 color: #开头的 td (过滤掉了 color: 0 这样的 td), 然后使用 .. 语法得到只含有 color: # 子元素的 tr 父节点。以上两种方法异曲同工, 殊途同归。并且方法二最后得到的也是两个 tr 元素:

    content = selector.xpath('//tr/td[starts-with(@style,"color: #")]/..')
    

    打印:

    <Element tr at 0x222f170>
    <Element tr at 0x222f198>
    

    程序最后主要代码如下:

    content = selector.xpath('//tr[descendant::td[@style!="color: 0"]]')
    for each in content:
        info = each.xpath('string(.)')
        msg = info.replace('\n', '')
        print(msg)
        print('-' * 85)
    
    xpath.png

    lxml 的安装

    </br>
    关于 lxml 的安装, Python 2.7 以下的就不说了, 说下 Python 3 下怎么安装 lxml:

    Windows 7 32bit/64bit 系统下直接使用 pip install lxml 会提示 lxml Unable to find vcvarsall.bat。 我们采用本地安装, 线安装 wheel 模块:

    pip install wheel
    

    然后到模块仓库pythonlibs (相当于 Perl 的 metacpan)下载 lxml, 我下载的是 lxml-3.6.4-cp35-cp35m-win32.whl(即使你是 64 bit的系统)。然后在该文件所在目录下执行

    pip install  lxml-3.6.4-cp35-cp35m-win32.whl
    

    这样就安装成功了。如下图所示

    result.png

    Ubuntu 系统下你需要先安装依赖包:

    sudo apt-get libxml2, libxml2-devel, libxlst, libxlst-devel, python-libxml2, python-libxslt
    

    然后再安装

    pip install lxml
    

    相关文章

      网友评论

        本文标题:在 Python 中使用 XPath

        本文链接:https://www.haomeiwen.com/subject/vcxzettx.html