ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Scrapling Spider 快速上手指南:从第一个爬虫到数据导出与抓取控制

Scrapling Spider 快速上手指南:从第一个爬虫到数据导出与抓取控制 Scrapling Spider 快速上手指南从第一个爬虫到数据导出与抓取控制【免费下载链接】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 仓库中的 Spider 入门文档编写带你从零搭建一个可运行的爬虫定义name、start_urls与parse()三大要素用start()一键运行并获取详细的CrawlResult统计再掌握response.follow()跨页跟随、ItemList多格式数据导出、allowed_domains域过滤与robots_txt_obey合规抓取。读完你应能独立编写、运行并控制一个多页爬虫同时理解 Scrapling 引擎在每个环节背后的真实实现。你的第一个 SpiderSpider 是一个类用于定义如何从网站抓取与提取数据。最简单的 Spider 如下from scrapling.spiders import Spider, Response class QuotesSpider(Spider): name quotes start_urls [https://quotes.toscrape.com] async def parse(self, response: Response): for quote in response.css(div.quote): yield { text: quote.css(span.text::text).get(), author: quote.css(small.author::text).get(), }每个 Spider 需要三样东西nameSpider 的唯一标识符。start_urls开始爬取的 URL 列表。parse()一个异步生成器方法处理每个响应并 yield 结果。parse()方法处理每个响应。你使用的是与 Scrapling 的 Selector/Response 对象 完全相同的选取方法然后通过yield字典来输出抓取到的条目。源码视角Spider 基类到底提供了什么从 Spider 基类 的定义可以看出parse()是抽象方法且类型签名明确要求它是异步生成器AsyncGenerator这与所有回调都必须是async defyield的要求一致。基类还内置了一批类级默认配置写 Spider 时可以直接覆盖配置项默认值作用concurrent_requests4全局并发请求数concurrent_requests_per_domain0单域并发限制0 表示仅用全局限制download_delay0.0请求间延迟秒robots_txt_obeyFalse是否遵守 robots.txtautothrottle_enabledFalse是否启用自动限速max_blocked_retries3被拦截请求的最大重试次数logging_levellogging.DEBUG日志级别两个初始化细节值得注意如果name为None__init__会直接抛出ValueErrorspider.py L112-L113所以忘记命名会立刻暴露问题。每个 Spider 实例都会配置一个名为scrapling.spiders.name的独立 logger日志格式中带上 Spider 名这就是运行期间一切都会打印到终端的来源spider.py L115-L136。在引擎侧CrawlerEngine._run_callbacks 会消费回调 yield 出来的对象遇到Request就经过域过滤后入队遇到dict就交给on_scraped_item钩子处理后计入条目——也就是说parse()里混着 yield 字典和新请求是被明确支持的两种结果类型。运行 Spiderstart() 与 CrawlResult要运行 Spider创建实例并调用start()result QuotesSpider().start()start()方法在内部处理了所有异步机制因此你无需操心事件循环。Spider 运行期间发生的一切都会记录到终端爬取结束时你会得到非常详细的统计信息。这些统计位于返回的CrawlResult对象中它提供了你需要的一切result QuotesSpider().start() # 访问抓取的条目 for item in result.items: print(item[text], -, item[author]) # 查看统计信息 print(fScraped {result.stats.items_scraped} items) print(fMade {result.stats.requests_count} requests) print(fTook {result.stats.elapsed_seconds:.1f} seconds) # 爬虫是正常结束还是被暂停了 print(fCompleted: {result.completed})源码视角start() 的内部机制从 start() 的实现 可以看到它通过anyio.run(self.__run, backendasyncio, ...)同步封装了整套异步爬取流程对外表现为一次阻塞调用还支持use_uvloopTrue参数以启用更快的 uvloop/winloop 事件循环若可用。它临时安装了 SIGINT 处理器按一次CtrlC发起优雅暂停等待活动任务完成再按一次强制停止若配置了crawldir优雅关闭时还会保存 checkpoint 以便后续恢复。__run 中创建CrawlerEngine、执行engine.crawl()得到统计再把engine.items与paused标志打包成CrawlResult返回。CrawlResult 本身很轻statsCrawlStats实例、itemsItemList、paused布尔值其中completed属性即not paused。它同时实现了__len__与__iter__可以直接len(result)或对结果迭代条目。而终端打印的那些统计全部来自 CrawlStats 数据类除文档示例用到的items_scraped、requests_count、elapsed_seconds外还可直接访问failed_requests_count失败请求、offsite_requests_count被域过滤丢弃的请求、robots_disallowed_count被 robots.txt 拦截的请求、cache_hits/cache_misses缓存命中情况、response_bytes响应总字节、requests_per_second吞吐量派生属性、response_status_count按 HTTP 状态码的计数等。stats.to_dict()会把这些汇总成可序列化字典elapsed_seconds与requests_per_second均由start_time/end_time派生result.py L149-L157。跟随链接response.follow()大多数爬取需要跨多页跟随链接。使用response.follow()创建后续请求from scrapling.spiders import Spider, Response class QuotesSpider(Spider): name quotes start_urls [https://quotes.toscrape.com] async def parse(self, response: Response): # 从当前页提取条目 for quote in response.css(div.quote): yield { text: quote.css(span.text::text).get(), author: quote.css(small.author::text).get(), } # 跟随 下一页 链接 next_page response.css(li.next a::attr(href)).get() if next_page: yield response.follow(next_page, callbackself.parse)response.follow()会自动处理相对 URL将其与当前页面 URL 拼接同时默认把当前页面设置为Referer请求头。你也可以把后续请求指向不同的回调方法以区分不同类型的页面async def parse(self, response: Response): for link in response.css(a.product-link::attr(href)).getall(): yield response.follow(link, callbackself.parse_product) async def parse_product(self, response: Response): yield { name: response.css(h1::text).get(), price: response.css(.price::text).get(), }注意所有回调方法都必须是异步生成器使用async def和yield。源码视角follow() 的完整参数Response.follow 的实现 签名比文档示例展示的更丰富除url和callback外还提供参数说明sid指定用哪个会话发起该请求留空则沿用上一请求的会话priority优先级数值越大越先被处理dont_filter该请求若此前执行过禁用去重过滤器允许再次执行meta附加到请求上的元数据字典referer_flow默认True将当前响应 URL 作为新请求的 referer**kwargs透传给会话的额外请求参数如headers、data两个实现细节参数继承follow()会把上一请求的会话参数与新传入的参数合并新值优先custom.py L120-L121所以连续yield response.follow(...)时 headers、代理等设置会自动流转。前置条件follow()要求response.request已由引擎设置否则抛出TypeErrorcustom.py L117-L118——这意味着follow()只适用于引擎回调上下文中的响应不能对裸构造的Response使用。生成的 Request 对象 内部通过update_fingerprint()计算 SHA1 指纹涵盖会话 ID、方法、规范化 URL 与请求体用于去重相同请求不会重复入队priority则通过__lt__/__gt__的比较实现参与调度排序request.py L71-L143。导出数据ItemList 的内置导出方法result.items返回的ItemList带有内置导出方法result QuotesSpider().start() # 导出为 JSON result.items.to_json(quotes.json) # 导出为带缩进的 JSON result.items.to_json(quotes.json, indentTrue) # 导出为 JSON Lines每行一个 JSON 对象 result.items.to_jsonl(quotes.jsonl) # 导出为 CSV 或 XML result.items.to_csv(quotes.csv) result.items.to_xml(quotes.xml)以上方法都会在父目录不存在时自动创建源码中每个方法都先执行Path(path).parent.mkdir(parentsTrue, exist_okTrue)。to_csv()会为所有条目中出现过的键各写一列因此即使条目键不完全一致也能导出缺失单元格留空。可以传fields[...]自行挑选列及其顺序或delimiter\t生成 TSV 文件。to_xml()把每个条目包在item元素内整体再包在items根元素内两者可通过root_tag和item_tag改名。两种格式下非简单标量值嵌套字典或列表都会被写成 JSON确保没有任何数据被静默丢弃。源码视角导出的容错处理从 ItemList 的实现 可以确认上述行为并补充几点序列化统一使用orjson带OPT_SERIALIZE_NUMPY选项to_json(indentTrue)使用 2 空格缩进源码注释标明会稍慢一些。CSV 列的默认顺序是键在条目中出现的先后顺序用字典推导保序去重result.py L77to_csv内部使用csv.DictWriter且extrasactionignore。XML 导出比文档描述更健壮条目键若不是合法的 XML 标签名会被改写为合法形式并把原始键名保留在name属性中文本中的非法 XML 控制字符会被剔除result.py L17-L19, L89-L118。非标量值序列化为 JSON 的逻辑集中在_stringify()result.py L22-L28CSV 与 XML 共用。每次导出都会以 INFO 级别记录Saved N items to日志。过滤域名allowed_domains使用allowed_domains将 Spider 限制在特定域名内防止它意外跟随到外部网站的链接class MySpider(Spider): name my_spider start_urls [https://example.com] allowed_domains {example.com} async def parse(self, response: Response): for link in response.css(a::attr(href)).getall(): # 指向其他域名的链接会被静默丢弃 yield response.follow(link, callbackself.parse)子域名会被自动匹配因此设置allowed_domains {example.com}同样允许sub.example.com、blog.example.com等。被过滤掉的请求会计入stats.offsite_requests_count方便你看到有多少请求被丢弃。源码视角域匹配与计数发生在哪这两个行为都能在 CrawlerEngine 中逐行对应_is_domain_allowed()的判断逻辑是domain allowed or domain.endswith(. allowed)——这就是子域名自动匹配的实现若allowed_domains为空集则全部放行。在 _run_callbacks 中回调 yield 出的Request若未通过域检查则self.stats.offsite_requests_count 1并打印一条 DEBUG 日志Filtered offsite request to: ...请求不进入调度器——即静默丢弃且可计数。robots.txt 合规robots_txt_obey设置robots_txt_obey True让 Spider 在抓取任何域名前先遵守 robots.txt 规则class PoliteSpider(Spider): name polite start_urls [https://example.com] robots_txt_obey True async def parse(self, response: Response): for link in response.css(a::attr(href)).getall(): yield response.follow(link, callbackself.parse)启用后Spider 会预取 robots.txt爬取开始前并发抓取start_urls中所有域名的 robots.txt。检查每个请求对照该域名 robots.txt 的Disallow规则检查。被禁止的请求被静默丢弃并计入stats.robots_disallowed_count。遵守Crawl-delay与Request-rate指令取指令值与你配置的download_delay的较大者。这意味着 robots.txt 的延迟永远不会降低你配置的延迟只会在需要时增大它。robots.txt 使用 Spider 的默认会话抓取并在整个爬取期间按域缓存。爬取中途发现的域名不在start_urls中会在首次请求该域名时抓取其 robots.txt。注意robots_txt_obey默认关闭。它不影响你的并发设置——只调整请求之间的延迟。如果不想手工设定download_delay可以设置autothrottle_enabled TrueSpider 会根据各域名的响应速度自行调节延迟被拦截时自动退避。参见 AutoThrottle 进阶文档。源码视角RobotsTxtManager 与延迟解析上述三步流程对应两处源码RobotsTxtManager 负责 robots.txt 的抓取、解析与缓存prefetch()用 anyio 的create_task_group并发预热start_urls涉及的各域can_fetch()以通配 user-agent*判定 URL 是否允许抓取基于 protego 库解析解析器按domain缓存在self._cache中整个爬取期间只取一次。抓取或解析失败只记录 WARNING 并回退到空规则不会中断爬取。延迟取最大值的逻辑在 CrawlerEngine._get_domain_delay它同时读取Crawl-delay与Request-rate两类指令其中Request-rate会被换算为周期 / 请求数再与download_delay取最大值结果按域名缓存在_domain_delays中。源码注释明确说明对于预取过的域名这是本地解析器读取而爬取中途发现的域名会在此处按需抓取——与文档描述一致。robots_txt_obey的默认值False定义在 Spider 类属性 中只有开启它引擎才会初始化 robots 管理器与按域延迟缓存engine.py L80-L81。小结与延伸阅读到这里你已经覆盖了入门文档的全部主线定义三要素 Spider →start()运行并读取CrawlResult→response.follow()跨页跟随 →ItemList四种格式导出 →allowed_domains域过滤 →robots_txt_obey合规抓取。所有行为均与 scrapling/spiders 目录下的源码实现一一对应相关测试用例如 tests/spiders/test_spider.py、tests/spiders/test_robotstxt.py、tests/spiders/test_result.py可用于进一步验证。继续深入可阅读仓库文档Spider 进阶AutoThrottle、开发模式等Spider 架构详解会话管理选择器与主要解析类抓取器选择指南与 Response 对象Scrapy 集成说明【免费下载链接】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),仅供参考
返回列表