Python爬虫技术 第14节 HTML结构解析
HTML 结构解析是 Web 爬虫中的核心技能之一,它允许你从网页中提取所需的信息。Python 提供了几种流行的库来帮助进行 HTML 解析,其中最常用的是 BeautifulSoup
和 lxml
。
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 自带的标准库、lxml
和 html5lib
。
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 渲染的内容或者分页等。
在我们已经讨论的基础上,让我们进一步扩展代码,以便处理更复杂的场景,比如分页、错误处理、日志记录以及数据持久化。我们将继续使用 requests
和 BeautifulSoup
,并引入 logging
和 sqlite3
来记录日志和存储数据。
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_all
和 find
方法的参数。
既然我们已经有了一个基本的框架来抓取分页数据并存储到 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 请求无法获取完整的内容。这时可以使用 Selenium
或 Pyppeteer
等库来模拟浏览器行为。这里以 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 欢迎来到我的主页,我是博主英杰,…...

怎样在 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() 方法是一个强大的工具,适合于需要将数组中的每个元素转换为新形式的情况。然而,对于性能敏感的应用或需要更复杂控制逻辑的场景,可能需要考虑其他方法。 优点: 函数式编程风格:…...

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

基于微信小程序+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 "…...

.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...

苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...

Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...

Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...

短视频矩阵系统文案创作功能开发实践,定制化开发
在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...
苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会
在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...