精进Beautiful Soup 小技巧(三)---综合提供效率(缓存/error/多线程/异步)

前言:

提高抓取和解析效率的根本还是在于发送请求;如何从这个方面进行效率提升呢?

深入使用requests.Session()

 深入使用requests.Session()

1.持久连接:

当使用 requests.Session() 时,连接会话中所有的请求将优先使用一个TCP连接,即“持久连接”,这样即使你发起多次对同一主机的独立请求,Session 实例会重用底层的连接,从而降低握手的开销。
import requests# 创建一个会话实例
session = requests.Session()# 向相同的主机发送多次请求
response_one = session.get('https://httpbin.org/get')
response_two = session.get('https://httpbin.org/get')# 展示使用了持久连接的行为,两个请求将通过相同的连接发送
print(id(response_one.raw._connection))
print(id(response_two.raw._connection))# 输出一样的ID,意味着使用的是同一连接# 事后一定清理:常规操作
session.close()

2.连接适配和参数预设:

Session 对象允许你自定义一些请求细节,如头信息和鉴权凭证等,并在之后的请求中保持这些设置,减少了重复代码的编写。
import requests
from requests.auth import HTTPBasicAuth# 创建会话实例,并设置默认值
session = requests.Session()
session.headers.update({'user-agent': 'my-app/0.0.1'})
session.auth = HTTPBasicAuth('username', 'password')# 现在进行的所有的请求都会发送预设的头信息
response = session.get('https://httpbin.org/headers')
print(response.text)  # 应当会见到"user-agent"和之前设定的鉴权信息# 一般在完成请求后关闭会话
session.close()

3.为请求维持Cookie状态:

Session 对象自动处理请求的 Cookies,所有发给同一个会话的请求将使用同一个Cookie jar,在这样的机制下,所有与server的会话变量都可以一次设立,然后按预期工作。
import requests# 创建会话实例
session = requests.Session()# 初次登录以设置cookie
login_res = session.post('https://example.com/login', data={'username':'xxx', 'password':'yyy'})# Session会保存服务端设置在客户端的cookie信息, 现在进行的请求都将携带这个cookie
profile_res = session.get('https://example.com/profile')# 经过验证的响应内容
print(profile_res.text)# 完成所有动作后关闭会话提释放资源
session.close()

你现在应该有了一个清晰的Session如何作为一个持久连接来降低延时的认识,如何使用Session预设请求参数和身份验证方式,以及如何维持cookies的状态以跨请求进行身份维持和通行。在所有会话结束之后,确保调用 .close() 方法至关重要,以确保资源的妥善释放。

异常处理

网络爬虫可能面临各种预料之外的问题,如网络波动、页面结构更改、服务器配置问题等。为了提高脚本的健壮性,应当合理捕获并处理这些异常。

案例1:处理网络请求异常

import requests
import logging
from requests.exceptions import HTTPError, ConnectionError, Timeout, RequestException# 配置logging,设置日志级别为WARNING,简短日志格式,并将日志输出到控制台。
logging.basicConfig(level=logging.WARNING, format='%(asctime)s - %(levelname)s - %(message)s')url = "https://example.com"try:response = requests.get(url, timeout=10)response.raise_for_status()except HTTPError as http_err:logging.warning(f"HTTP错误发生了:{http_err}")
except ConnectionError as conn_err:logging.warning(f"连接错误发生了:{conn_err}")
except Timeout as timeout_err:logging.warning(f"请求超时了:{timeout_err}")
except RequestException as err:logging.warning(f"出现了请求错误:{err}")
else:print("请求成功完成。")

案例2:处理Beautiful Soup可能的异常

from bs4 import BeautifulSoup
import logging# 配置logging,设置日志级别并输出到控制台
logging.basicConfig(level=logging.WARNING, format='%(asctime)s - %(levelname)s - %(message)s')html_doc = """
<html><title>This is title</title></html>
"""try:soup = BeautifulSoup(html_doc, "html.parser")title_text = soup.title.textexcept AttributeError as e:# 如果BeautifulSoup尝试访问不存在的属性会抛出这个错误logging.warning(f"未能找到属性。错误:{e}")except Exception as e:# 通用异常捕获,可能在解析HTML文档时遇到其他没有预料到的错误logging.error(f"发生错误:{e}")else:print(f"文档的标题是:{title_text}")
  1. 对于Beautiful Soup,在操作前应检查返回对象是否为预期的标签,可以简单通过条件语句实现,例如:if soup.title:
  2. 尝试将异常处理模块化,以便在多处爬虫代码中重复使用。例如,可能为网络请求定义一个函数,并以此处理所有网络请求相关的异常。
  3. 针对预期可能发生的错误,可以定义明确的异常处理逻辑,如网络信号弱时重试操作等。
  4. 最重要的是编写清晰、易读且易于维护的代码,异常处理也要紧密跟随这个准则。

使用多线程和并发

当处理的网页数量庞大时,这一过程往往相当耗时。在Python中通过threading和concurrent.futures模块将Beautiful Soup的使用并行化,显著提升效率。

多线程基础

threading模块允许我们运行多个线程(即任务)来执行代码。在网络请求和HTML解析任务中,多线程能有效减少等待I/O操作(如网络请求)的时间。

使用concurrent.futures简化多线程

concurrent.futures模块提供了一种高级别的异步执行机制,通过ThreadPoolExecutor类我们可以非常方便地创建线程池。

案例一:简单多线程HTML请求和解析

我们首先摆脱繁杂的线程管理,并且用concurrent.futures来提升我们代码的执行速度:
from concurrent.futures import ThreadPoolExecutor
import requests
from bs4 import BeautifulSoupurls = ['https://example.com','https://example.org','https://example.net',
]def fetch_and_parse(url):response = requests.get(url)soup = BeautifulSoup(response.content, 'html.parser')title = soup.title.textreturn titlewith ThreadPoolExecutor(max_workers=5) as executor:futures = [executor.submit(fetch_and_parse, url) for url in urls]for future in concurrent.futures.as_completed(futures):try:data = future.result()print(data)except Exception as exc:print(f"生成异常: {url} {exc}")
在这个案例中,ThreadPoolExecutor创建了一个线程池,异步地请求网页并解析标题标签

案例二:并发实现细粒度Html元素处理

如果网页数据解析涉及大量细致的处理,我们进一步地将Html元素的收集和处理分摊到不同线程去执行。
from concurrent.futures import ThreadPoolExecutor
import requests
from bs4 import BeautifulSoupurl = "https://example.com/products"def parse_html(html):soup = BeautifulSoup(html, "html.parser")products = soup.find_all('li', {'class': 'product'})return [product.text for product in products]def get_html(url):response = requests.get(url)return response.textwith ThreadPoolExecutor() as executor:html = executor.submit(get_html, url).result()product_texts = executor.submit(parse_html, html).result()print(product_texts)
executor.submit()负责提交任务给线程池,此处分别用独立的线程下载HTML文档和解析文档中的产品列表。

案例三:避免全局解释器锁(GIL)带来的影响

虽然threading在I/O密集型任务中表现良好,但GIL(Global Interpreter Lock,全局解释器锁)可能会在某些情况下影响效率。此时,我们可以考虑使用 Python 的 multiprocessing 模块。
from multiprocessing.pool import ThreadPool
import requests
from bs4 import BeautifulSoupurls = ["https://example.com", "https://example.org"]def fetch_and_parse(url):response = requests.get(url)soup = BeautifulSoup(response.content, 'html.parser')return soup.title.textif __name__ == '__main__':pool = ThreadPool(processes=2)results = pool.map(fetch_and_parse, urls)pool.close()pool.join()for title in results:print(title)
通过创建一个基于进程的ThreadPool来完成并发执行,这样就可以绕过GIL的限制,适用于任何数目的cpu密集型和I/O密集型任务。

运用多线程和并发可以大量缩短网页数据处理的时间,对于领域内从事数据采集和分析的从业者来说,这是提升工作效率的重要方法。希望通过本文,您能利用Python提供的并发工具,更高效地实现爬虫和数据解析任务。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/172256.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

点击url如何唤起nativescript应用程序?

1、低于ios 9.0的版本 可以使用 nativescript-urlhandler&#xff0c;通过在app.component.ts中添加handleOpenURL来实现。 2、高于ios 9.0的版本 可以使用 nativescript-community/universal-links来实现 https://github.com/nativescript-community/universal-links 安装&a…

【Amazon】基于Amazon提供的托管式EKS通过eksctl命令部署Kubernetes集群

文章目录 一、使用CloudFormation创建堡垒机二、安装AWS CLI命令行工具三、安装eksctl命令行工具四、创建集群角色4.1 集群服务角色创建4.2 集群节点组角色创建 五、创建 EKS集群六、登录EKS控制台七、参考链接 一、使用CloudFormation创建堡垒机 导航至CloudFormation&#xf…

Kafka(二)在WSL搭建Schema Registry

目录 1 Avro与Schema Registry2 搭建Schema Registry2.1 下载Confluent并解压2.2 设置环境变量2.3 修改配置2.4 启动服务 3 API列表 1 Avro与Schema Registry Apache Avro 是一种高效的数据序列化系统&#xff0c;用于在不同的应用程序和平台之间传输和存储数据。它提供了一种…

AI智能客服搭建教程附带免费源码

*名称* *版本要求* 服务器 CPU 2核心 ↑运存 4G ↑宽带 5M ↑ 服务器操作系统 Linux Centos7 运行环境 Nginx 1.18 PHP 7.3 MYSQL 5.6 服务器配置及环境要求 PHP设置 一、安装PHP扩展插件:fileinfo、redis、 sg11 二、删除PHP对应版本中的 pcntl_signal 、pcntl_signal_dis…

python类和对象

1.使用对象组织数据 class Student:nameNone #记录名字 stu1Student() #创建对象 stu1.name"abc" #为对象属性赋值2.类的定义和使用 2.1成员方法的定义语法 传参的时候self是透明的&#xff0c;不用管 class Stu:nameNonedef sayHi(self):print(f"你好&#x…

【数据中台】开源项目(1)-LarkMidTable

LarkMidTable 是一站式开源的数据中台&#xff0c;实现中台的 基础建设&#xff0c;数据治理&#xff0c;数据开发&#xff0c;监控告警&#xff0c;数据服务&#xff0c;数据的可视化&#xff0c;实现高效赋能数据前台并提供数据服务的产品。 系统演示地址 &#xff1a; www.l…

Windows 7隐藏用户测试

请注意Window 7是在虚拟机上安装的&#xff0c;ip是192.168.0.108。 下边都是在虚拟机Window 7上操作&#xff0c;直到最后远程连接才在自己本机Windows 11上操作。 需要同时按下Windowsr,然后输入cmd&#xff0c;再点击确定。 在命令上里边输入net user可以显示一下用户。 …

C语言学习笔记之函数篇

与数学意义上的函数不同&#xff0c;C语言中的函数又称为过程&#xff0c;接口&#xff0c;具有极其重要的作用。教科书上将其定义为&#xff1a;程序中的子程序。 在计算机科学中&#xff0c;子程序&#xff08;英语&#xff1a;Subroutine, procedure, function, routine, me…

React 入门使用 (官方文档向 Part2)

文章目录 用 State 响应输入声明式地考虑 UI步骤 1&#xff1a;定位组件中不同的视图状态步骤 2&#xff1a;确定是什么触发了这些状态的改变步骤 3&#xff1a;通过 useState 表示内存中的 state步骤 4&#xff1a;删除任何不必要的 state 变量步骤 5&#xff1a;连接事件处理…

TypeScript 中的type与interface

TypeScript 中的type与interface 对于 TypeScript&#xff0c;有两种定义类型的方法&#xff1a;type与interface。 人们常常想知道该使用哪一种&#xff0c;而答案并不是一刀切的。这确实取决于具体情况。有时&#xff0c;其中一种比另一种更好&#xff0c;但在许多情况下&a…

059-第三代软件开发-巧用工控板LED指示灯引脚

第三代软件开发-巧用工控板LED指示灯引脚 文章目录 第三代软件开发-巧用工控板LED指示灯引脚项目介绍巧用工控板LED指示灯引脚第一种方式第二种方式 总结 关键字&#xff1a; Qt、 Qml、 Power、 继电器、 IO 项目介绍 欢迎来到我们的 QML & C 项目&#xff01;这个项…

video标签在h5中被劫持问题

将video的视频链接转为blob export const encryptionVideo (options: URL) > {return new Promise((resolve, reject) > {window.URL window.URL || window.webkitURL;var xhr new XMLHttpRequest();xhr.open(GET, options.url, true);xhr.responseType blob;xhr.onl…

题解(讲题时备用):CF1896-D. Ones and Twos

题解(讲题时备用)&#xff1a;CF1896-D. Ones and Twos 题目链接 Problem - D - Codeforces。 思路简述 我们不难得出只要询问中s&#xff08;s>2&#xff09;行&#xff0c;s-2就也行。&#xff08;通过区间内的左端点和右端点上面的数可以得出&#xff09; 之后维护偶…

圆通速递单号查询入口,以表格的形式导出详细物流信息

批量查询圆通速递单号的物流信息&#xff0c;并以表格的形式导出单号的详细物流信息。 所需工具&#xff1a; 一个【快递批量查询高手】软件 圆通速递单号若干 操作步骤&#xff1a; 步骤1&#xff1a;运行【快递批量查询高手】软件&#xff0c;第一次使用的伙伴记得先注册&…

C++初识类和对象

前言 上一期我们介绍了一些C入门的基础知识&#xff0c;本期我们来介绍面向对象。初步认识一下面向对象和面向过程、类、以及封装&#xff01; 本期内容介绍 面向过程和面向对象 类的引入 类的定义 类的访问限定符和封装 类的作用域 类的实例化 类对象模型 this指针 一、面向…

基本数据结构二叉树(1)

目录 1.树概念及结构 1.1树的概念 1.2 树的相关概念 1.3 树的表示 1.4 树在实际中的运用&#xff08;表示文件系统的目录树结构&#xff09; 2.二叉树概念及结构 2.1概念 2.2现实中的二叉树&#xff1a; 2.3 特殊的二叉树&#xff1a; 2.5 二叉树的存储结构 2. 链式存…

【多线程】-- 03 龟兔赛跑案例线程创建方法之三:Callable接口

多线程 2 线程创建 【续】2.2 龟兔赛跑案例 首先需要一个赛道距离&#xff0c;然后会距离终点越来越近判断比赛是否结束打印出胜利者龟兔赛跑开始故事中是乌龟获胜&#xff0c;兔子需要睡觉&#xff0c;所以要模拟兔子睡觉最终&#xff0c;乌龟赢得比赛 package com.duo.de…

C语言数据类型和变量

# C语言数据类型和变量 # 数据类型介绍 C语⾔提供了丰富的数据类型来描述⽣活中的各种数据。使⽤整型类型来描述整数&#xff0c;使⽤字符类型来描述字符&#xff0c;使⽤浮点型类型来描述⼩数。所谓“类型”&#xff0c;就是相似的数据所拥有的共同特征&#xff0c;编译器只有…

[ruby on rails] array、jsonb字段

一、jsonb # 新增 add_column :shi_tis, :setting, :jsonb, default: {}# string转jsonb def changechange_column :users, :setting, :jsonb, using: setting::jsonb, default: {} end# 加索引 add_index :users, :setting, using: :gin # 这样就为setting jsonb字段创建了一…

TypeScript中的枚举是什么?

在TypeScript中&#xff0c;枚举&#xff08;Enum&#xff09;是一种用于定义一组有命名的常量值的数据类型。它们可以提供更具可读性和可维护性的代码。 枚举的作用是为一组相关的值提供一个易于理解和使用的命名空间。它们可以用于代表一系列可能的选项、状态或标志&#xf…