Scrapling 交互式 Shell 实战:基于 IPython 的 Web Scraping REPL,从 get 快捷函数到 curl 命令转换
【免费下载链接】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
Scrapling 的交互式 Shell 是一个面向 Web 抓取任务的 IPython 增强版 REPL,进入即预置全部 Fetcher 类、请求快捷函数、自动页面追踪和 curl 命令转换工具,让“写脚本—运行—改选择器”的循环变成即输即得的探索式体验。本文基于文档 docs/cli/interactive-shell.md 展开,并结合 scrapling/core/shell.py、scrapling/core/_shell_signatures.py 等源码,讲清每个快捷命令背后的实现机制与可复制的实操流程。读完本文,你能够独立安装并启动 Shell、熟练使用page/pages页面管理、用uncurl/curl2fetcher把浏览器 DevTools 中的请求一键转为 Fetcher 请求,并理解其底层解析链路。
为什么使用交互式 Shell
文档把 Shell 定位成把抓取从“慢速脚本循环”变成“快速探索”的工具,官方列出的典型场景包括:
- 快速原型(Rapid prototyping):即时验证抓取策略;
- 数据探索(Data exploration):交互式地导航网站并抽取数据;
- 学习 Scrapling:在实时环境中试验各种特性;
- 调试爬虫:逐步检查请求并查看结果;
- 工作流转换(Converting workflows):把浏览器 DevTools 里的 curl 命令一行转换为 Fetcher 请求。
这些能力的共同基础是:Shell 把 Scrapling 最常用的一等对象(Fetcher、Selector、Response)和请求函数全部注入命名空间,用户不需要任何import语句。
前置知识
在开始之前,文档建议先阅读以下页面(链接均以仓库根目录为起点):
- Fetchers 基础,理解 Response 对象 以及如何选择 Fetcher;
- 元素查询,理解如何从 Selector/Response 对象中查找/提取元素;
- 主类,理解 Response 从 Selector 继承的属性与方法;
- 至少一页抓取器文档,用于实际发请求:HTTP 请求、动态网站 或 强保护动态网站。
安装与启动
安装依赖
Shell 属于 CLI 能力之一(参见 CLI 总览),需要先安装shell依赖组,再安装各 Fetcher 的浏览器等运行依赖:
pip install "scrapling[shell]" scrapling install从 pyproject.toml 可以看到shell额外依赖的具体内容:IPython>=8.37(源码注释说明这是最后一个支持 Python 3.10 的版本线)、markdownify>=1.2.0,以及传递依赖scrapling[fetchers]。scrapling install会下载 Chromium 浏览器、系统依赖与指纹处理相关依赖,详见 cli.py 中的 install 命令实现。
启动命令
# 启动交互式 Shell scrapling shell # 执行一段代码后退出(适合脚本化场景) scrapling shell -c "get('https://quotes.toscrape.com'); print(len(page.css('.quote')))" # 设置日志级别 scrapling shell --loglevel info这三个入口对应 cli.py 中的 Click 命令定义:
-c/--code:在 Shell 中执行给定代码后退出。源码中通过InteractiveShellEmbed.run_cell(self.code, store_history=False)实现,执行异常会被捕获并记录日志而不是让进程崩溃;-L/--loglevel:取值为debug、info、warning、error、critical、fatal之一(case_sensitive=False),默认值为debug。源码 shell.py 用_known_logging_levels映射到标准 logging 级别,未知级别会回落到DEBUG并打一条 warning。
启动后终端会显示 Scrapling 的自定义 Banner。从 CustomShell.banner() 可以看到 Banner 分三部分:可用的 Scrapling 对象(Fetcher/AsyncFetcher/FetcherSession、DynamicFetcher/DynamicSession/AsyncDynamicSession、StealthyFetcher/StealthySession/AsyncStealthySession、Selector)、六个请求快捷函数、以及page/response/pages/uncurl/curl2fetcher/view/help这些实用命令。退出方式为exit或 Ctrl+D。
进入 Shell 后即可直接抓取,无需任何导入:
# 无需 import,一切就绪 get('https://news.ycombinator.com') # 探索页面结构 page.css('a')[:5] # 查看前 5 个链接 # 精炼选择器 stories = page.css('.titleline>a') len(stories) # 30 # 提取具体数据 for story in stories[:3]: ... title = story.text ... url = story['href'] ... print(f"{title}: {url}") # 尝试不同的写法 titles = page.css('.titleline>a::text') # 直接提取文本 urls = page.css('.titleline>a::attr(href)') # 直接提取属性内置快捷函数与预置对象
六个请求快捷函数
Shell 提供了消除样板代码的快捷函数(对应关系见 get_namespace 与 banner):
| 快捷函数 | 等价于 | 说明 |
|---|---|---|
get(url, **kwargs) | Fetcher.get | HTTP GET 请求 |
post(url, **kwargs) | Fetcher.post | HTTP POST 请求 |
put(url, **kwargs) | Fetcher.put | HTTP PUT 请求 |
delete(url, **kwargs) | Fetcher.delete | HTTP DELETE 请求 |
fetch(url, **kwargs) | DynamicFetcher.fetch | 基于浏览器的动态页面抓取 |
stealthy_fetch(url, **kwargs) | StealthyFetcher.fetch | 隐身浏览器抓取(对抗强防护站点) |
常用类也被自动注入命名空间,包括Fetcher、AsyncFetcher、FetcherSession、DynamicFetcher、DynamicSession、AsyncDynamicSession、StealthyFetcher、StealthySession、AsyncStealthySession和Selector,全部来自 scrapling.fetchers 的导出,无需 import 即可使用。
快捷函数的参数提示:**kwargs的签名展开
一个容易忽略的细节是:get等函数的签名中大量参数走**kwargs(Unpack[TypedDict]注解),在普通 IPython 里 Tab 补全只能看到**kwargs,无法提示具体参数名。Shell 专门解决了这一点:
- scrapling/core/_shell_signatures.py 在模块级维护了三组参数字典:
_REQUESTS_PARAMS(params、cookies、auth、impersonate、http3、stealthy_headers、proxies、proxy、proxy_auth、timeout、headers、retries、retry_delay、follow_redirects、max_redirects、verify、cert、selector_config)、_FETCH_PARAMS(headless、disable_resources、network_idle、wait_selector、page_action、proxy、extra_headers、timeout、cdp_url、block_ads、retries、capture_xhr、dns_over_https等浏览器参数)、_STEALTHY_FETCH_PARAMS(在_FETCH_PARAMS基础上增加allow_webgl、hide_canvas、block_webrtc、solve_cloudflare等隐身参数),并以Signatures_map把函数名get/post/put/delete/fetch/stealthy_fetch映射到对应参数字典,其中post/put额外带有data与json参数; - scrapling/core/shell.py 的 _unpack_signature 在
CustomShell.create_wrapper中被调用,把**kwargs(Parameter.VAR_KEYWORD)替换为一个个KEYWORD_ONLY参数并写回包装函数的__signature__,于是 IPython 的补全和get?帮助就能像 IDE 一样展示impersonate、proxy、timeout等具体参数及其类型注解。
这就是文档中page.c<TAB>、Fetcher.<TAB>等补全体验完整的底层原因。
智能页面管理:page、response与pages
Shell 会自动追踪你的请求与页面,这是它区别于普通 Python REPL 的核心体验:
当前页面访问:page和response两个名字会自动更新为最近一次抓取的页面:
get('https://quotes.toscrape.com') # 'page' 和 'response' 都指向最后一次抓取的页面 page.url # 'https://quotes.toscrape.com' response.status # 打印 200;与 page.status 等价页面历史:pages是一个Selectors对象,保留最近5 个页面:
get('https://site1.com') get('https://site2.com') get('https://site3.com') # 访问最近 5 个页面 len(pages) # 保存页面历史的 Selectors 对象 -> 3 pages[0].url # 历史中的第一个页面 -> 'https://site1.com' pages[-1].url # 最新的页面 -> 'https://site3.com' # 处理历史页面 for i, old_page in enumerate(pages): ... print(f"Page {i}: {old_page.url} - {old_page.status}")源码侧的实现非常清晰:所有快捷函数都是CustomShell.create_wrapper生成的包装函数,包装函数在执行完真实请求后统一调用 update_page:
- 若返回结果是
Response或Selector实例,则self.page = result,并向self.pages追加;当len(self.pages) > 5时pop(0)丢弃最旧一项,这就是“最近 5 页”上限的来源; - 随后把
page、response、pages三个名字同步写回self.shell.user_ns(IPython 用户命名空间),保证你在 REPL 里看到的始终是最新值; - 若结果不是页面(例如
uncurl返回的Request对象),则原样返回且不更新页面状态。
Selectors本体定义在 scrapling/parser.py,它是一个List[Selector]的子类,因此支持len()、下标、切片和迭代。
附加实用命令
页面可视化:view()
在浏览器中直接查看抓下来的页面:
get('https://quotes.toscrape.com') view(page) # 在默认浏览器中打开该页面的 HTML对应实现 show_page_in_browser:它先校验输入必须是Selector实例,否则记录错误日志;然后写入一个scrapling_view_前缀的临时 HTML 文件(编码取自page.encoding),最后通过webbrowser.open(f"file://{fname}")调用系统默认浏览器打开。适合在调整 CSS 选择器时对照真实页面结构。
curl 命令集成:uncurl与curl2fetcher
Shell 提供了把浏览器 DevTools 中的 curl 命令转换为Fetcher请求的两个函数:uncurl(只转换)和curl2fetcher(转换并直接执行)。使用流程:在 Chrome DevTools 的 Network 面板中选择请求,右键 “Copy as cURL”,粘贴进 Shell。
第一步:把 curl 命令转换为 Request 对象
curl_cmd = '''curl 'https://scrapling.requestcatcher.com/post' \ ... -X POST \ ... -H 'Content-Type: application/json' \ ... -d '{"name": "test", "value": 123}' ''' request = uncurl(curl_cmd) request.method # -> 'post' request.url # -> 'https://scrapling.requestcatcher.com/post' request.headers # -> {'Content-Type': 'application/json'}第二步:一步转换并执行
# 转换 + 执行一步到位 curl2fetcher(curl_cmd) page.status # -> 200 page.json()['json'] # -> {'name': 'test', 'value': 123}底层实现:CurlParser 的解析细节
这两个函数背后是 scrapling/core/shell.py 的 CurlParser。它的设计目标是“优先处理从 DevTools 网络面板复制出来的 curl 命令”,要点如下:
- 基于 argparse 而非正则:
CurlParser.__init__构造一个禁用了 help 的NoExitArgumentParser(shell.py 中让解析错误抛出ValueError而不是直接sys.exit,保证 REPL 不会因一条坏命令而退出),注册了 DevTools 常见参数:url、-X/--request、-H/--header(可重复)、-A/--user-agent、-d/--data、--data-raw(浏览器 JSON body 常用)、--data-binary、--data-urlencode(可重复)、-G/--get、-b/--cookie、-x/--proxy、-U/--proxy-user、-k/--insecure、--compressed、-i/-s/-v等; - 解析主流程 parse():先剥离
curl前缀并把\\\n续行替换为空格,用shlex.split按 shell 语法切分 token,再用parse_known_args解析——出现未知参数会抛出AttributeError(测试用例test_invalid_curl_commands验证了这一点); - 方法推断规则:默认
get;-G强制 GET;否则取-X的值并转小写;若都没有但存在任意 data 参数(-d/--data-raw/--data-binary/--data-urlencode)则推断为post; - Header 与 Cookie:
-H列表交给 _ParseHeaders 拆分,其中键名为cookie的 header 会被 _CookieParser(基于http.cookies.SimpleCookie)解析为字典;-b的 cookie 字符串解析后按同名覆盖 header 中已有的 cookie; - 请求体优先级:
--data-binary(转为 bytes)>--data-raw(剥离行首$前缀)>-d>--data-urlencode(合并为&串再解析为字典);若最终 data 是字符串且能被 orjson 解析成 dict/list,则升级为json_data(即json=参数)并把data置空;-G场景下 data 会被移入 URLparams; - 代理:
-x缺省补http://前缀,-U user:pass会拼入代理 URL 的 netloc,最终生成{"http": proxy_url, "https": proxy_url}的标准字典格式; - 返回值:
uncurl返回一个 8 字段的Requestnamed tuple(method/url/params/data/json_data/headers/cookies/proxy/follow_redirects,定义见 shell.py),follow_redirects固定为"safe"——跟随重定向但拒绝指向内网/私有 IP 的重定向; - 执行链路 convert2fetcher:把
Request._asdict()展开,仅支持get/post/put/delete四种方法(_supported_methods);json_data键被重命名为json以匹配Fetcher的参数名;GET/DELETE 会丢弃data/json;最后getattr(Fetcher, method)(**request_args)发起真实请求,返回值经update_page写入page/pages,因此curl2fetcher之后可以直接page.status、page.json()继续操作。
这套解析逻辑有完整的测试覆盖,见 tests/cli/test_shell_functionality.py 的TestCurlParser(基础 GET、headers、表单/JSON data、-H Cookie与-b合并、-x/-U代理、convert2fetcher调用验证、非法命令抛错),以及 tests/core/test_shell_core.py 中对_CookieParser、_ParseHeaders、Request与日志级别映射的单元测试。
IPython 全部能力
Shell 继承自 IPython(InteractiveShellEmbed嵌入模式,见 start()),因此所有 IPython 特性都可用:
# 魔术命令 %time page = get('https://example.com') # 计时 %history # 查看命令历史 %save filename.py 1-10 # 把第 1-10 条命令保存为文件 # 任意位置 Tab 补全 page.c<TAB> # 显示 css、cookies、headers 等 Fetcher.<TAB> # 显示 Fetcher 全部方法 # 对象检查 get? # 查看 get 的文档实战示例
以下是文档提供的两个由 AI 辅助生成的示例场景,展示从探索到放大的完整工作流。
电商数据采集
# 从商品列表页开始 catalog = get('https://shop.example.com/products') # 找到商品链接 product_links = catalog.css('.product-link::attr(href)') print(f"Found {len(product_links)} products") # 先抽样几个商品验证选择器 for link in product_links[:3]: ... product = get(f"https://shop.example.com{link}") ... name = product.css('.product-name::text').get('') ... price = product.css('.price::text').get('') ... print(f"{name}: {price}") # 验证无误后,用 Session 提升批量抓取效率 from scrapling.fetchers import FetcherSession with FetcherSession() as session: ... products = [] ... for link in product_links: ... product = session.get(f"https://shop.example.com{link}") ... products.append({ ... 'name': product.css('.product-name::text').get(''), ... 'price': product.css('.price::text').get(''), ... 'url': link ... })这个示例体现了 Shell 的典型用法:先用get单发请求快速验证选择器,确认无误后再切换到FetcherSession(命名空间中已预置,甚至不需要 import)做规模化抓取。
API 集成与测试
>>> # 交互式测试 API 端点 >>> response = get('https://jsonplaceholder.typicode.com/posts/1') >>> response.json() {'userId': 1, 'id': 1, 'title': 'sunt aut...', 'body': 'quia et...'} >>> # 测试 POST 请求 >>> new_post = post('https://jsonplaceholder.typicode.com/posts', ... json={'title': 'Test Post', 'body': 'Test content', 'userId': 1}) >>> new_post.json()['id'] 101 >>> # 测试更新请求 >>> updated = put(f'https://jsonplaceholder.typicode.com/posts/{new_post.json()["id"]}', ... json={'title': 'Updated Title'})post/put的json=参数与Fetcher.post/Fetcher.put完全一致(参见 Signatures_map 中post/put额外包含的data、json参数),因此交互中验证通过的请求可以原样搬进生产代码。
源码索引与延伸阅读
Shell 的实现集中在以下几个文件,便于按需深入:
- scrapling/cli.py:
scrapling shell的 Click 命令定义(-c、-L/--loglevel); - scrapling/core/shell.py:
CustomShell(命名空间、Banner、页面更新)、CurlParser(curl 解析与uncurl/curl2fetcher)、show_page_in_browser(view)、Convertor(供scrapling extract命令做 HTML→Markdown/文本转换,属于 CLI 总览 中的另一条能力线); - scrapling/core/_shell_signatures.py:六个快捷函数的参数签名表,支撑 IPython 的参数级补全;
- scrapling/core/utils/_shell.py:Header/Cookie 字符串解析工具;
- 测试:tests/cli/test_shell_functionality.py(
CurlParser、CustomShell、Convertor)、tests/core/test_shell_core.py(cookie/header 解析、Request、日志级别)。
与 Shell 相关的其他 CLI 文档可参考 CLI 总览 和 Extract 命令;抓取器选型见 choosing.md。Shell 的适用前提再次强调:需要安装scrapling[shell]依赖组并执行scrapling install完成浏览器依赖安装;-c模式适合把 Shell 纳入脚本流程,--loglevel默认debug,生产调试时可调整为info及以上以降噪。
【免费下载链接】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),仅供参考