Scrapling Python 网页抓取实战指南:先跑通一个页面,再考虑扩展
【免费下载链接】Scrapling🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl!项目地址: https://gitcode.com/GitHub_Trending/sc/Scrapling
如果你需要写 Python 爬虫,先要面对一个老问题:目标页面的结构会随时变,今天能取到价格的 CSS 选择器,下周改版后可能就空了。Scrapling 是一个 Python 网页抓取框架,定位是"从单个请求到整站爬取"的完整链路:内置多档请求器、带自适应能力的内容解析器,以及支持并发、暂停恢复的 Spider 框架。本文以"把列表页数据稳定取出来并导出"为主线,走完安装、取数、导出、排错和调参五步。
它解决哪几类取数问题
- 纯静态页面:商品详情、API 样例 JSON、公开文档页,一次 HTTP 请求就能拿到内容,不需要浏览器。
- JS 动态渲染:列表靠前端脚本插入 DOM,需要用真实浏览器等待加载完成。
- 有反爬策略的站点:请求被质询或拦截,需要更接近真实浏览器的指纹策略来降低被识别概率。
- 多页、多域名的整站任务:需要并发控制、限速、断点续抓,而不是手写循环脚本。
- 页面改版导致的维护成本:选择器失效后,需要按元素特征重新定位,而不是逐个改代码。
对号入座后再选工具,能省掉大量试错时间。
安装并跑通第一个页面
Scrapling 要求 Python 3.10 及以上。注意一个容易踩的坑:默认pip install scrapling只装了解析引擎,不带任何 fetchers,导入抓取类会直接报ModuleNotFoundError。用到了抓取能力,装完整依赖并下载浏览器:
pip install "scrapling[fetchers]" scrapling install这条命令解决"装完库却不能发请求"的问题,scrapling install会补齐浏览器及其系统依赖。
跑一段最短代码验证链路:
from scrapling.fetchers import FetcherSession with FetcherSession(impersonate="chrome") as s: page = s.get("https://quotes.toscrape.com/") print(page.status) print(page.css(".quote .text::text").getall()[:2])这段代码解决"环境是否可用"的验证:会话以 Chrome 的 TLS 指纹发一个普通请求,再取前两条引文。你会看到状态码 200 和一个两元素的文本列表,说明请求、解析、选择器三层都通了。下一步检查:把 URL 换成你的真实目标页,确认css能取到非空值。
三种 Fetcher 按场景选型
Scrapling 把请求分成三档,取舍是速度和拟真程度(选型对比 里有完整参数说明):
| 类 | 机制 | 适合 |
|---|---|---|
Fetcher/FetcherSession | 纯 HTTP,可模拟浏览器 TLS 指纹与 HTTP/3 | 静态页、API、JSON 端点 |
DynamicFetcher | Playwright 驱动的 Chromium 或 Chrome | 需要 JS 执行、小自动化 |
StealthyFetcher | 带指纹伪装的隐身浏览器 | 反爬较强、被质询拦截的页面 |
规则很直接:能用Fetcher就不要开浏览器,速度差一个量级。浏览器类 fetcher 支持cdp_url连接已在运行的远程浏览器,也支持executable_path指定自己的 Chromium 构建。遇到 Cloudflare Turnstile 质询页时,StealthyFetcher的solve_cloudflare=True是内置选项,但它是"降低被拦截概率",不是保证,仍要控制请求频率。
把 HTML 转成结构化数据
解析层对应 scrapling/parser.py,核心是Selector类;响应对象本身就是Selector,所以取到页面就能直接选。同一目标支持四种写法:
- CSS:
page.css(".quote .text::text").getall() - XPath:
page.xpath('//span[@class="text"]/text()').getall() - BeautifulSoup 风格:
page.find_all("div", class_="quote") - 按文本定位:
page.find_by_text("quote", tag="div")
父、兄弟、子节点导航都有对应方法,配合find_similar()还能按已命中的元素找同构兄弟节点。
解析器的默认配置里adaptive是关闭的。开启后配合元素存储:首次选择时把目标元素的特征记录下来,之后站点改版导致原选择器失配,用adaptive=True重新查找,可以按相似度把元素定位回来。对长期维护的取数脚本,这是减少"改版即挂"的直接手段。
任务实践:抓商品列表并导出 JSON
把前面的能力拼成一个小而完整的任务:Spider 类声明入口 URL 和并发,parse回调逐条 yield 数据,结果直接落盘。
from scrapling.spiders import Spider, Response class ProductSpider(Spider): name = "products" start_urls = ["https://example.com/catalog"] concurrent_requests = 5 async def parse(self, response: Response): for item in response.css(".product-card"): yield { "name": item.css("h2::text").get(), "price": item.css(".price::text").get(), } result = ProductSpider(crawldir="./crawl_data").start() result.items.to_json("products.json")这段代码解决"列表页→结构化文件"的完整闭环。跑完你会看到本地生成products.json;crawldir参数同时启用了检查点,中途 Ctrl+C 优雅暂停,再用同一路径启动即从断点恢复。开发期可以先用开发模式把响应缓存到磁盘回放,反复调parse逻辑而不重复打目标站。选不到数据时,优先核对选择器写法和::text伪元素位置。
常见卡点排查
- 报错
ModuleNotFoundError:装的是基础包,缺 fetchers 依赖。回到上一节,装[fetchers]后跑scrapling install。 - 选择器返回空列表:先确认页面已完整加载,再核对选择器。动态内容的页面,
DynamicFetcher传network_idle=True等待网络空闲,而不是加 sleep。 - 状态码 403 或拿到质询页:说明触发了反爬策略。按
Fetcher→DynamicFetcher→StealthyFetcher的顺序逐级升级请求器,不要靠加大频率去"撞开"。 - 请求长时间不返回:给目标页加超时并记录失败 URL,避免单点挂起拖死整批任务。
- 不写代码先验证页面:
scrapling extract get 'https://example.com' content.md可把页面直接导出为 Markdown,加--css-selector还能只取局部,适合动手前先确认页面结构。
稳定运行与适用边界
给长任务定四条规则:
- 并发从低起步,
concurrent_requests先设 5 以内;Spider 支持按域名限速和自动降速,被限流时延时会自行翻倍,恢复后再提速。 - 长任务一律挂
crawldir检查点,让中断可恢复。 - 遵守目标站条款与 robots.txt,Spider 有
robots_txt_obey开关可遵循Disallow、Crawl-delay等指令。 - 调试期用缓存回放,正式跑批再打真实站点,减少不必要的请求。
边界也说清楚:它适合公开页面、中小规模、需要一定维护成本的取数任务;不适合绕过登录认证或做大规模未授权抓取,反爬能力只应配合合理频率使用。
三个可执行的下一步:挑一个真实列表页把选择器跑通并导出 CSV;评估你的目标站是否必须换用浏览器类 fetcher;打开 scrapling/spiders/ 看并发、节流和检查点的具体参数。先跑通一个最小页面,再按请求速度、解析稳定性和被拦截情况逐项调参,比一开始就堆功能更容易收敛。
【免费下载链接】Scrapling🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl!项目地址: https://gitcode.com/GitHub_Trending/sc/Scrapling
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考