0

0

解决BeautifulSoup网页抓取空列表问题:精准选择器与结构化提取指南

碧海醫心

碧海醫心

发布时间:2025-10-11 10:01:17

|

509人浏览过

|

来源于php中文网

原创

解决beautifulsoup网页抓取空列表问题:精准选择器与结构化提取指南

本教程深入探讨使用BeautifulSoup进行网页抓取时,因选择器不当导致返回空列表的常见问题。我们将分析传统find()方法可能遇到的陷阱,并重点介绍如何利用CSS选择器进行精确元素定位,通过迭代文章容器实现结构化数据提取,从而有效解决数据抓取失败的问题。

引言:BeautifulSoup抓取空列表的常见原因

在使用BeautifulSoup进行网页数据抓取时,一个常见的困扰是最终得到一个空列表。这通常不是因为网站反爬虫机制过于严苛(尽管这也会发生),而是由于HTML元素选择器未能准确匹配到目标内容。当BeautifulSoup无法根据提供的选择器找到任何匹配的元素时,它会返回None或者一个空的列表/结果集,进而导致后续的数据提取操作失败。理解并正确使用选择器是解决此类问题的关键。

原代码问题分析

我们首先来看一个导致空列表的典型代码示例及其潜在问题:

import requests
from bs4 import BeautifulSoup

url = 'https://inshorts.com/en/read/technology'
news_data = []
news_category = url.split('/')[-1]

headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/91.0.4472.124124 Safari/537.36'}
data = requests.get(url, headers=headers)

if data.status_code == 200:
    soup = BeautifulSoup(data.content, 'html.parser')

    headlines = soup.find('div', class_=['news-card-title', 'news-right-box'])
    articles = soup.find('div', class_=['news-card-content', 'news-right-box'])

    if headlines and articles and len(headlines) == len(articles):
        news_articles = [
            {
                'news_headline': headline.find_all('span', attrs={'itemprop': 'headline'}).string,
                'news_article': article.find_all('div', attrs={'itemprop': 'articleBody'}).string,
                'news_category': news_category
            }
            for headline, article in zip(headlines, articles)
        ]
        news_data.extend(news_articles)

print(news_data)

上述代码旨在从inshorts.com抓取新闻标题和文章内容。然而,它常常返回一个空列表。分析其原因,主要有以下几点:

  1. find() 方法的局限性: soup.find() 只会返回第一个匹配的元素。如果页面上有多个新闻卡片,它只会找到第一个新闻标题和第一个文章内容,而不是所有。这与我们期望抓取多条新闻的意图不符。
  2. 选择器不精确: class_=['news-card-title', 'news-right-box'] 这种选择器组合可能无法准确匹配到包含所有标题和文章内容的父级元素。更常见的情况是,news-card-title和news-right-box是不同的类,或者它们不是同一层级的元素。如果选择器未能匹配到任何元素,headlines和articles将为None。
  3. 条件判断错误: 当headlines或articles为None时,len(headlines)或len(articles)会导致错误。即使它们不是None,如果find()只返回单个元素,那么len()操作也不是获取列表长度的正确方式。
  4. 文本提取方式: find_all(...).string 是一个常见误区。find_all() 返回的是一个列表(可能包含零个、一个或多个元素),直接在其上调用 .string 会失败。正确的做法是先从列表中取出元素(如果只有一个,可以使用 [0] 或 find()),再调用 .string 或 get_text()。

解决方案:利用CSS选择器进行精确提取

为了解决上述问题,我们推荐使用更强大、更灵活的CSS选择器。BeautifulSoup通过select()和select_one()方法支持CSS选择器,它们可以帮助我们更精确地定位元素。核心思路是:

PathFinder
PathFinder

AI驱动的销售漏斗分析工具

下载
  1. 定位父级容器: 首先找到页面上每个独立新闻项的父级容器。通常,这些容器会有一个独特的类名、ID或属性来标识。
  2. 迭代父级容器: 使用select()方法获取所有父级容器的列表,然后遍历这个列表。
  3. 在子级中提取: 在每个父级容器内部,使用select_one()或find()方法进一步定位新闻标题和文章内容等子元素。

示例代码与详细解释

以下是优化后的代码,展示了如何利用CSS选择器高效地提取数据:

import requests
from bs4 import BeautifulSoup

url = 'https://inshorts.com/en/read/technology'
news_data = []
news_category = url.split('/')[-1]

headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/91.0.4472.124124 Safari/537.36'}
data = requests.get(url, headers=headers)

if data.status_code == 200:
    soup = BeautifulSoup(data.content, 'html.parser')

    # 使用CSS选择器定位所有新闻文章的父级容器
    # 根据inshorts网站结构,每个新闻文章通常有一个itemtype属性
    for article_container in soup.select('[itemtype="http://schema.org/NewsArticle"]'):
        headline_element = article_container.select_one('[itemprop="headline"]')
        article_body_element = article_container.select_one('[itemprop="articleBody"]')

        # 确保元素存在,避免NoneType错误
        if headline_element and article_body_element:
            news_data.append(
                {
                    'news_headline': headline_element.get_text(strip=True),
                    'news_article': article_body_element.get_text(strip=True),
                    'news_category': news_category
                }
            )

print(news_data)

代码解释:

  1. soup.select('[itemtype="http://schema.org/NewsArticle"]'):
    • 这是最关键的改进。我们不再尝试直接寻找标题和文章内容,而是首先寻找它们的共同父级容器。
    • 通过观察inshorts.com的HTML结构,我们发现每个新闻文章卡片都带有一个itemtype="http://schema.org/NewsArticle"的属性。这是一个非常精确且稳定的CSS选择器,它能选择所有具有该特定属性的元素。
    • select()方法返回一个匹配所有元素的列表。
  2. for article_container in ...:
    • 我们遍历select()返回的每个article_container(即每个新闻文章的父级元素)。
  3. article_container.select_one('[itemprop="headline"]') 和 article_container.select_one('[itemprop="articleBody"]'):
    • 在每个article_container内部,我们再次使用CSS选择器select_one()来定位具体的标题和文章内容。
    • [itemprop="headline"]和[itemprop="articleBody"]是基于HTML语义化标签(Schema.org微数据)的属性选择器,它们能够精确地指向新闻标题和文章主体。
    • select_one()方法只会返回第一个匹配的元素,如果不存在则返回None。
  4. if headline_element and article_body_element::
    • 这是一个重要的错误处理步骤。在尝试提取文本之前,我们检查headline_element和article_body_element是否为None。这可以有效防止在某些元素缺失时程序崩溃。
  5. .get_text(strip=True):
    • get_text()方法用于提取元素的纯文本内容。
    • strip=True参数会自动移除文本开头和结尾的空白字符,使提取的数据更整洁。
    • 相比于.string,get_text()更加健壮,它能处理包含子标签的文本内容,而.string只有当元素只有一个子节点且该子节点是文本时才有效。

注意事项与最佳实践

  1. 深入理解HTML结构: 在编写爬虫代码之前,务必使用浏览器的开发者工具(F12)仔细检查目标网站的HTML结构。这是选择正确选择器的基础。
  2. 选择器的优先级:
    • ID选择器 (#id_name): 最高优先级,ID在页面中应是唯一的。
    • 属性选择器 ([attribute="value"]): 如本例所示,非常有效且具体。
    • 类选择器 (.class_name): 常用,但要注意类名是否具有唯一性或是否会动态变化。
    • 标签选择器 (tag_name): 最不具体,通常需要与其他选择器结合使用。
    • 组合选择器: 例如 div.news-card a.title 表示div标签下类名为news-card的元素内部,再选择类名为title的a标签。
  3. find() vs find_all() vs select() vs select_one():
    • find(tag, attrs):返回第一个匹配的元素。
    • find_all(tag, attrs):返回所有匹配元素的列表。
    • select(css_selector):使用CSS选择器,返回所有匹配元素的列表。
    • select_one(css_selector):使用CSS选择器,返回第一个匹配的元素。
    • 在需要抓取多个相同结构的数据时,优先使用select()或find_all()来获取所有容器,然后遍历它们。
  4. 错误处理: 始终对可能返回None的选择器结果进行判断,例如 if element:,以避免程序运行时出现AttributeError: 'NoneType' object has no attribute 'get_text'等错误。
  5. 文本清洗: 提取到的文本可能包含多余的空格、换行符等。使用.get_text(strip=True)或Python的字符串方法(如.strip(), .replace('\n', ''))进行清洗。
  6. 动态内容: BeautifulSoup只能处理静态HTML内容。如果目标数据是通过JavaScript动态加载的(例如,滚动到底部加载更多内容),则需要结合Selenium等工具来模拟浏览器行为。

总结

当使用BeautifulSoup进行网页抓取时遇到空列表问题,核心原因通常在于HTML元素选择器的不准确性。通过对原始代码的分析,我们发现find()方法的局限性、选择器不精确以及文本提取方式的误用是导致问题的主要因素。

解决方案在于采用更强大、更精确的CSS选择器,并结合结构化的数据提取策略。首先定位包含目标数据的父级容器,然后遍历这些容器,并在每个容器内部使用更具体的选择器提取所需信息。同时,进行适当的空值检查和文本清洗是保证爬虫健壮性和数据质量的关键。遵循这些最佳实践,可以显著提高网页抓取的成功率和效率。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Python爬虫获取数据的方法
Python爬虫获取数据的方法

Python爬虫可以通过请求库发送HTTP请求、解析库解析HTML、正则表达式提取数据,或使用数据抓取框架来获取数据。更多关于Python爬虫相关知识。详情阅读本专题下面的文章。php中文网欢迎大家前来学习。

293

2023.11.13

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

1031

2023.08.02

if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

847

2023.08.22

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

760

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

221

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1567

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

649

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

1228

2024.03.22

Python异步编程与Asyncio高并发应用实践
Python异步编程与Asyncio高并发应用实践

本专题围绕 Python 异步编程模型展开,深入讲解 Asyncio 框架的核心原理与应用实践。内容包括事件循环机制、协程任务调度、异步 IO 处理以及并发任务管理策略。通过构建高并发网络请求与异步数据处理案例,帮助开发者掌握 Python 在高并发场景中的高效开发方法,并提升系统资源利用率与整体运行性能。

37

2026.03.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Sass 教程
Sass 教程

共14课时 | 0.9万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3.6万人学习

CSS教程
CSS教程

共754课时 | 42.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号