什么是CSS选择器?
- CSS(Cascading Style Sheets)是一种语言,它被用来描述 HTML 和 XML 文档的表现。
- CSS使用选择器来为页面元素绑定属性。
CSS 选择器常用语法:
表达式 | 匹配结果 |
---|---|
* 通用元素选择器 | 匹配任何元素 |
E 标签选择器 | 匹配所有使用 E 标签的元素 |
.info class 选择器 | 匹配所有 class 属性中包含 info 的元素 |
#footer id 选择器 | 匹配所有 id 属性等于 footer 的元素 |
E,F 多元素选择器 | 同时匹配所有 E 元素或 F 元素,E 和 F 之间用逗号分隔 |
E F 后代元素选择器 | 匹配所有属于 E 元素后代的 F 元素,E 和 F 之间用空格分隔 |
E > F 子元素选择器 | 匹配所有 E 元素的子元素 F |
E + F 毗邻元素选择器 | 匹配紧随 E 元素之后的同级元素 F (只匹配第一个) |
E ~ F 同级元素选择器 | 匹配所有在 E 元素之后的同级 F 元素 |
E[att=‘val’] | 属性 att 的值为 val 的 E 元素 |
E[att^=‘val’] | 属性 att 的值以 val 开头的 E 元素 |
E[att$=‘val’] | 属性 att 的值以 val 结尾的 E 元素 |
E[att*=‘val’] | 属性 att 的值包含 val 的 E 元素 |
E[att1=‘v1’][att2*=‘v2’] | 属性 att1 的值为 v1,att2 的值包含 v2 |
E:contains(‘xxxx’) | 内容中包含 xxxx 的 E 元素 |
E:not(s) | 匹配不符合当前选择器的任何元素 |
PyQuery 的使用
在 Python中,PyQuery、Selenium、Scrapy 等库可用 CSS 选择器作为定位策略。这里以 PyQuery 为例。
(1) PyQuery 使用 CSS 选择器作为元素定位
from pyquery import PyQuery
"""初始化url"""
doc = PyQuery('https://www.baidu.com', encoding='utf8')
# 通过标签名获取元素
print(doc('title'))
# 通过id属性值获取元素
print(doc('#su'))
# 通过class属性值获取元素
print(doc('.s_ipt'))
# 通过其他属性值获取元素
print(doc('[type="submit"]'))
print(doc('[name="wd"]'))
# 组合定位
print(doc('input.s_ipt'))
print(doc('[value="百度一下"][type="submit"]'))
# 子元素选择器
print(doc('#u1>a'))
# 后代选择器
print(doc('#u1 a'))
# 获取同级元素后面的第一个元素
print(doc('a[name="tj_trnews"]+a'))
# 获取同级元素后面的所有元素
print(doc('a[name="tj_trnews"]~a'))
(2) PyQuery 的结构性定位
from pyquery import PyQuery
doc = PyQuery('https://www.baidu.com', encoding='utf8')
# 获取a元素集合中的第一个
print(doc('#u1>a:first'))
# 获取a元素集合中的第三个
print(doc('#u1>a:eq(2)'))
# 获取a元素集合中的最后一个
print(doc('#u1>a:last'))
# 获取a元素集合中排在第三位之前的所有a元素
print(doc('#u1>a:lt(2)'))
# 获取a元素集合中排在第三位之后的所有a元素
print(doc('#u1>a:gt(2)'))
(3) PyQuery 提取元素中的内容
from pyquery import PyQuery
doc = PyQuery('https://www.baidu.com', encoding='utf8')
'''获取元素中的文本'''
print(doc('title').text())
# >>> 百度一下,你就知道
'''获取元素中的属性值'''
print(doc('#su').attr('value'))
# print(doc('#su').attr.value) 同上
# >>> 百度一下
print(type(doc('#u1>a')))
# >>> <class 'pyquery.pyquery.PyQuery'>
'''items() 方法可以将 PyQuery 对象变成生成器'''
els = doc('#u1>a').items()
print(type(els))
# >>> <class 'generator'>
'''遍历生成器,每个元素又是 PyQuery 对象'''
for el in els:
print(type(el))
# >>> <class 'pyquery.pyquery.PyQuery'>
print(el.text())
(4) 下面用 PyQuery 解析数据的爬取图片例子:
from fake_useragent import UserAgent
from pyquery import PyQuery
import requests
import os
import re
def get_response(url, referer):
""" 获取response响应内容 """
headers = {'User-Agent': UserAgent().chrome, 'Referer': referer}
response = requests.get(url, headers=headers, timeout=8)
response.raise_for_status()
return response
def crawler(url):
""" 获取页面的套图链接、标题、套图数量 """
page = get_response(url, url).text
doc = PyQuery(page)
lis = doc('#pins>li>a').items()
for li in lis:
href = li.attr('href')
html = get_response(href, href).text
d = PyQuery(html)
# 返回提取的数据
src = d('div.main-image a>img').attr('src')
alt = d('div.main-image a>img').attr('alt')
num = d('div.pagenavi>a:eq(4)').text()
yield (href, src, alt, num)
def process(items):
"""处理数据 """
for item in items:
href, src, alt, num = item
alt = re.sub(r'\W+', '_', alt) # 更换标题的特殊字符
# 创建存放每个套图的目录
global path
path = './image/' + alt
if not os.path.exists(path):
os.makedirs(path)
# 封装数据
for n in range(1, int(num) + 1):
p = str(n) if n > 9 else f'0{n}' # 处理图片序号
img_url = src[:-6] + p + '.jpg'
img_referer = href + '/' + f'{n}'
img_name = alt + p
yield (img_url, img_referer, img_name)
def download(images):
"""下载图片"""
for image in images:
img_url, img_referer, img_name = image
content = get_response(img_url, img_referer).content
with open(path + '/' + img_name + '.jpg', 'wb') as f:
f.write(content)
print('已下载', img_name + '.jpg')
if __name__ == '__main__':
"""要爬取的页面"""
for i in range(1, 151):
url = f'https://www.mzitu.com/xinggan/page/{i}/'
try:
"""爬取页面的数据"""
items = crawler(url)
"""处理数据"""
images = process(items)
"""下载图片"""
download(images)
except:
pass