爬虫 - css selector
CSS SELECTOR
功能:分析静态 html 代码,定位到具体的界面元素。
名字中有 CSS,所以与前端的 CSS 样式(Cascading Style Sheets)真的有关,
在样式中,通过选择器定位元素,进行界面渲染;而爬虫通过选择器定位元素,进行界面抓取,
二者有着类似的 API,前端开发人员能快速掌握相关内容。
安装插件
pip install beautifulsoup4
测试代码
from bs4 import BeautifulSoup
html = '''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<span>first</span>
<span id="a">a</span>
<span class="b">b</span>
<span id="c">c</span>
<label for="d">
<input id="d" name="d" value="d"/>
</label>
<span id="x">x<span id="y">y<span id="z">z</span></span></span>
<span>last</span>
<p title="this is content" id="p">last</p>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
</body>
</html>
'''
soup = BeautifulSoup(html, 'html.parser')
常规 CSS 选择
# id 查找
elements = soup.select('#a')
print(elements)
# class 查找
elements = soup.select('.b')
print(elements)
# 标签查找
elements = soup.select('input')
print(elements)
# 标签 + id 或者 标签 + class
elements = soup.select('span.b')
print(elements)
属性选择
# 查找 p 标签,存在 title 属性
elements = soup.select('p[title]')
print(elements)
# 查找 p 标签,要求 title = this is content
elements = soup.select('p[title="this is content"]')
print(elements)
# 查找 p 标签,要求 title like this%
elements = soup.select('p[title^="this"]')
print(elements)
# 查找 p 标签,要求 title like %this
elements = soup.select('p[title$="content"]')
print(elements)
# 查找 p 标签,要求 title like %is%
elements = soup.select('p[title*="is"]')
print(elements)
# 查找 p 标签,要求 title 用空格分割后包含 is
elements = soup.select('p[title~="is"]')
print(elements)
关系选择器
# 后代选择器,包含孙子级
elements = soup.select('span#x span')
print(elements)
# 子代选择器,不包含孙子级
elements = soup.select('span#x > span')
print(elements)
# 相邻兄弟选择器,标签之后第一个元素
elements = soup.select('span#a + span')
print(elements)
# 通用兄弟选择器,标签之后的所有元素
elements = soup.select('span#a ~ span')
print(elements)
```python
#### 逻辑关系
```python
# 关系与,同时满足两个条件
elements = soup.select('p[title*="is"][id="p"]')
print(elements)
# 关系或,满足其中一个条件
elements = soup.select('span#a, span.b')
print(elements)
# 关系非
elements = soup.select('span:not(#a)')
print(elements)
伪类选择器(:符号)
存在一个非常反直觉的代码,对于 'span:first-child' 和 'span:last-child',
我们下意识会觉得它们是一对:'span:first-child' 查找的是第一个 span 标签,'span:last-child' 找的应该是最后一个 span 标签,
实际并非如此,如果 span 标签内嵌其它标签,通过 'span:last-child' 找到的是:span 子级标签中的最后一个。
# 1. 同级别的第几个
# 注意:序选择器是对同级标签来说的;
# 比如:<div><p>1<p></div> <div><p>2<p></div>
# 两个 p 标签,分布在两个 div 中,不是兄弟关系,
# 在各自的兄弟族谱中,都是第一个,因此,两个 p 标签都能通过 p:first-child 进行查找。
# 取第一个,找到 3 个元素
elements = soup.select('span:first-child')
print(elements)
# 取最后一个,找到 2 个元素
# 直觉上,功能应该与 first-child 相反,实际上,这里找的是 span 的最后一个子元素,
# 而且,与下一行的代码相比,写法完全一致,但是效果不同,日常编码中需要注意这一问题。
elements = soup.select('span:last-child')
print(elements)
# 取最后一个,找最后一个 li 标签
elements = soup.select('li:last-child')
print(elements)
# 取第一个,注意 index 从 1 开始
elements = soup.select('span:nth-child(1)')
print(elements)
# 取倒数第一个,注意 index 从 1 开始,与 :last-child 效果一致,存在相同问题
elements = soup.select('span:nth-last-child(1)')
print(elements)
# 选中父元素中唯一的标签
elements = soup.select('span:only-child')
print(elements)
# 2. 同类型的第几个
# 选中同类型的第一个标签。
elements = soup.select('li:first-of-type')
print(elements)
# 选中同类型的最后一个标签。
elements = soup.select('li:last-of-type')
print(elements)
# 选中同类型的第n个标签。
elements = soup.select('li:nth-of-type(1)')
print(elements)
# 选中同类型的倒数第n个标签。
elements = soup.select('li:nth-last-of-type(1)')
print(elements)
# 选中同类型的唯一的一个。
elements = soup.select('span:only-of-type')
print(elements)
# 3. 奇偶数选择第几个
# 选取奇数位标签
elements = soup.select('li:nth-child(2n+1)')
print(elements)
# 选取奇数位标签
elements = soup.select('li:nth-child(odd)')
print(elements)
# 选取偶数位标签
elements = soup.select('li:nth-child(even)')
print(elements)
# 选取奇数位标签
elements = soup.select('li:nth-of-type(2n+1)')
print(elements)
# 选取奇数位标签
elements = soup.select('li:nth-of-type(odd)')
print(elements)
# 选取偶数位标签
elements = soup.select('li:nth-of-type(even)')
print(elements)
伪类选择器(:符号)
按属性查找
from bs4 import BeautifulSoup
html = '''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input id="i1" name="i1" value="i1"></input>
<input id="i2" name="i2" value="i2" disabled></input>
<div></div>
<div><h1>1</h1></div>
</body>
</html>
'''
soup = BeautifulSoup(html, 'html.parser')
elements = soup.select('input:disabled')
print(elements)
elements = soup.select('div:empty')
print(elements)
elements = soup.select('div:has(h1)')
print(elements)
疯狂的妞妞 :每一天,做什么都好,不要什么都不做!