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-idID的元素。
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通常与lxmlhtml.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

posted @ 2024-08-06 16:04  七夜魔手  阅读(9)  评论(0编辑  收藏  举报  来源