当前位置: 首页 > news >正文

Python爬虫技术 第14节 HTML结构解析

HTML 结构解析是 Web 爬虫中的核心技能之一,它允许你从网页中提取所需的信息。Python 提供了几种流行的库来帮助进行 HTML 解析,其中最常用的是 BeautifulSouplxml

在这里插入图片描述

1. 安装必要的库

首先,你需要安装 requests(用于发送 HTTP 请求)和 beautifulsoup4(用于解析 HTML)。可以通过 pip 安装:

pip install requests beautifulsoup4

2. 发送 HTTP 请求并获取 HTML 内容

使用 requests 库可以轻松地从网站抓取 HTML 页面:

import requestsurl = "https://www.example.com"
response = requests.get(url)# 检查请求是否成功
if response.status_code == 200:html_content = response.text
else:print(f"Failed to retrieve page, status code: {response.status_code}")

3. 解析 HTML 内容

接下来,使用 BeautifulSoup 解析 HTML 内容:

from bs4 import BeautifulSoupsoup = BeautifulSoup(html_content, 'html.parser')

这里的 'html.parser' 是解析器的名字,BeautifulSoup 支持多种解析器,包括 Python 自带的标准库、lxmlhtml5lib

4. 选择和提取信息

一旦你有了 BeautifulSoup 对象,你可以开始提取信息。以下是几种常见的选择器方法:

  • 通过标签名

    titles = soup.find_all('h1')
    
  • 通过类名

    articles = soup.find_all('div', class_='article')
    
  • 通过 ID

    main_content = soup.find(id='main-content')
    
  • 通过属性

    links = soup.find_all('a', href=True)
    
  • 组合选择器

    article_titles = soup.select('div.article h2.title')
    

5. 遍历和处理数据

提取到数据后,你可以遍历并处理它们:

for title in soup.find_all('h2'):print(title.text.strip())

6. 递归解析

对于复杂的嵌套结构,你可以使用递归函数来解析:

def parse_section(section):title = section.find('h2')if title:print(title.text.strip())sub_sections = section.find_all('section')for sub_section in sub_sections:parse_section(sub_section)sections = soup.find_all('section')
for section in sections:parse_section(section)

7. 实战示例

让我们创建一个完整的示例,抓取并解析一个简单的网页:

import requests
from bs4 import BeautifulSoupurl = "https://www.example.com"# 发送请求并解析 HTML
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')# 找到所有的文章标题
article_titles = soup.find_all('h2', class_='article-title')# 输出所有文章标题
for title in article_titles:print(title.text.strip())

这个示例展示了如何从网页中抓取所有具有 class="article-title"h2 元素,并打印出它们的文本内容。

以上就是使用 Python 和 BeautifulSoup 进行 HTML 结构解析的基本流程。当然,实际应用中你可能需要处理更复杂的逻辑,比如处理 JavaScript 渲染的内容或者分页等。

在我们已经讨论的基础上,让我们进一步扩展代码,以便处理更复杂的场景,比如分页、错误处理、日志记录以及数据持久化。我们将继续使用 requestsBeautifulSoup,并引入 loggingsqlite3 来记录日志和存储数据。

1. 异常处理和日志记录

在爬取过程中,可能会遇到各种问题,如网络错误、服务器错误或解析错误。使用 try...except 块和 logging 模块可以帮助我们更好地处理这些问题:

import logging
import requests
from bs4 import BeautifulSouplogging.basicConfig(filename='crawler.log', level=logging.INFO, format='%(asctime)s:%(levelname)s:%(message)s')def fetch_data(url):try:response = requests.get(url)response.raise_for_status()  # Raises an HTTPError for bad responsessoup = BeautifulSoup(response.text, 'html.parser')return soupexcept requests.exceptions.RequestException as e:logging.error(f"Failed to fetch {url}: {e}")return None# Example usage
url = 'https://www.example.com'
soup = fetch_data(url)
if soup:# Proceed with parsing...
else:logging.info("No data fetched, skipping...")

2. 分页处理

许多网站使用分页显示大量数据。你可以通过检查页面源码找到分页链接的模式,并编写代码来遍历所有页面:

def fetch_pages(base_url, page_suffix='page/'):current_page = 1while True:url = f"{base_url}{page_suffix}{current_page}"soup = fetch_data(url)if not soup:break# Process page data here...# Check for next page linknext_page_link = soup.find('a', text='Next')if not next_page_link:breakcurrent_page += 1

3. 数据持久化:SQLite

使用数据库存储爬取的数据可以方便后续分析和检索。SQLite 是一个轻量级的数据库,非常适合小型项目:

import sqlite3def init_db():conn = sqlite3.connect('data.db')cursor = conn.cursor()cursor.execute('''CREATE TABLE IF NOT EXISTS articles (id INTEGER PRIMARY KEY AUTOINCREMENT,title TEXT NOT NULL,author TEXT,published_date DATE)''')conn.commit()return conndef save_article(conn, title, author, published_date):cursor = conn.cursor()cursor.execute('''INSERT INTO articles (title, author, published_date) VALUES (?, ?, ?)''', (title, author, published_date))conn.commit()# Initialize database
conn = init_db()# Save data
save_article(conn, "Example Title", "Author Name", "2024-07-24")

4. 完整示例:抓取分页数据并保存到 SQLite

让我们将上述概念整合成一个完整的示例,抓取分页数据并将其保存到 SQLite 数据库:

import logging
import requests
from bs4 import BeautifulSoup
import sqlite3logging.basicConfig(filename='crawler.log', level=logging.INFO)def fetch_data(url):try:response = requests.get(url)response.raise_for_status()return BeautifulSoup(response.text, 'html.parser')except requests.exceptions.RequestException as e:logging.error(f"Failed to fetch {url}: {e}")return Nonedef fetch_pages(base_url, page_suffix='page/'):conn = sqlite3.connect('data.db')cursor = conn.cursor()cursor.execute('''CREATE TABLE IF NOT EXISTS articles (id INTEGER PRIMARY KEY AUTOINCREMENT,title TEXT NOT NULL,author TEXT,published_date DATE)''')conn.commit()current_page = 1while True:url = f"{base_url}{page_suffix}{current_page}"soup = fetch_data(url)if not soup:break# Assume the structure of the site allows us to find titles easilytitles = soup.find_all('h2', class_='article-title')for title in titles:save_article(conn, title.text.strip(), None, None)next_page_link = soup.find('a', text='Next')if not next_page_link:breakcurrent_page += 1conn.close()def save_article(conn, title, author, published_date):cursor = conn.cursor()cursor.execute('''INSERT INTO articles (title, author, published_date) VALUES (?, ?, ?)''', (title, author, published_date))conn.commit()# Example usage
base_url = 'https://www.example.com/articles/'
fetch_pages(base_url)

这个示例将抓取 https://www.example.com/articles/ 上的分页数据,保存文章标题到 SQLite 数据库。注意,你需要根据实际网站的 HTML 结构调整 find_allfind 方法的参数。

既然我们已经有了一个基本的框架来抓取分页数据并存储到 SQLite 数据库中,现在让我们进一步完善这个代码,包括添加更详细的错误处理、日志记录、以及处理动态加载的网页内容(通常由 JavaScript 渲染)。

1. 更详细的错误处理

fetch_data 函数中,除了处理请求错误之外,我们还可以捕获和记录其他可能发生的错误,比如解析 HTML 的错误:

def fetch_data(url):try:response = requests.get(url)response.raise_for_status()soup = BeautifulSoup(response.text, 'html.parser')return soupexcept requests.exceptions.RequestException as e:logging.error(f"Request error fetching {url}: {e}")except Exception as e:logging.error(f"An unexpected error occurred: {e}")return None

2. 更详细的日志记录

在日志记录方面,我们可以增加更多的信息,比如请求的 HTTP 状态码、响应时间等:

import timedef fetch_data(url):try:start_time = time.time()response = requests.get(url)elapsed_time = time.time() - start_timeresponse.raise_for_status()soup = BeautifulSoup(response.text, 'html.parser')logging.info(f"Fetched {url} successfully in {elapsed_time:.2f} seconds, status code: {response.status_code}")return soupexcept requests.exceptions.RequestException as e:logging.error(f"Request error fetching {url}: {e}")except Exception as e:logging.error(f"An unexpected error occurred: {e}")return None

3. 处理动态加载的内容

当网站使用 JavaScript 动态加载内容时,普通的 HTTP 请求无法获取完整的内容。这时可以使用 SeleniumPyppeteer 等库来模拟浏览器行为。这里以 Selenium 为例:

from selenium import webdriver
from selenium.webdriver.chrome.options import Optionsdef fetch_data_with_js(url):options = Options()options.headless = True  # Run Chrome in headless modedriver = webdriver.Chrome(options=options)driver.get(url)# Add wait time or wait for certain elements to loadtime.sleep(3)  # Wait for dynamic content to loadhtml = driver.page_sourcedriver.quit()return BeautifulSoup(html, 'html.parser')

要使用这段代码,你需要先下载 ChromeDriver 并确保它在系统路径中可执行。此外,你还需要安装 selenium 库:

pip install selenium

4. 整合所有改进点

现在,我们可以将上述所有改进点整合到我们的分页数据抓取脚本中:

import logging
import time
import requests
from bs4 import BeautifulSoup
import sqlite3
from selenium import webdriver
from selenium.webdriver.chrome.options import Optionslogging.basicConfig(filename='crawler.log', level=logging.INFO)def fetch_data(url):try:start_time = time.time()response = requests.get(url)elapsed_time = time.time() - start_timeresponse.raise_for_status()soup = BeautifulSoup(response.text, 'html.parser')logging.info(f"Fetched {url} successfully in {elapsed_time:.2f} seconds, status code: {response.status_code}")return soupexcept requests.exceptions.RequestException as e:logging.error(f"Request error fetching {url}: {e}")except Exception as e:logging.error(f"An unexpected error occurred: {e}")return Nonedef fetch_data_with_js(url):options = Options()options.headless = Truedriver = webdriver.Chrome(options=options)driver.get(url)time.sleep(3)html = driver.page_sourcedriver.quit()return BeautifulSoup(html, 'html.parser')def fetch_pages(base_url, page_suffix='page/', use_js=False):conn = sqlite3.connect('data.db')cursor = conn.cursor()cursor.execute('''CREATE TABLE IF NOT EXISTS articles (id INTEGER PRIMARY KEY AUTOINCREMENT,title TEXT NOT NULL,author TEXT,published_date DATE)''')conn.commit()current_page = 1fetch_function = fetch_data_with_js if use_js else fetch_datawhile True:url = f"{base_url}{page_suffix}{current_page}"soup = fetch_function(url)if not soup:breaktitles = soup.find_all('h2', class_='article-title')for title in titles:save_article(conn, title.text.strip(), None, None)next_page_link = soup.find('a', text='Next')if not next_page_link:breakcurrent_page += 1conn.close()def save_article(conn, title, author, published_date):cursor = conn.cursor()cursor.execute('''INSERT INTO articles (title, author, published_date) VALUES (?, ?, ?)''', (title, author, published_date))conn.commit()# Example usage
base_url = 'https://www.example.com/articles/'
use_js = True  # Set to True if the site uses JS for loading content
fetch_pages(base_url, use_js=use_js)

这个改进版的脚本包含了错误处理、详细的日志记录、以及处理动态加载内容的能力,使得它更加健壮和实用。

相关文章:

Python爬虫技术 第14节 HTML结构解析

HTML 结构解析是 Web 爬虫中的核心技能之一,它允许你从网页中提取所需的信息。Python 提供了几种流行的库来帮助进行 HTML 解析,其中最常用的是 BeautifulSoup 和 lxml。 1. 安装必要的库 首先,你需要安装 requests(用于发送 HTT…...

【vue3|第18期】Vue-Router路由的三种传参方式

日期:2024年7月17日 作者:Commas 签名:(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释:如果您觉得有所帮助,帮忙点个赞,也可以关注我,我们一起成长;如果有不对的地方,还望各位大佬不吝赐教,谢谢^ - ^ 1.01365 = 37.7834;0.99365 = 0.0255 1.02365 = 1377.408…...

ElasticSearch(六)— 全文检索

一、match系列查询 前面讲到的query中的查询,都是精准查询。可以理解成跟在关系型数据库中的查询类似。match系列的查询,是全文检索的查询。会通过分词进行评分,匹配,再返回搜索结果。 1.1 match 查询 "query": {&qu…...

Oracle核心进程详解并kill验证

Oracle核心进程详解并kill验证 文章目录 Oracle核心进程详解并kill验证一、说明二、核心进程详解2.1.PMON-进程监控进程2.2.SMON-系统监控进程2.3.DBWn-数据库块写入进程2.4. LGWR-日志写入器进程2.5. CKPT-检查点进程 三、Kill验证3.1.kill ckpt进程3.2.kill pmon进程3.3.kill…...

【BUG】已解决:SyntaxError:positional argument follows keyword argument

SyntaxError:positional argument follows keyword argument 目录 SyntaxError:positional argument follows keyword argument 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页,我是博主英杰&#xff0c…...

怎样在 Nginx 中配置基于请求客户端 Wi-Fi 连接状态的访问控制?

🍅关注博主🎗️ 带你畅游技术世界,不错过每一次成长机会! 文章目录 怎样在 Nginx 中配置基于请求客户端 Wi-Fi 连接状态的访问控制一、理解请求客户端 Wi-Fi 连接状态二、Nginx 中的访问控制基础知识三、获取客户端 Wi-Fi 连接状态…...

逆向案例二十九——某品威客登录,请求头参数加密,简单webpack

网址:登录- 一品威客网,创新型知识技能共享服务平台 抓到登陆包分析,发现请求头有参数加密,直接搜索 定位到加密位置,打上断点,很明显是对象f的a方法进行了加密。 往上找f,可以发现f被定义了,是…...

河道高效治理新策略:视频AI智能监控如何助力河污防治

一、背景与现状 随着城市化进程的加快,河道污染问题日益严重,对生态环境和居民生活造成了严重影响。为了有效治理河道污染,提高河道管理的智能化水平,TSINGSEE青犀提出了一套河污治理视频智能分析及管理方案。方案依托先进的视频…...

[React]如何提高大数据量场景下的Table性能?

[React]如何提高大数据量场景下的Table性能? 两个方向:虚拟列表,发布订阅 虚拟列表 虚拟列表实际上只对可视区域的数据项进行渲染 可视区域(visibleHeight): 根据屏幕可视区域动态计算或自定义固定高度数据渲染项&…...

基于Vision Transformer的mini_ImageNet图片分类实战

【图书推荐】《PyTorch深度学习与计算机视觉实践》-CSDN博客 PyTorch计算机视觉之Vision Transformer 整体结构-CSDN博客 mini_ImageNet数据集简介与下载 mini_ImageNet数据集节选自ImageNet数据集。ImageNet是一个非常有名的大型视觉数据集,它的建立旨在促进视觉…...

JS中map()使用记录

优点和缺点 总的来说,map() 方法是一个强大的工具,适合于需要将数组中的每个元素转换为新形式的情况。然而,对于性能敏感的应用或需要更复杂控制逻辑的场景,可能需要考虑其他方法。 优点: 函数式编程风格&#xff1a…...

JavaWeb学习——请求响应、分层解耦

目录 一、请求响应学习 1、请求 简单参数 实体参数 数组集合参数 日期参数 Json参数 路径参数 总结 2、响应 ResponseBody&统一响应结果 二、分层解耦 1、三层架构 三层架构含义 架构划分 2、分层解耦 引入概念 容器认识 3、IOC&DI入门 4、IOC详解 …...

Vue中!.和?.是什么意思

在Vue(或更广泛地说,在JavaScript和TypeScript中),!. 和 ?. 是两个与可选链(Optional Chaining)和断言非空(Non-null Assertion)相关的操作符,它们分别用于处理可能为nu…...

秋招突击——7/22——复习{堆——前K个高频元素}——新作{回溯——单次搜索、分割回文串。链表——环形链表II,合并两个有序链表}

文章目录 引言复习堆堆——前K个高频元素个人实现复习实现二参考实现 新作单词搜索个人实现参考实现 分割回文串个人实现参考实现 环形链表II个人实现参考实现 两个有序链表个人实现 总结 引言 又是充满挑战性的一天,继续完成我们的任务吧!继续往下刷&a…...

android13禁用某个usb设备

总纲 android13 rom 开发总纲说明 目录 1.前言 2.触摸设备查看 3.功能修改 3.1 禁用usb触摸 3.2 禁用usb键盘 3.3 禁用usb遥感 4.查看生效与否 5.彩蛋 1.前言 用户想要禁止使用某些usb设备,需要系统不能使用相关的usb设备,例如usb触摸屏,usb键盘,usb遥感等等usb…...

tmux相关命令

tmux相关命令 1、tmux介绍2、会话(session)、窗口(windows)、窗格(pane)3、会话相关命令4、窗口相关命令5、窗格相关命令6、内容查看7、tmux配置文件 1、tmux介绍 略 2、会话(session&#xf…...

初创小程序公司怎么选服务器合作商

初创小程序公司怎么选服务器合作商?在移动互联网的浪潮中,小程序以其轻量、便捷、即用即走的特点,成为了众多初创企业快速触达用户、展现创意与服务的理想平台。然而,对于初创小程序公司而言,如何在纷繁复杂的服务器市…...

基于微信小程序+SpringBoot+Vue的自习室选座与门禁系统(带1w+文档)

基于微信小程序SpringBootVue的自习室选座与门禁系统(带1w文档) 基于微信小程序SpringBootVue的自习室选座与门禁系统(带1w文档) 本课题研究的研学自习室选座与门禁系统让用户在小程序端查看座位,预定座位,支付座位价格,该系统让用户预定座位…...

【Linux】进程IO|重定向|缓冲区|dup2|dup|用户级缓冲区|模拟缓冲区

目录 前言 重定向 实验一 为什么log.txt文件的文件描述符是1 为什么向stdout打印的信息也出现在文件中 实验二 用户级缓冲区 为什么要有用户级缓冲区 系统调用 dup 为什么close(fd1)之后还能向log.txt写入数据? dup2 缓冲区 观察现象 测试1 测试2 测…...

bug bug bug

importError: DLL load failed while importing _multiarray_umath: 找不到指定的模块。 Traceback (most recent call last): File "D:\yolov8_about\ultralytics-main3\trainCPU.py", line 4, in <module> from ultralytics import YOLO File "…...

基于算法竞赛的c++编程(28)结构体的进阶应用

结构体的嵌套与复杂数据组织 在C中&#xff0c;结构体可以嵌套使用&#xff0c;形成更复杂的数据结构。例如&#xff0c;可以通过嵌套结构体描述多层级数据关系&#xff1a; struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

使用VSCode开发Django指南

使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架&#xff0c;专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用&#xff0c;其中包含三个使用通用基本模板的页面。在此…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)

2025年能源电力系统与流体力学国际会议&#xff08;EPSFD 2025&#xff09;将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会&#xff0c;EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路

进入2025年以来&#xff0c;尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断&#xff0c;但全球市场热度依然高涨&#xff0c;入局者持续增加。 以国内市场为例&#xff0c;天眼查专业版数据显示&#xff0c;截至5月底&#xff0c;我国现存在业、存续状态的机器人相关企…...

【Java_EE】Spring MVC

目录 Spring Web MVC ​编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 ​编辑参数重命名 RequestParam ​编辑​编辑传递集合 RequestParam 传递JSON数据 ​编辑RequestBody ​…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)

本期内容并不是很难&#xff0c;相信大家会学的很愉快&#xff0c;当然对于有后端基础的朋友来说&#xff0c;本期内容更加容易了解&#xff0c;当然没有基础的也别担心&#xff0c;本期内容会详细解释有关内容 本期用到的软件&#xff1a;yakit&#xff08;因为经过之前好多期…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)

船舶制造装配管理现状&#xff1a;装配工作依赖人工经验&#xff0c;装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书&#xff0c;但在实际执行中&#xff0c;工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...

Linux离线(zip方式)安装docker

目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1&#xff1a;修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本&#xff1a;CentOS 7 64位 内核版本&#xff1a;3.10.0 相关命令&#xff1a; uname -rcat /etc/os-rele…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

mac 安装homebrew (nvm 及git)

mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用&#xff1a; 方法一&#xff1a;使用 Homebrew 安装 Git&#xff08;推荐&#xff09; 步骤如下&#xff1a;打开终端&#xff08;Terminal.app&#xff09; 1.安装 Homebrew…...