大学英文网站建设,赣州律师网站建设,想建一个自己的网站,网页制作与网站建设技术大全 下载前言:
提高抓取和解析效率的根本还是在于发送请求;如何从这个方面进行效率提升呢?
深入使用requests.Session() 深入使用requests.Session()
1.持久连接#xff1a;
当使用 requests.Session() 时#xff0c;连接会话中所有的请求将优先使用一个TCP连接#xff0c;即“…前言:
提高抓取和解析效率的根本还是在于发送请求;如何从这个方面进行效率提升呢?
深入使用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(levellogging.WARNING, format%(asctime)s - %(levelname)s - %(message)s)url https://example.comtry:response requests.get(url, timeout10)response.raise_for_status()except HTTPError as http_err:logging.warning(fHTTP错误发生了{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(levellogging.WARNING, format%(asctime)s - %(levelname)s - %(message)s)html_doc
htmltitleThis 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})对于Beautiful Soup在操作前应检查返回对象是否为预期的标签可以简单通过条件语句实现例如if soup.title: 尝试将异常处理模块化以便在多处爬虫代码中重复使用。例如可能为网络请求定义一个函数并以此处理所有网络请求相关的异常。 针对预期可能发生的错误可以定义明确的异常处理逻辑如网络信号弱时重试操作等。 最重要的是编写清晰、易读且易于维护的代码异常处理也要紧密跟随这个准则。 使用多线程和并发
当处理的网页数量庞大时这一过程往往相当耗时。在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_workers5) 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/productsdef 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密集型任务中表现良好但GILGlobal 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(processes2)results pool.map(fetch_and_parse, urls)pool.close()pool.join()for title in results:print(title)通过创建一个基于进程的ThreadPool来完成并发执行这样就可以绕过GIL的限制适用于任何数目的cpu密集型和I/O密集型任务。 运用多线程和并发可以大量缩短网页数据处理的时间对于领域内从事数据采集和分析的从业者来说这是提升工作效率的重要方法。希望通过本文您能利用Python提供的并发工具更高效地实现爬虫和数据解析任务。