Scrapling 交互式 Shell 实战:基于 IPython 的 Web Scraping REPL,从 get 快捷函数到 curl 命令转换
2026/9/5 18:11:22 网站建设 项目流程

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语句。

前置知识

在开始之前,文档建议先阅读以下页面(链接均以仓库根目录为起点):

  1. Fetchers 基础,理解 Response 对象 以及如何选择 Fetcher;
  2. 元素查询,理解如何从 Selector/Response 对象中查找/提取元素;
  3. 主类,理解 Response 从 Selector 继承的属性与方法;
  4. 至少一页抓取器文档,用于实际发请求: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:取值为debuginfowarningerrorcriticalfatal之一(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.getHTTP GET 请求
post(url, **kwargs)Fetcher.postHTTP POST 请求
put(url, **kwargs)Fetcher.putHTTP PUT 请求
delete(url, **kwargs)Fetcher.deleteHTTP DELETE 请求
fetch(url, **kwargs)DynamicFetcher.fetch基于浏览器的动态页面抓取
stealthy_fetch(url, **kwargs)StealthyFetcher.fetch隐身浏览器抓取(对抗强防护站点)

常用类也被自动注入命名空间,包括FetcherAsyncFetcherFetcherSessionDynamicFetcherDynamicSessionAsyncDynamicSessionStealthyFetcherStealthySessionAsyncStealthySessionSelector,全部来自 scrapling.fetchers 的导出,无需 import 即可使用。

快捷函数的参数提示:**kwargs的签名展开

一个容易忽略的细节是:get等函数的签名中大量参数走**kwargsUnpack[TypedDict]注解),在普通 IPython 里 Tab 补全只能看到**kwargs,无法提示具体参数名。Shell 专门解决了这一点:

  • scrapling/core/_shell_signatures.py 在模块级维护了三组参数字典:_REQUESTS_PARAMSparamscookiesauthimpersonatehttp3stealthy_headersproxiesproxyproxy_authtimeoutheadersretriesretry_delayfollow_redirectsmax_redirectsverifycertselector_config)、_FETCH_PARAMSheadlessdisable_resourcesnetwork_idlewait_selectorpage_actionproxyextra_headerstimeoutcdp_urlblock_adsretriescapture_xhrdns_over_https等浏览器参数)、_STEALTHY_FETCH_PARAMS(在_FETCH_PARAMS基础上增加allow_webglhide_canvasblock_webrtcsolve_cloudflare等隐身参数),并以Signatures_map把函数名get/post/put/delete/fetch/stealthy_fetch映射到对应参数字典,其中post/put额外带有datajson参数;
  • scrapling/core/shell.py 的 _unpack_signature 在CustomShell.create_wrapper中被调用,把**kwargsParameter.VAR_KEYWORD)替换为一个个KEYWORD_ONLY参数并写回包装函数的__signature__,于是 IPython 的补全和get?帮助就能像 IDE 一样展示impersonateproxytimeout等具体参数及其类型注解。

这就是文档中page.c<TAB>Fetcher.<TAB>等补全体验完整的底层原因。

智能页面管理:pageresponsepages

Shell 会自动追踪你的请求与页面,这是它区别于普通 Python REPL 的核心体验:

当前页面访问pageresponse两个名字会自动更新为最近一次抓取的页面:

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:

  • 若返回结果是ResponseSelector实例,则self.page = result,并向self.pages追加;当len(self.pages) > 5pop(0)丢弃最旧一项,这就是“最近 5 页”上限的来源;
  • 随后把pageresponsepages三个名字同步写回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 命令集成:uncurlcurl2fetcher

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.statuspage.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_ParseHeadersRequest与日志级别映射的单元测试。

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/putjson=参数与Fetcher.post/Fetcher.put完全一致(参见 Signatures_map 中post/put额外包含的datajson参数),因此交互中验证通过的请求可以原样搬进生产代码。

源码索引与延伸阅读

Shell 的实现集中在以下几个文件,便于按需深入:

  • scrapling/cli.py:scrapling shell的 Click 命令定义(-c-L/--loglevel);
  • scrapling/core/shell.py:CustomShell(命名空间、Banner、页面更新)、CurlParser(curl 解析与uncurl/curl2fetcher)、show_page_in_browserview)、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(CurlParserCustomShellConvertor)、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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询