使用lxml遍历元素及其子元素
这段内容是给那些真正懂得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
不过,因为你还需要扫描链接,所以这样做其实并没有给你带来什么好处。
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
不过,因为你还需要扫描链接,所以这样做其实并没有给你带来什么好处。