ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Scrapling 平台爬虫模板详解:ShopifySpider 如何免写 HTML 解析抓取整店商品

Scrapling 平台爬虫模板详解:ShopifySpider 如何免写 HTML 解析抓取整店商品 Scrapling 平台爬虫模板详解ShopifySpider 如何免写 HTML 解析抓取整店商品【免费下载链接】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 的平台型爬虫模板Platform Spider Templates展开它面向 Shopify 这类统一数据结构、跨大量独立站点的平台只需用ShopifySpider指定一个店铺域名即可通过平台的 JSON API 抓取全部商品与变体数据。读完本文你将掌握平台模板与通用模板的本质区别、ShopifySpider的分页抓取流程、全部 item 字段的来源与取值规则、target_website的域名解析逻辑以及如何通过覆写_process_product()定制输出结构并能结合仓库源码验证每一个行为细节。平台模板 vs 通用模板按平台而非按模式复用Scrapling 内置的爬虫模板分为两类理解两者的定位是理解本文的前提通用模板CrawlSpider、SitemapSpider、XMLFeedSpider、CSVFeedSpider覆盖的是爬取的模式跟踪匹配某模式的链接、遍历站点 sitemap、迭代 XML/CSV 数据源。它们需要你针对具体站点的 HTML 结构自己写解析逻辑。平台模板覆盖的是平台网站构建器site builder会在它托管的众多独立网站上暴露出相同的机器可读结构所以爬虫天生知道数据在哪里——你只需把爬虫指向某个具体域名。从源码结构看这一划分直接体现在模板包的组织方式上scrapling/spiders/templates/init.py 将通用模板CrawlSpider、SitemapSpider、XMLFeedSpider、CSVFeedSpider与平台模板ShopifySpider统一导出而 scrapling/spiders/init.py 再将其提升到scrapling.spiders顶层因此可以直接from scrapling.spiders import ShopifySpider。当前仓库中唯一的平台模板就是ShopifySpider它是本文的绝对主角。ShopifySpider最小可用示例ShopifySpider通过 Shopify 店铺的 JSON API 提取任意 Shopify 驱动商店的全部商品全程不接触网站的 HTML。最小用法如下from scrapling.spiders import ShopifySpider class MyStore(ShopifySpider): target_website example.com result MyStore().start() print(result.items[0])将target_website设置为商店域名即可爬虫会自行完成 collections 与 products 两层的分页遍历result.items中是逐变体展开的商品条目。Spider基类的其余能力全部继承可用并发配置、下载延迟、robots.txt 遵循、检查点checkpoint以及生命周期钩子——这套异步调度、并发控制与断点续爬的完整机制可参见 Spider 架构文档。目标域名解析三级回退与自动归一化target_website并非唯一指定目标的方式。从 shopify.py 的__init__可以看到域名的确定遵循明确的三级回退顺序优先使用target_website为空时回退到start_urls的第一个条目仍为空时回退到allowed_domains的第一个条目三者全部为空则抛出ValueError错误信息明确要求设置其中任意一项。无论来源是裸域名example.com还是完整 URLhttps://example.com/collections/all最终都会被归一化为纯域名netloc没有://的字符串会先补上https://前缀再交给urlparse取netloc。这套行为在 tests/spiders/test_shopify.py 的TestDomainResolution中有逐项验证从target_website取域名、从完整 URL 归一化出域名、从start_urls回退含www.子域保留、从allowed_domains回退以及三源皆空时抛出ValueError五个用例与源码实现一一对应。抓取流程collections.json → products.json → 变体级条目ShopifySpider的抓取逻辑由三个类属性 URL 模板驱动shopify.py#L33-L37name shopify target_website collections_url https://{website}/collections.json?page{page}limit250 products_url https://{website}/collections/{handle}/products.json?page{page}limit250 product_url https://{website}/collections/{handle}/products/{product_handle}其中limit250是 Shopify 平台的单页上限。完整流程分三步第一步遍历 collections.json 分页start_requests()只产出第一个请求https://store/collections.json?page1limit250并携带meta{page: 1}。parse()处理该响应时做两件事shopify.py#L54-L70对当前页中每一个products_count非零的 collection派发一个指向/collections/handle/products.json?page1的请求meta中记录handle与page只要当前页的collections列表非空就继续派发下一页page 1的 collections.json 请求。空页即终止不再产生后续请求。products_count在这里只被当作非零就抓这个 collection的信号从不作为期望总数使用——原因见下文注意事项与限制。第二步遍历每个 collection 的 products.json 分页parse_collection()shopify.py#L96-L112对每个 collection 的响应执行对products列表中的每个产品调用_process_product()逐变体产出条目只要当前页products非空就派发该 collection 的下一页产品请求空页表示该 collection 已抓完记录一条 debug 日志Extracted all products from collection 并停止。测试用例test_parse_dispatches_collections_and_next_page、test_parse_stops_on_empty_page、test_parse_collection_stops_on_empty_pagetest_shopify.py精确覆盖了这套分页边界2 个 collection含一个空 collection 被跳过时派发 2 个请求、空 collections 页返回 0 个请求、空 products 页返回 0 个请求。第三步按变体产出条目并跨 collection 去重去重状态存放在实例属性self.collected_ids一个set在__init__中初始化。每个变体以variant[id]作为键已见过的变体 id 直接跳过。由于同一个产品变体可能出现在多个 collection 中这一机制保证每个变体只产出一次条目。测试用例test_variants_deduplicated_across_collections验证了同一产品在lipsticks与bestsellers两个 collection 中只产出一次test_dedup_state_is_per_instance则确认去重状态是实例级的——不同 Spider 实例之间互不干扰。条目字段详解每个字段的来源与取值规则ShopifySpider默认每个变体产出一个 dict 条目字段结构与底层数据来源如下逐项对应 _process_product() 的实现字段来源与规则name产品标题当变体标题不是Default Title时追加 - 变体标题price变体价格字符串保持 Shopify 返回的原样如9.00category所属 collection 的 handle做title-case化summer-sale变成Summer Salebrand产品的vendor字段identifier变体 idvariant[id]sku变体 SKU店铺未设置时为None也被归一为空串stock变体有货为None缺货为0image_url产品第一张图的src无图为url产品在所属 collection 内的商品页 URLproduct_url模板拼出description产品body_html经remove_tags来自w3lib.html剥离 HTML 标签后的纯文本old_pricecompare_at_price但仅当它是真实预售价非零时才保留否则为barcode变体barcode无则为大多数店铺不在这两个端点暴露该字段测试数据test_shopify.py#L19-L59 的PRODUCTS_PAGE恰好覆盖了所有边界分支TestItemProcessing的断言可以直接当作字段规则 → 期望输出的验收清单例如变体标题为Red非默认→name为Matte Lipstick - Red标题为Default Title→name保持产品原标题sku: None→ 归一为available: False→stock为0compare_at_price: 0.00→old_price为12.00→ 原样保留body_html: None→description为images: []→image_url为。自定义输出结构覆写_process_product()上述字段不是强制契约。如果你想改变条目结构、或从产品数据中提取其他字段只需在子类中覆写_process_product()——它的签名是_process_product(self, product: Dict, collection_handle: str) - Generator[Dict, None, None]接收单个产品 dict 与所属 collection 的 handle以生成器形式逐条yield结果。覆写后parse_collection()的分页、去重之外的调用链保持不变注意跨 collection 的变体去重发生在_process_product()内部如果你完全重写该方法需要自行决定是否保留self.collected_ids去重逻辑。注意事项与限制使用ShopifySpider前必须了解以下边界来自 platform-templates.md 与源码行为JSON 端点的可见性限制/collections.json与/products.json只暴露已发布到 online-store 渠道的商品因此一个 collection 报告的products_count可能大于实际能抓到的数量。源码中shopify.py#L58if collection[products_count]:的判断印证了这一点——该计数只被用作是否抓取的开关而不是断点校验或完整性预期。受保护店铺大概率不可用位于额外防护或密码保护Shopify 店铺密码页后面的商店该模板很可能无法工作即使勉强可用也需要你进行大量覆写。Spider 基类能力照常生效robots_txt_obey、concurrent_requests、下载延迟、crawldir检查点暂停/恢复与生命周期钩子等 Spider 系统 提供的一切机制对平台模板同样适用。什么样的平台有资格成为平台模板仓库文档给出了明确的准入标准平台模板只接受在大量独立网站上暴露统一、机器可读结构的平台Shopify 的 collections/products JSON 端点即典型例子。反过来针对某一个特定网站的爬虫不属于库的收录范围——无论该网站有多受欢迎。从源码结构看这一约束也反映在实现方式上ShopifySpider的全部逻辑都建立在平台级 URL 模板collections_url/products_url/product_url类属性之上没有任何站点专属的 HTML 选择器或硬编码路径——这正是平台模板与单站爬虫的结构性差异。小结Scrapling 的平台模板把数据在哪里的知识封装进了库ShopifySpider用约 110 行源码scrapling/spiders/templates/shopify.py实现了三级域名回退、双层分页遍历、变体级去重和 12 个规范化字段并留出_process_product()作为唯一的定制点。对任意一家 Shopify 店铺你只需要定义一个两行的子类并调用start()而docs/spiders/generic-templates.md中的通用模板则继续负责链接跟踪、sitemap 与数据源迭代这些模式级的复用。两者叠加覆盖了从单页抓取到整站乃至整平台规模抓取的大部分场景。【免费下载链接】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),仅供参考
返回列表