Scrapy与分布式开发(2.4):bs4+css基本指令和提取方法详解
bs4+css基本指令和提取方法详解
CSS简介
CSS选择器是网页开发中不可或缺的工具,它们让我们能够精确地定位和选择HTML文档中的元素。在爬虫领域多用于从网页中提取和解析数据。本教程将结合网上教程,提供一份详细的CSS选择器使用指南,并深入探讨更多的指令和API。
基本指令和提取方法
当从Python的角度考虑CSS的基本语法时,我们通常是在使用像BeautifulSoup或Scrapy这样的库来解析HTML文档,并从中提取或修改CSS样式。在Python中,CSS选择器的使用通常与这些库的选择器方法相结合,以定位HTML元素。以下是一个关于CSS基本语法、说明和案例的表格,这些案例假设你正在使用Python的某个库来处理HTML和CSS。
语法 | 说明 | 案例 |
---|---|---|
tagname | 选择指定HTML标签的元素。 | soup.select('div') 选择所有的<div> 元素。 |
.classname | 选择具有指定CSS类的元素。 | soup.select('.my-class') 选择所有具有my-class 类的元素。 |
#idname | 选择具有指定ID的元素。 | soup.select('#my-id') 选择具有my-id ID的元素。 |
element element | 选择后代元素,即第一个元素内部的所有第二个元素。 | soup.select('div p') 选择所有在<div> 元素内部的<p> 元素。 |
element > element | 选择子元素,即第一个元素的直接子元素。 | soup.select('ul > li') 选择所有直接作为<ul> 元素子元素的<li> 元素。 |
element + element | 选择紧接在第一个元素之后的下一个同级元素。 | soup.select('h1 + p') 选择所有紧接在<h1> 元素之后的<p> 元素。 |
element ~ element | 选择第一个元素之后的所有同级元素。 | soup.select('div ~ p') 选择所有在<div> 元素之后的所有<p> 元素。 |
:nth-child(n) | 选择其父元素的第n个子元素。 | soup.select('div:nth-child(2)') 选择所有作为其父元素的第二个子元素的<div> 元素。 |
:nth-last-child(n) | 选择其父元素的倒数第n个子元素。 | soup.select('div:nth-last-child(1)') 选择所有作为其父元素的最后一个子元素的<div> 元素。 |
[attribute] | 选择具有指定属性的元素。 | soup.select('[href]') 选择所有具有href 属性的元素。 |
[attribute=value] | 选择具有指定属性值的元素。 | soup.select('[target="_blank"]') 选择所有target 属性值为_blank 的元素。 |
[attribute^=value] | 选择属性值以指定字符串开头的元素。 | soup.select('[href^="https"]') 选择所有href 属性值以https 开头的元素。 |
[attribute$=value] | 选择属性值以指定字符串结尾的元素。 | soup.select('[href$=".pdf"]') 选择所有href 属性值以.pdf 结尾的元素。 |
[attribute*=value] | 选择属性值包含指定字符串的元素。 | soup.select('[href*="example"]') 选择所有href 属性值包含example 的元素。 |
:contains(text) | 选择包含特定文本的元素。 | soup.select('div:contains("Hello")') 选择所有<div> 元素,其文本内容包含"Hello"。 |
:has(selector) | 选择包含匹配选择器的元素的元素。 | soup.select('div:has(p)') 选择所有包含<p> 元素的<div> 元素。 |
:not(selector) | 排除匹配选择器的元素。 | soup.select('div:not(.ignore)') 选择所有<div> 元素,但不包括那些具有ignore 类的元素。 |
:input | 选择所有输入元素,如<input> , <textarea> , <select> , 和 <button> 。 | soup.select(':input') 选择页面上的所有输入元素。 |
:checked | 选择所有被选中的复选框和单选按钮。 | soup.select('input[type="checkbox"]:checked') 选择所有被选中的复选框。 |
:disabled | 选择所有禁用的输入元素。 | soup.select('input:disabled') 选择所有禁用的输入元素。 |
:enabled | 选择所有启用的输入元素。 | soup.select('input:enabled') 选择所有启用的输入元素。 |
:first-child | 选择其父元素的第一个子元素。 | soup.select('div:first-child') 选择所有作为其父元素的第一个子元素的<div> 元素。 |
:last-child | 选择其父元素的最后一个子元素。 | soup.select('div:last-child') 选择所有作为其父元素的最后一个子元素的<div> 元素。 |
:first-of-type | 选择其父元素中第一个指定类型的子元素。 | soup.select('p:first-of-type') 选择每个父元素中的第一个<p> 元素。 |
:last-of-type | 选择其父元素中最后一个指定类型的子元素。 | soup.select('p:last-of-type') 选择每个父元素中的最后一个<p> 元素。 |
:only-child | 选择那些是其父元素的唯一子元素的元素。 | soup.select('div:only-child') 选择所有是其父元素的唯一子元素的<div> 元素。 |
:only-of-type | 选择那些是其父元素中唯一指定类型的子元素的元素。 | soup.select('p:only-of-type') 选择所有是其父元素中唯一<p> 元素的元素。 |
:empty | 选择没有子元素(包括文本节点)的元素。 | soup.select('div:empty') 选择所有空的<div> 元素。 |
:root | 选择文档的根元素。在HTML中,这通常是<html> 元素。 | soup.select(':root') 选择文档的根元素。 |
:lang(language) | 选择具有指定lang 属性的元素。 | soup.select('p:lang(en)') 选择所有<p> 元素,其lang 属性值为en 。 |
:focus | 选择当前获取焦点的元素。 | soup.select(':focus') 选择当前获取焦点的元素(注意:这通常在浏览器环境中有效,而不是在Python解析HTML时)。 |
:hover | 选择用户鼠标悬停在其上的元素。 | soup.select(':hover') 选择用户鼠标当前悬停在其上的元素(注意:这通常在浏览器环境中有效,而不是在Python解析HTML时)。 |
:active | 选择用户当前激活的元素,通常是鼠标点击但还未释放的元素。 | soup.select(':active') 选择用户当前激活的元素(注意:这通常在浏览器环境中有效,而不是在Python解析HTML时)。 |
:visited | 选择用户已访问过的链接。 | soup.select('a:visited') 选择所有用户已访问过的<a> 元素(注意:这通常在浏览器环境中有效,而不是在Python解析HTML时,并且可能受到隐私政策限制)。 |
:link | 选择所有未被访问的链接。 | soup.select('a:link') 选择所有未被访问的<a> 元素(注意:这通常在浏览器环境中有效,而不是在Python解析HTML时)。 |
:not(:empty) | 选择所有非空元素。 | soup.select('div:not(:empty)') 选择所有包含内容(文本或其他子元素)的<div> 元素。 |
:header | 选择所有标题元素,如<h1> , <h2> , …, <h6> 。 | soup.select(':header') 选择所有的标题元素。 |
:footer | 选择所有页脚元素。这不是一个标准的CSS选择器,但某些库可能支持它。 | soup.select(':footer') 如果库支持,选择所有的页脚元素。 |
:nth-last-of-type(n) | 选择其父元素中倒数第n个指定类型的子元素。 | soup.select('p:nth-last-of-type(2)') 选择每个父元素中倒数第二个<p> 元素。 |
bs4应用CSS
BeautifulSoup4是一个强大的Python库,用于解析HTML和XML文档。它可以轻松地提取、修改和导航文档树。除了提供传统的基于标签名、属性等的方法外,BeautifulSoup4还支持使用CSS选择器来定位和提取页面元素。下面我们将通过实战案例来详细介绍如何使用BeautifulSoup4与CSS选择器进行HTML文档的处理。
安装BeautifulSoup4
首先,确保已经安装了BeautifulSoup4库。如果还没有安装,可以通过pip来安装:
pip install beautifulsoup4
同时,BeautifulSoup4通常与lxml
或html.parser
一起使用作为解析器。lxml
通常更快,但html.parser
是Python的标准库,不需要额外安装。
实战案例:从网页中提取信息
from bs4 import BeautifulSoup
import requests
# 获取网页内容
url = 'http://example.com' # 替换成实际的网页URL
response = requests.get(url)
html_content = response.text
# 创建BeautifulSoup对象
soup = BeautifulSoup(html_content, 'lxml')
# 使用CSS选择器提取标题
title = soup.select_one('title').text
print('Title:', title)
# 使用CSS选择器提取介绍文本
intro_text = soup.select_one('.intro').text
print('Introduction:', intro_text)
# 使用CSS选择器提取所有链接的URL
link_urls = [a['href'] for a in soup.select('.links a')]
print('Links:', link_urls)
在上面的代码中,我们使用了select_one
方法来提取单个元素(如<title>
标签或具有intro
类的<p>
标签)。对于多个元素的提取,我们使用了select
方法,该方法返回一个包含所有匹配元素的列表。然后,我们可以遍历这个列表,提取需要的信息。
实战案例:提取表格数据
我们的目标是提取表格中的所有行和列数据。
from bs4 import BeautifulSoup
# 假设这是我们的HTML表格内容
html_table = '''
<table id="myTable">
<tr>
<th>Header 1</th>
<th>Header 2</th>
</tr>
<tr>
<td>Row 1, Column 1</td>
<td>Row 1, Column 2</td>
</tr>
<tr>
<td>Row 2, Column 1</td>
<td>Row 2, Column 2</td>
</tr>
</table>
'''
# 创建BeautifulSoup对象
soup = BeautifulSoup(html_table, 'lxml')
# 使用CSS选择器找到表格
table = soup.select_one('#myTable')
# 提取表格的所有行
rows = table.find_all('tr')
# 遍历行,提取每行的所有单元格
for row in rows:
cells = row.find_all(['th', 'td']) # 选择th和td元素
row_data = [cell.text for cell in cells]
print(row_data)
输出将是:
['Header 1', 'Header 2']
['Row 1, Column 1', 'Row 1, Column 2']
['Row 2, Column 1', 'Row 2, Column 2']
实战案例:提取特定结构的文本
有时候,你可能想要提取具有特定结构的文本,例如在一个特定的<div>
标签内,但不在其任何子标签内。
<div class="extract-me">
This is the text we want to extract.
<p>This is a paragraph inside the div.</p>
</div>
要提取外层<div>
标签内的直接文本,但不包括其任何子标签内的文本,你可以使用.stripped_strings
属性。
from bs4 import BeautifulSoup
html_content = '''
<div class="extract-me">
This is the text we want to extract.
<p>This is a paragraph inside the div.</p>
</div>
'''
soup = BeautifulSoup(html_content, 'lxml')
# 使用CSS选择器找到div
div = soup.select_one('.extract-me')
# 提取直接文本
direct_text = [text.strip() for text in div.stripped_strings if text.strip()]
print(direct_text) # 输出: ['This is the text we want to extract.']
在这个例子中,stripped_strings
生成器会产生所有在标签内部(包括嵌套标签之间)的文本,我们通过检查每个文本并去除其前后的空白来过滤出直接文本。
实战案例:提取属性
有时候你可能想要提取元素的属性,比如链接的href
属性或图片的src
属性。
<a href="https://example.com/link1" class="external-link">Link 1</a>
<img src="image.jpg" alt="Example Image">
from bs4 import BeautifulSoup
html_content = '''
<a href="https://example.com/link1" class="external-link">Link 1</a>
<img src="image.jpg" alt="Example Image">
'''
soup = BeautifulSoup(html_content, 'lxml')
# 提取链接的href属性
link_href = soup.select_one('a.external-link')['href']
print('Link Href:', link_href)
# 提取图片的src属性
image_src =soup.select_one('img')['src']
print('Image Src:', image_src)
输出将是:
Link Href: https://example.com/link1
Image Src: image.jpg
实战案例:处理多个相同标签
如果页面上有多个相同类型的标签,并且你想提取它们的文本或属性,你可以使用find_all
方法。
<ul>
<li class="item">Item 1</li>
<li class="item">Item 2</li>
<li class="item">Item 3</li>
</ul>
from bs4 import BeautifulSoup
html_content = '''
<ul>
<li class="item">Item 1</li>
<li class="item">Item 2</li>
<li class="item">Item 3</li>
</ul>
'''
soup = BeautifulSoup(html_content, 'lxml')
# 提取所有li标签的文本
items = [li.text for li in soup.select('.item')]
print('Items:', items)
# 提取所有li标签的class属性
item_classes = [li['class'] for li in soup.select('.item')]
print('Item Classes:', item_classes)
输出将是:
Items: ['Item 1', 'Item 2', 'Item 3']
Item Classes: [['item'], ['item'], ['item']]
实战案例:处理嵌套的HTML结构
有时,你可能需要处理嵌套的HTML结构,比如在一个列表中嵌套另一个列表。
<ul class="outer-list">
<li>Outer Item 1</li>
<li>Outer Item 2
<ul class="inner-list">
<li>Inner Item 1</li>
<li>Inner Item 2</li>
</ul>
</li>
<li>Outer Item 3</li>
</ul>
from bs4 import BeautifulSoup
html_content = '''
<ul class="outer-list">
<li>Outer Item 1</li>
<li>Outer Item 2
<ul class="inner-list">
<li>Inner Item 1</li>
<li>Inner Item 2</li>
</ul>
</li>
<li>Outer Item 3</li>
</ul>
'''
soup = BeautifulSoup(html_content, 'lxml')
# 提取外部列表的所有直接li元素
outer_items = soup.select('.outer-list li')
for item in outer_items:
# 检查li元素是否包含内部列表
if item.find('ul', class_='inner-list'):
# 提取内部列表的项
inner_items = item.find('ul', class_='inner-list').find_all('li')
print('Outer Item:', item.text)
print('Inner Items:', [inner_item.text for inner_item in inner_items])
else:
print('Outer Item:', item.text)
输出将是:
Outer Item: Outer Item 1
Outer Item: Outer Item 2
Inner Items: ['Inner Item 1', 'Inner Item 2']
Outer Item: Outer Item 3
以上是一些使用BeautifulSoup4和CSS选择器从HTML中提取数据的实战案例。你可以根据自己的需求对这些技术进行调整和扩展。
经典面试题:beautifulsoup4与lxml区别在哪
这两个库主要是解析html/xml文档,BeautifulSoup是一个库,而 XPath是一种技术, python XPath中最常用的库lxml
性能lxml >> BeautifulSoup
BeautifulSoup和xm的原理不一样,BeautifulSoup是基于DOM的,会载入整个文档,解析整个DOM树,因此时间和内存开销都会大很多。而lxml只会局部遍历,另外lxml是用c写的,而 BeautifulSoup是用python写的,因此性能方面自然会差很多。易用性 BeautifulSoup >> lxml
BeautifulSoup用起来比较简单,AP非常人性化,支持css选择器,lxml的 XPath写起来麻烦,开发效率不如BeautifulSoup。
总结:需求比较确定,要求性能的场合用lxml,快速开发用 BeautifulSoup
本文来自博客园,作者:七夜魔手,转载请注明原文链接:https://www.cnblogs.com/ranbox/p/18461045