rvest与bs4如何根据嵌套子元素过滤网页超链接节点
根据子元素类型过滤超链接的实现方法
rvest和BeautifulSoup4都支持基于子节点特征筛选元素,不需要依赖父级标签的class、id等属性,具体实现如下:
R(rvest)实现
rvest底层依托libxml2解析引擎,原生支持XPath选择器,可以直接通过XPath谓语规则写筛选逻辑,不需要先全选a标签再循环过滤。
核心XPath规则说明:
//a:匹配页面所有a标签[.//h3]:限定a标签的后代节点中存在h3标签[not(.//img)]:限定a标签的后代节点中不存在img标签
替换原有选择逻辑的完整可运行代码:
library(rvest) library(magrittr) html <- '<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div> <div> <div> <a href="https://upload.wikimedia.org/wikipedia/commons/thumb/e/e0/SNice.svg/1200px-SNice.svg.png"> <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/e0/SNice.svg/1200px-SNice.svg.png" style="max-width:72px;max-height:72px"> </a> </div> <span> <h3> <div> Smiley Face </div> </h3> </span> <span> <div> https://upload.wikimedia.org/wikipedia/commons/thumb/e/e0/SNice.svg/1200px-SNice.svg.png </div> </span> </div> </div> <div> <div> <a href="https://www.hbs.edu"> <h3> <div>Harvard Business School</div> </h3> <div>https://www.hbs.edu</div> </a> </div> </div> </body> </html>' my_page <- read_html(html) my_page %>% html_nodes(xpath = "//a[.//h3 and not(.//img)]") %>% html_attr("href")
运行后输出结果为[1] "https://www.hbs.edu",自动剔除了嵌套img的图片链接。
如果需要更严格的匹配规则(比如要求h3、img必须是a标签的直接子元素,而非多层嵌套的后代节点),只需要把XPath中代表任意深度后代的.//替换成代表直接子节点的./即可。
Python(BeautifulSoup4)实现
bs4支持对节点子元素的遍历判断,可以先选中所有a标签,再通过子节点存在性过滤:
from bs4 import BeautifulSoup html = """<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div> <div> <div> <a href="https://upload.wikimedia.org/wikipedia/commons/thumb/e/e0/SNice.svg/1200px-SNice.svg.png"> <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/e0/SNice.svg/1200px-SNice.svg.png" style="max-width:72px;max-height:72px"> </a> </div> <span> <h3> <div> Smiley Face </div> </h3> </span> <span> <div> https://upload.wikimedia.org/wikipedia/commons/thumb/e/e0/SNice.svg/1200px-SNice.svg.png </div> </span> </div> </div> <div> <div> <a href="https://www.hbs.edu"> <h3> <div>Harvard Business School</div> </h3> <div>https://www.hbs.edu</div> </a> </div> </div> </body> </html>""" soup = BeautifulSoup(html, "html.parser") valid_links = [] for a_tag in soup.find_all("a"): # 排除嵌套img的链接,保留嵌套h3的链接 if a_tag.find("img") is None and a_tag.find("h3") is not None: valid_links.append(a_tag.get("href")) print(valid_links)
运行后输出['https://www.hbs.edu'],符合过滤要求。如果需要判断直接子元素,遍历a_tag.children检查标签名即可。
两类工具都不需要依赖父级标签的属性做定位,完全基于标签嵌套关系就能实现精准过滤。
内容的提问来源于stack exchange,提问作者Jeff Parker
相关产品推荐
相关产品推荐

