让 Python 的Beautiful Soup在抓取时更快的 10 个技巧
在本指南中,我将分享 10 个简单的技巧,帮助您加快 Beautiful Soup抓取 项目。这些技巧将让您更快、更高效地进行刮擦,而不会失去准确性或遗漏重要数据。让我们开始吧
通过请求会话优化网络请求
Beautiful Soup 主要是一款解析工具,这意味着它可以在获取数据后工作。但是,任何网络抓取任务的第一步都是从网站获取 HTML 或 XML,通常是通过 requests 库完成的。一个常见的错误是,为每一个页面都发送一个新的 requests.get() 调用。这种做法效率很低,因为每次请求都要建立新的连接,执行 DNS 查询以及可能的 SSL 握手。
解决方案:使用 requests.Session()。请求中的会话对象会在多个请求中持续存在,并重复使用底层 TCP 连接,这可以大大减少网络开销所花费的时间。
例如
import requests
session = requests.Session()
response = session.get('https://example.com')
会话可以缩短扫描多个页面时的响应时间,使整个过程更快。
限制解析范围
Beautiful Soup 允许你解析整个文档,但如果你知道自己感兴趣的 HTML 的特定部分,直接针对该部分进行解析会更有效率。与其解析整个文档,不如将解析范围限制在特定标记或部分。
解决方案:使用 find() 或 find_all() 方法缩小搜索范围。这样可以防止 Beautiful Soup 扫描 HTML 中不必要的部分。
例如
soup = BeautifulSoup(html_doc、 html.parser)
# Target specific section
content = soup.find(div, {'class': 'content'})
通过缩小搜索范围,可以大大加快解析速度,尤其是对于大型 HTML 文档。
使用正确的解析器
Beautiful Soup 支持多种解析器,例如 HTML.parser、XML 和 HTML5lib.每个解析器都有不同的性能特点。默认情况下,Beautiful Soup 使用 Python 内置的 HTML.parser 虽然方便,但不是最快的。
解决方案:改用速度更快的解析器,如 XML,这是一种高度优化的基于 C 的解析器,可大幅缩短解析时间。
例如
from bs4 import BeautifulSoup
# Use lxml parser for faster performance
soup = BeautifulSoup(html_doc、 lxml)
改用 lxml 可以通过以下方式提高 Beautiful Soup 脚本的性能 高达 10 倍.
缓存重复解析任务
如果您要重复扫描相同或类似的 HTML 结构,可以通过缓存解析数据的结果来节省时间。这在多次扫描同一网站时尤其有用。
解决方案:使用 functools.lru_cache 等库缓存昂贵的解析操作结果。
例如
from bs4 import BeautifulSoup
from functools import lru_cache
@lru_cache(maxsize=100)
def parse_html(html):
return BeautifulSoup(html、 lxml)
# Now the parsing is cached
soup = parse_html(html_doc)
通过缓存已解析的数据,可以避免冗余解析并加快重复操作的速度。
使用多线程
同时抓取多个页面可以加快整个过程。Beautiful Soup 本身不是线程安全的,但请求库是。你可以使用多线程同时获取多个页面,然后用 Beautiful Soup 并行处理每个页面。
解决方案:使用 Python 的 concurrent.futures 或 threading 在网络搜索代码中实现多线程。
例如
import concurrent.futures
import requests
from bs4 import BeautifulSoup
urls = ['https://example.com/page1', 'https://example.com/page2']
def fetch_page(url):
response = requests.get(url)
return BeautifulSoup(response.content、 lxml)
with concurrent.futures.ThreadPoolExecutor() as executor:
results = executor.map(fetch_page, urls)
# Process results faster
for soup in results:
print(soup.title.text)
使用多线程,您可以一次获取并解析多个页面,从而缩短搜索任务的总体时间。
限制 DOM 遍历深度
有时,您可能会过度浏览 DOM 的方法。Beautiful Soup 允许你通过 .find_parent()、.find_next_sibling() 和其他方法遍历 DOM 树。虽然这些方法很有用,但不必要的遍历会拖慢你的搜刮引擎。
解决方案:避免深度和重复的 DOM 遍历。准确了解所需的元素并直接访问它,而无需依赖多个遍历层。
例如
# Instead of chaining multiple navigations
element = soup.find(div).find_next_sibling().find('span')
# Target the specific element directly
element = soup.select_one(div + span)
减少 DOM 遍历的深度可提高搜索效率,减少不必要的处理时间。
解析前预处理 HTML
有时,您抓取的 HTML 中会出现不必要的空白、注释或 JavaScript,从而减慢解析速度。对 HTML 进行预处理,删除不必要的部分,可以加快解析阶段的速度。
解决方案:使用正则表达式或字符串方法对 HTML 进行预处理和清理,然后再将其传递给 Beautiful Soup。
例如
import re
# Remove script tags and comments before parsing
cleaned_html = re.sub(r'<script.*?', '', html_doc)
cleaned_html = re.sub(r'<!- .*?→', '', cleaned_html)
soup = BeautifulSoup(cleaned_html、 lxml)
通过这种方式对 HTML 进行预处理,可以减轻 Beautiful Soup 的负担,提高解析速度。
批量处理多个页面
在抓取多个页面时,批量处理比一次抓取、解析和保存一个页面更有效率。通过批处理任务,可以减少在不同操作之间不断切换的开销。
解决方案:使用会话一次获取多个页面,并分批处理。
例如
import requests
from bs4 import BeautifulSoup
session = requests.Session()
urls = ['https://example.com/page1', 'https://example.com/page2']
响应 = [session.get(url) for url in urls]
soups = [BeautifulSoup(response.content、 lxml) for response in responses]
# Now process the soups
for soup in soups:
print(soup.title.text)
同时批量处理多个页面可优化网络请求和解析操作。
简化数据提取
如果要重复提取相同的元素,可以预先定义所需的元素,避免使用复杂的 CSS 选择器,从而提高数据提取的速度。
解决方案:使用简单的选择器或 XPath 直接访问元素,减少复杂的搜索操作。
例如
# Instead of using multiple class or id selectors
title = soup.find(div, {'class': 'article-title'}).find('h1')
# Use a more direct CSS selector or XPath
title = soup.select_one('.article-title h1')
直接访问方法比连锁多个查找操作要快得多,并能降低搜索代码的复杂性。
简介您的代码
最后,如果您仍然遇到性能问题,最好对代码进行剖析以找出瓶颈。Python 有像 cProfile 这样的内置工具,可以帮助您找出代码中速度较慢的部分。
解决方案:使用 cProfile 测量不同功能所花费的时间,并确定需要优化的领域。
例如
import cProfile
def scrape_site():
# Your scraping code here
pass
cProfile.run(scrape_site())
对代码进行剖析,可以让您了解刮擦过程中哪些部分耗时最长,从而有效集中优化工作。
高效解析 HTML 的 7 个技巧
以下是一些高效解析 HTML 的简单技巧:
- 浏览 DOM 树 DOM 就像一棵代表 HTML 结构的对象树。了解它有助于快速提取数据。
- 遍历 DOM 使用 .parent 查看父元素,使用 .children 循环查看子元素。使用 .next_sibling 和 .previous_sibling 在同级元素之间移动。
- 搜索 DOM: 使用 find() 或 find_all() 查询特定标记和属性,或使用 select() 查询 CSS 样式。
- 处理大型文件: 要加快大型文件的解析速度,可使用 lxml 解析器,并考虑安装 腌菜 以加快编码检测速度。SoupStrainer 还可以帮助限制解析的内容。
- 修改解析树 Beautiful Soup 允许你添加、删除或编辑 HTML 元素,这对清理数据很有帮助。
- 错误处理和日志记录 用 try-except 块封装代码,以处理畸形 HTML 等错误,并记录这些问题以便调试。
- 与其他工具集成: 对于 JavaScript 较多的网站,可将 Beautiful Soup 与 Selenium 或 Playwright 等工具一起使用,以有效地刮擦动态内容。
结论
Beautiful Soup 是一款出色的网络搜索工具,但如果优化不当,运行速度可能会变慢。我了解到,我们可以通过一些调整让它运行得更快,比如选择正确的解析器、减少我们搜索网页的数量,以及使用 SoupStrainer 等工具。我还使用会话缓存和多线程来进一步加快速度。这些改变让搜索变得更快、更可靠,也更容易随着项目的增长而扩展。