使用lxml遍历元素及其子元素

1 投票
1 回答
3913 浏览
提问于 2025-04-17 13:59

这段内容是给那些真正懂得lxml的人看的。我有一个网页抓取的应用程序,我想在一个网站上遍历多个div.content(content是类名)标签。一旦进入一个div.content标签,我想看看里面是否有任何<a>标签是<h3>元素的子标签。这个看起来相对简单,只需要用XPath从div.content标签创建一个列表就可以了,也就是:

linkList = tree.xpath('div[contains(@class,"cont")]//h3//a')

问题是,我还想创建一个tuple,这个元组里包含了来自div.content框的链接,以及同一个div.content框里的段落元素的文本。显然,我可以遍历整个文档,把所有的段落文本和链接都存起来,但这样我就没办法把合适的段落和<a>标签对应起来了。

lxml的Element.iter()函数几乎可以做到这一点,它可以遍历所有的div.cont元素,忽略那些没有<a>标签的,然后把段落/a组合在一起,但不幸的是,这个方法似乎只能按标签名遍历,而不能按类名遍历。

补充说明:这是我想解析的HTML的一个非常简化的版本:

<body>
<div class="cont">
    <h1>Random Text</h1>
    <p>The text I want to obtain</p>
    <h3><a href="somelink">The link I want to obtain</a></h3>
</div>
</body>

我想处理的div.cont标签有很多,虽然大多数的元素比这个要多得多,但这只是一个草图,让你大致了解我在处理什么。

1 个回答

3

你可以使用一个不那么具体的XPath表达式:

for matchingdiv in tree.xpath('div[contains(@class,"cont")]'):
    # skip those without a h3 > a setup.
    link = matchingdiv.xpath('.//h3//a')
    if not link:
        continue

    # grab the `p` text and of course the link.

你可以更进一步(大胆一点),选择

标签下的标签,然后再找到它的父元素
(这个是基于使用后代和后代文本的XPath查询的思路):

for matchingdiv in tree.xpath('.//h3//a/ancestor::*[self::div[contains(@class,"cont")]]'):
    # no need to skip anymore, this is a div.cont with h3 and a contained
    link = matchingdiv.xpath('.//h3//a')

    # grab the `p` text and of course the link

不过,因为你还需要扫描链接,所以这样做其实并没有给你带来什么好处。

撰写回答