—— BeautifulSoup 数据提取
from bs4 import BeautifulSoup # pip install beautifulsoup4
html = """
<html>
<head><title>测试页面</title></head>
<body>
<h1 class="title">欢迎</h1>
<div id="content">
<ul class="list">
<li>项目1</li>
<li>项目2</li>
<li>项目3</li>
</ul>
<a href="https://example.com" target="_blank">链接</a>
</div>
</body>
</html>
"""
soup = BeautifulSoup(html, "html.parser")
# 获取标签
print(soup.title.string) # 测试页面
print(soup.h1.string) # 欢迎
print(soup.find("h1").string) # 欢迎
# 获取属性
link = soup.find("a")
print(link["href"]) # https://example.com
print(link["target"]) # _blank
print(link.get("href")) # 安全获取,不存在返回 None
# 获取文本
print(soup.h1.text) # 欢迎
print(soup.h1.get_text(strip=True)) # 去除空白
from bs4 import BeautifulSoup
# find - 找第一个
soup.find("div") # 标签名
soup.find("div", id="content") # 标签+id
soup.find("h1", class_="title") # 标签+class(注意class_)
soup.find("a", attrs={"target": "_blank"}) # 任意属性
# find_all - 找所有
soup.find_all("li") # 所有 li
soup.find_all("li", limit=2) # 最多2个
soup.find_all(["h1", "h2", "h3"]) # 多种标签
# CSS 选择器(推荐!更灵活)
soup.select(".title") # class
soup.select("#content") # id
soup.select("ul.list li") # 后代
soup.select("ul.list > li") # 直接子元素
soup.select("a[href]") # 有 href 属性的 a
soup.select("a[target='_blank']") # 属性值匹配
soup.select("li:nth-child(2)") # 第二个 li
# select_one - 找第一个(等于 find)
soup.select_one("h1.title")
# 遍历
for li in soup.select("ul.list li"):
print(li.get_text(strip=True))
from bs4 import BeautifulSoup
html = """
<table class="data-table">
<thead>
<tr><th>姓名</th><th>年龄</th><th>城市</th></tr>
</thead>
<tbody>
<tr><td>张三</td><td>28</td><td>北京</td></tr>
<tr><td>李四</td><td>32</td><td>上海</td></tr>
<tr><td>王五</td><td>25</td><td>深圳</td></tr>
</tbody>
</table>
"""
def extract_table(soup) -> list[dict]:
"""提取 HTML 表格数据"""
# 获取表头
headers = [th.get_text(strip=True)
for th in soup.select("table.data-table thead th")]
# 获取数据行
rows = []
for tr in soup.select("table.data-table tbody tr"):
cells = [td.get_text(strip=True) for td in tr.select("td")]
rows.append(dict(zip(headers, cells)))
return rows
soup = BeautifulSoup(html, "html.parser")
data = extract_table(soup)
# [{'姓名': '张三', '年龄': '28', '城市': '北京'}, ...]
import requests
import time
from pathlib import Path
# 1. 遵守 robots.txt
# 2. 控制请求频率
# 3. 设置 User-Agent
# 4. 尊重网站资源
class PoliteScraper:
"""礼貌的爬虫"""
def __init__(self, delay: float = 1.0):
self.session = requests.Session()
self.session.headers.update({
"User-Agent": "MyBot/1.0 (Educational Purpose)",
"Accept": "text/html",
})
self.delay = delay
self.last_request = 0
def fetch(self, url: str) -> str:
"""获取页面(自动限速)"""
import time
elapsed = time.time() - self.last_request
if elapsed < self.delay:
time.sleep(self.delay - elapsed)
resp = self.session.get(url, timeout=10)
resp.raise_for_status()
self.last_request = time.time()
return resp.text
# 缓存已抓取页面(避免重复请求)
def cached_fetch(url: str, cache_dir: str = ".cache") -> str:
"""带缓存的页面获取"""
import hashlib
cache_path = Path(cache_dir) / hashlib.md5(url.encode()).hexdigest()
if cache_path.exists():
return cache_path.read_text(encoding="utf-8")
resp = requests.get(url, timeout=10,
headers={"User-Agent": "MyBot/1.0"})
resp.raise_for_status()
cache_path.parent.mkdir(parents=True, exist_ok=True)
cache_path.write_text(resp.text, encoding="utf-8")
return resp.text
#!/usr/bin/env python3
"""第17课 网页爬虫验证"""
from bs4 import BeautifulSoup
def test_basic_parsing():
"""基本解析测试"""
html = "<html><head><title>测试</title></head><body><h1>Hello</h1></body></html>"
soup = BeautifulSoup(html, "html.parser")
assert soup.title.string == "测试"
assert soup.h1.string == "Hello"
print("✅ 基本解析测试通过")
def test_find_elements():
"""元素查找测试"""
html = """
<div id="main">
<h1 class="title">标题</h1>
<ul class="list">
<li>A</li><li>B</li><li>C</li>
</ul>
<a href="https://example.com">链接</a>
</div>
"""
soup = BeautifulSoup(html, "html.parser")
assert soup.find("h1", class_="title").string == "标题"
assert soup.find("div", id="main") is not None
assert soup.find("a")["href"] == "https://example.com"
lis = soup.find_all("li")
assert len(lis) == 3
print("✅ 元素查找测试通过")
def test_css_selector():
"""CSS选择器测试"""
html = """
<div class="container">
<ul class="items">
<li class="item">1</li>
<li class="item active">2</li>
<li class="item">3</li>
</ul>
</div>
"""
soup = BeautifulSoup(html, "html.parser")
items = soup.select("li.item")
assert len(items) == 3
active = soup.select_one("li.active")
assert active.string == "2"
print("✅ CSS选择器测试通过")
def test_table_extraction():
"""表格提取测试"""
html = """
<table>
<tr><th>名称</th><th>值</th></tr>
<tr><td>A</td><td>100</td></tr>
<tr><td>B</td><td>200</td></tr>
</table>
"""
soup = BeautifulSoup(html, "html.parser")
headers = [th.get_text(strip=True) for th in soup.select("th")]
rows = []
for tr in soup.select("tr")[1:]:
cells = [td.get_text(strip=True) for td in tr.select("td"]
if cells:
rows.append(dict(zip(headers, cells)))
assert len(rows) == 2
assert rows[0]["名称"] == "A"
print("✅ 表格提取测试通过")
if __name__ == "__main__":
test_basic_parsing()
test_find_elements()
test_css_selector()
test_table_extraction()
print("\n🎉 第17课全部验证通过!")