brainstorming
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or planning anything new, in software or out of it (a talk, a business, a renovation).
headless-web-scraping使用 scrapling Python 库从网页提取数据 —— 根据目标网站防御选择适当的 fetcher 层(HTTP、stealth Chromium 或完整浏览器自动化)、配置无头浏览, 并使用 CSS 选择器提取结构化数据。当 WebFetch 不足以应对 JS 渲染页面、 反机器人保护的站点,或需要 DOM 遍历的结构化多元素提取时使用。
Independent GitHub snapshot · Automated classification · Original documentation governs
使用 scrapling 的三层 fetcher 架构和基于 CSS 的数据提取,从抗拒简单 HTTP 请求的网页 —— JS 渲染内容、Cloudflare 保护的站点和动态 SPA —— 提取数据。
WebFetch 或 requests.get() 返回空或被阻止的响应确定哪个 scrapling fetcher 匹配目标站点的防御。
# Decision matrix:
# 1. Fetcher — static HTML, no JS, no anti-bot (fastest)
# 2. StealthyFetcher — Cloudflare/Turnstile, TLS fingerprint checks
# 3. DynamicFetcher — JS-rendered SPAs, click/scroll interactions
# Quick probe: try Fetcher first, escalate on failure
from scrapling import Fetcher
fetcher = Fetcher()
response = fetcher.get("https://example.com/target-page")
if response.status == 200 and response.get_all_text():
print("Fetcher tier sufficient")
else:
print("Escalate to StealthyFetcher or DynamicFetcher")
| 信号 | 推荐层 |
|---|---|
| 静态 HTML、无保护 | Fetcher |
| 403/503、Cloudflare 挑战页 | StealthyFetcher |
| 页面加载但内容区为空 | DynamicFetcher |
| 需要点击按钮或滚动 | DynamicFetcher |
| 存在 altcha CAPTCHA | 无(无法自动化) |
预期结果: 识别三层之一。对大多数现代站点,StealthyFetcher 是正确起点。
失败处理: 若所有三层都返回被阻止响应,检查站点是否使用 altcha CAPTCHA(无法绕过的工作量证明挑战)。若是,记录限制并改为提供手动提取说明。
用适当选项设置选定的 fetcher。
from scrapling import Fetcher, StealthyFetcher, DynamicFetcher
# Tier 1: Fast HTTP with TLS fingerprint impersonation
fetcher = Fetcher()
fetcher.configure(
timeout=30,
retries=3,
follow_redirects=True
)
# Tier 2: Headless Chromium with anti-detection
fetcher = StealthyFetcher()
fetcher.configure(
headless=True,
timeout=60,
network_idle=True # wait for all network requests to settle
)
# Tier 3: Full browser automation
fetcher = DynamicFetcher()
fetcher.configure(
headless=True,
timeout=90,
network_idle=True,
wait_selector="div.results" # wait for specific element before extracting
)
预期结果: Fetcher 实例已配置并就绪。实例化时无错误。对 StealthyFetcher 和 DynamicFetcher,Chromium 二进制可用(scrapling 在首次运行时自动管理)。
失败处理:
playwright 或浏览器二进制未找到 —— 运行 python -m playwright install chromiumconfigure() 上超时 —— 增加超时值或检查网络连接pip install scrapling导航到目标 URL 并使用 CSS 选择器提取结构化数据。
# Fetch the page
response = fetcher.get("https://example.com/target-page")
# Single element extraction
title = response.find("h1.page-title")
if title:
print(title.get_all_text())
# Multiple elements
items = response.find_all("div.result-item")
for item in items:
name = item.find("span.name")
price = item.find("span.price")
print(f"{name.get_all_text()}: {price.get_all_text()}")
# Get attribute values
links = response.find_all("a.product-link")
urls = [link.get("href") for link in links]
# Get raw HTML content of an element
detail_html = response.find("div.description").html_content
关键 API 参考:
| 方法 | 用途 |
|---|---|
response.find("selector") | 第一个匹配元素 |
response.find_all("selector") | 所有匹配元素 |
element.get("attr") | 属性值(href、src、data-*) |
element.get_all_text() | 所有文本内容,递归 |
element.html_content | 原始内部 HTML |
预期结果: 提取的数据匹配可见页面内容。元素非 None,文本内容对填充页面非空。
失败处理:
find() 返回 None —— 检查实际 HTML(response.html_content)以验证选择器;页面可能使用与预期不同的类名get_all_text() 文本为空 —— 内容可能在 shadow DOM 或 iframe 中;尝试带 wait_selector 的 DynamicFetcher.css_first() —— 这不是 scrapling API 的一部分(与其他库的常见混淆)为 CAPTCHA 检测、空响应和会话要求实现回退逻辑。
import time
def scrape_with_fallback(url, selector):
"""Try each fetcher tier in order, with CAPTCHA detection."""
tiers = [
("Fetcher", Fetcher),
("StealthyFetcher", StealthyFetcher),
("DynamicFetcher", DynamicFetcher),
]
for tier_name, tier_class in tiers:
fetcher = tier_class()
fetcher.configure(headless=True, timeout=60)
try:
response = fetcher.get(url)
except Exception as error:
print(f"{tier_name} failed: {error}")
continue
# Detect CAPTCHA / challenge pages
page_text = response.get_all_text().lower()
if "altcha" in page_text or "proof of work" in page_text:
print(f"altcha CAPTCHA detected -- cannot automate")
return None
if response.status == 403 or response.status == 503:
print(f"{tier_name} blocked (HTTP {response.status}), escalating")
continue
result = response.find(selector)
if result and result.get_all_text().strip():
return result.get_all_text()
print(f"{tier_name} returned empty content, escalating")
print("All tiers exhausted. Manual extraction required.")
return None
预期结果: 函数在成功时返回提取的文本,或在所有层失败时返回带诊断消息的 None。CAPTCHA 页被检测并报告,而非无限重试。
失败处理:
在大规模运行前实现延迟并尊重站点政策。
import time
import urllib.robotparser
def check_robots_txt(base_url, target_path):
"""Check if scraping is allowed by robots.txt."""
rp = urllib.robotparser.RobotFileParser()
rp.set_url(f"{base_url}/robots.txt")
rp.read()
return rp.can_fetch("*", f"{base_url}{target_path}")
def scrape_urls(urls, selector, delay=1.0):
"""Scrape multiple URLs with rate limiting."""
results = []
fetcher = StealthyFetcher()
fetcher.configure(headless=True, timeout=60)
for url in urls:
response = fetcher.get(url)
data = response.find(selector)
if data:
results.append(data.get_all_text())
time.sleep(delay) # respect the server
return results
道德抓取检查清单:
robots.txt —— 尊重 Disallow 指令预期结果: 抓取以受控速率运行。在批量操作前检查 robots.txt。未触发 429 响应。
失败处理:
robots.txt 不允许路径 —— 尊重指令;不要覆盖configure() 方法(非已弃用的构造函数 kwargs).find() / .find_all() API(非 .css_first() 或其他库方法)robots.txt.css_first() 而非 .find():scrapling 使用 .find() 和 .find_all() 进行元素选择 —— .css_first() 属于不同库且会引发 AttributeErrorFetcher,再升级 —— DynamicFetcher 因完整浏览器启动慢 10-50 倍configure():scrapling v0.4.x 弃用了向构造函数传递选项;始终使用 configure() 方法