从 BeautifulSoup 迁移到 Scrapling¶
如果已经熟悉 BeautifulSoup,使用 Scrapling 会很容易上手。Scrapling 速度更快,提供相同的解析能力,还增加了 BeautifulSoup 没有的解析方法,以及获取和处理现代网页的功能。本指南帮助你将现有 BeautifulSoup 代码快速改为使用 Scrapling。
下表列出了网页抓取中最常见的操作。每一行展示了 BeautifulSoup 的写法和 Scrapling 中对应的方法。
BeautifulSoup 的某些快捷写法在 Scrapling 中不存在,这也是 BeautifulSoup 更慢的原因之一。如果一个功能已经能用简短的一行代码实现,就没必要为了再缩短一点而牺牲性能 :)
| 任务 | BeautifulSoup 代码 | Scrapling 代码 |
|---|---|---|
| 导入 Parser | from bs4 import BeautifulSoup |
from scrapling.parser import Selector |
| 解析字符串中的 HTML | soup = BeautifulSoup(html, 'html.parser') |
page = Selector(html) |
| 查找单个元素 | element = soup.find('div', class_='example') |
element = page.find('div', class_='example') |
| 查找多个元素 | elements = soup.find_all('div', class_='example') |
elements = page.find_all('div', class_='example') |
| 查找单个元素(示例 2) | element = soup.find('div', attrs={"class": "example"}) |
element = page.find('div', {"class": "example"}) |
| 查找单个元素(示例 3) | element = soup.find(re.compile("^b")) |
element = page.find(lambda e: re.search(r"^b", e.tag) is not None) |
| 查找单个元素(示例 4) | element = soup.find(lambda e: len(list(e.children)) > 0) |
element = page.find(lambda e: len(e.children) > 0) |
| 查找单个元素(示例 5) | element = soup.find(["a", "b"]) |
element = page.find(["a", "b"]) |
| 按文本内容查找元素 | element = soup.find(text="some text") |
element = page.find_by_text("some text", partial=False) |
| 用 CSS 选择器查找第一个匹配元素 | elements = soup.select_one('div.example') |
elements = page.css('div.example').first |
| 用 CSS 选择器查找所有匹配元素 | elements = soup.select('div.example') |
elements = page.css('div.example') |
| 获取格式化后的页面或元素源码 | prettified = soup.prettify() |
prettified = page.prettify() |
| 获取未格式化的页面或元素源码 | source = str(soup) |
source = page.html_content |
| 获取元素的标签名 | name = element.name |
name = element.tag |
| 提取元素的文本内容 | string = element.string |
string = element.text |
| 提取文档或标签下的全部文本 | text = soup.get_text(strip=True) |
text = page.get_all_text(strip=True) |
| 访问属性字典 | attrs = element.attrs |
attrs = element.attrib |
| 提取属性 | attr = element['href'] |
attr = element['href'] |
| 访问父元素 | parent = element.parent |
parent = element.parent |
| 获取元素的所有祖先 | parents = list(element.parents) |
parents = list(element.iterancestors()) |
| 在祖先中查找一个元素 | target_parent = element.find_parent("a") |
target_parent = element.find_ancestor(lambda p: p.tag == 'a') |
| 获取所有兄弟元素 | 不支持 | siblings = element.siblings |
| 获取下一个兄弟元素 | next_element = element.next_sibling |
next_element = element.next |
| 在兄弟元素中查找一个元素 | target_sibling = element.find_next_sibling("a")target_sibling = element.find_previous_sibling("a") |
target_sibling = element.siblings.search(lambda s: s.tag == 'a') |
| 在兄弟元素中查找多个元素 | target_sibling = element.find_next_siblings("a")target_sibling = element.find_previous_siblings("a") |
target_sibling = element.siblings.filter(lambda s: s.tag == 'a') |
| 在后续元素中查找一个元素 | target_parent = element.find_next("a") |
target_parent = element.below_elements.search(lambda p: p.tag == 'a') |
| 在后续元素中查找多个元素 | target_parent = element.find_all_next("a") |
target_parent = element.below_elements.filter(lambda p: p.tag == 'a') |
| 在祖先中查找一个元素 | target_parent = element.find_previous("a") ¹ |
target_parent = element.path.search(lambda p: p.tag == 'a') |
| 在祖先中查找多个元素 | target_parent = element.find_all_previous("a") ¹ |
target_parent = element.path.filter(lambda p: p.tag == 'a') |
| 获取上一个兄弟元素 | prev_element = element.previous_sibling |
prev_element = element.previous |
| 访问子元素 | children = list(element.children) |
children = element.children |
| 获取所有后代元素 | children = list(element.descendants) |
children = element.below_elements |
| 选择 story 类段落内的链接 | group = soup.select('p.story a') |
group = page.css('p.story a') |
直接传给 Scrapling find() 或 find_all() 的已编译正则表达式,匹配的是元素文本,而不是标签名。要匹配标签名,使用表中的 lambda;要直接匹配文本,可以使用 page.find_by_regex(r"^b")。
¹ 注意: BS4 的 find_previous/find_all_previous 会按文档顺序搜索所有先前元素,而 Scrapling 的 path 只返回祖先,也就是父元素链。它们并非完全等价,但祖先搜索能覆盖最常见的场景。
一个重要区别:BeautifulSoup 提供了在解析后修改页面的功能。Scrapling 更专注于快速提取数据,然后交给用户自行处理。两者都能用于网页抓取,但其中一个专门为此设计 :)
完整示例¶
下面分别使用 BeautifulSoup 和 Scrapling,提取页面中的所有链接。
使用 BeautifulSoup:
import requests
from bs4 import BeautifulSoup
url = 'https://example.com'
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
links = soup.find_all('a')
for link in links:
print(link['href'])
使用 Scrapling:
from scrapling import Fetcher
url = 'https://example.com'
page = Fetcher.get(url)
links = page.css('a::attr(href)').getall()
for link in links:
print(link)
Scrapling 将获取和解析合为一步,让代码更简洁、效率更高。
补充说明:
- 不同的 Parser:BeautifulSoup 允许选择解析引擎,例如
lxml。Scrapling 出于性能考虑,默认使用lxml库。 - 元素类型:BeautifulSoup 中的元素是
Tag对象,Scrapling 中的是Selector对象。它们提供类似的导航和数据提取方法及属性。 - 错误处理:找不到元素时,两者都返回
None,例如soup.find()或page.find()。Scrapling 的page.css()在没有匹配元素时返回空的Selectors列表。可以用page.css('.foo').first安全地获取第一个结果或None。访问属性前,先检查结果是否为None或为空。 - 文本提取:Scrapling 通过
TextHandler提供更多文本处理方法,例如clean(),可以帮助移除多余空白、连续空格或不需要的字符。完整列表请查看文档。
文档会更详细地介绍 Scrapling 的功能,并列出各方法支持的全部参数。
希望本指南能让从 BeautifulSoup 到 Scrapling 的迁移更顺利。祝抓取顺利!