如何用Python获取符合指定href格式的所有<a>标签?
解决XPath提取特定格式链接的问题
嘿,我看到你在尝试用XPath提取特定格式的链接时遇到了问题——问题出在你误用了contains()函数,它不支持正则表达式匹配,只是简单检查字符串是否包含某个子串。要实现正则匹配,你需要用XPath 2.0+的matches()方法,或者换一种更兼容的方式:先用XPath提取所有链接,再用Python的正则库过滤。
问题分析
你的目标链接格式是/static_word/带横杠的随机字符串/随机数字,而你写的XPath表达式//a[contains(@href,'^/static_word/[A-Za-z0-9_-]/[0-9]$')]有两个核心问题:
contains()不识别正则语法,它会把整个正则字符串当作普通子串去匹配,自然找不到符合条件的链接- 你的正则本身也有小瑕疵:
[A-Za-z0-9_-]和[0-9]都只匹配单个字符,而你需要匹配的是一段字符串/数字,应该加上+表示匹配至少一个字符
方案一:使用XPath的matches()函数(推荐,更简洁)
lxml库支持XPath 2.0的matches()方法,可以直接在XPath中写正则匹配:
from lxml import html import ssl import requests ssl._create_default_https_context = ssl._create_unverified_context headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'} myRequest = requests.get("https://somesecureurl.com/", headers=headers) webpage = html.fromstring(myRequest.content) # 修正后的XPath:用matches实现正则匹配,调整正则语法匹配多字符 theLinks = webpage.xpath("//a[matches(@href, '^/static_word/[A-Za-z0-9_-]+/[0-9]+$')]/@href") print(theLinks)
关键改动说明:
- 用
matches(@href, '正则表达式')替代contains(),实现真正的正则匹配 - 正则中把
[A-Za-z0-9_-]改成[A-Za-z0-9_-]+,匹配至少一个字母/数字/下划线/横杠组成的字符串 - 把
[0-9]$改成[0-9]+$,匹配至少一个数字结尾的路径 - 最后加上
/@href直接提取链接字符串,而不是返回a标签元素
方案二:提取所有链接后用Python正则过滤(兼容性更好)
如果你的lxml环境不支持XPath 2.0的matches()函数,或者你想更灵活地处理链接,可以先用XPath提取所有链接,再用Python的re库过滤:
from lxml import html import ssl import requests import re ssl._create_default_https_context = ssl._create_unverified_context headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'} myRequest = requests.get("https://somesecureurl.com/", headers=headers) webpage = html.fromstring(myRequest.content) # 先提取所有a标签的href属性 all_links = webpage.xpath("//a/@href") # 定义匹配目标格式的正则模式 link_pattern = re.compile(r'^/static_word/[A-Za-z0-9_-]+/[0-9]+$') # 过滤出符合条件的链接 filtered_links = [link for link in all_links if link_pattern.match(link)] print(filtered_links)
额外注意事项:
- 如果目标链接后面可能带有查询参数(比如
/static_word/abc-def/123?foo=bar),可以把正则末尾的$去掉,改成^/static_word/[A-Za-z0-9_-]+/[0-9]+ - 可以先打印
all_links看看实际返回的链接格式,再微调正则表达式,确保匹配准确
内容的提问来源于stack exchange,提问作者andres.gtz
相关产品推荐
相关产品推荐

