前言先划清一个前提本文说的Spider类不是 Python 标准库的一部分它是第三方爬虫框架 Scrapy 里最基础的类。本机没有安装 Scrapy也没有 Python 解释器所以下面的代码是结构性示例用来讲清类的组织方式具体属性名、参数与调用细节一律以 Scrapy 官方文档为准。讲 Scrapy 的Spider最容易产生的误解是把它当成一个能自动爬遍全网的对象。它不是。Spider只是一个定义了从哪些地址开始、拿到响应后怎么解析的骨架真正发起请求、调度、去重、限速的是框架的引擎和各个 Downloader Middleware。你写的子类只负责回答两个问题请求哪些 URL以及从响应里提取什么。另外必须把合规写在前头爬虫只能对着允许爬取的内容用。本文只讲合规侧的做法——遵守robots.txt、限速、使用真实可辨识的 User-Agent、不绕过登录墙与付费墙。一、Spider 类的骨架在 Scrapy 里自定义爬虫就是继承Spider并实现约定的成员。最小骨架包含三样东西name必填、入口 URL、以及解析方法。# 示例基于 Scrapy 2.x第三方库未在本机安装API 以 Scrapy 官方文档为准import scrapyclass ExampleSpider(scrapy.Spider):name example # 必填且全局唯一allowed_domains [example.com] # 可选限定抓取范围start_urls [https://example.com/]def parse(self, response):# response 是 TextResponse封装了这次请求的返回内容title response.css(title::text).get()yield {title: title}name是框架用来在scrapy crawl example时找到这个爬虫的键必须唯一且不能与项目里其它爬虫重名。二、几个核心类属性属性是否必需作用name必需爬虫的唯一标识命令行用它启动start_urls常用起始 URL 列表默认入口allowed_domains可选限定域名越界链接会被过滤custom_settings可选为这个爬虫覆盖项目级配置start_requests()可覆写自定义起始请求的生成方式parse()通常必需默认的响应解析回调start_urls的默认行为是框架按它逐个生成请求把响应交给parse()。allowed_domains是范围控制不是安全边界——它只保证不会顺着链接跑到别的站点不等于对方允许你爬。三、start_requests() 与 parse()默认的起始请求逻辑可以用start_requests()覆写。在较新的 Scrapy 里这个方法仍是同步生成器如果你需要更细的控制比如带请求头、控制顺序就在这里写。# 示例基于 Scrapy 2.x第三方库未在本机安装API 以 Scrapy 官方文档为准import scrapyclass BlogSpider(scrapy.Spider):name blogallowed_domains [example.com]def start_requests(self):# 覆写入口自己构造请求而不是用 start_urlsfor page in range(1, 4):url fhttps://example.com/list?p{page}yield scrapy.Request(url, callbackself.parse_list)def parse_list(self, response):# 从列表页提取详情页链接交回框架继续跟进for href in response.css(a.detail::attr(href)).getall():yield response.follow(href, callbackself.parse_detail)def parse_detail(self, response):yield {title: response.css(h1::text).get(),url: response.url,}要点回调函数靠yield把结果交还框架——yield字典表示一条数据项yield请求表示再抓一页。不要在回调里自己开线程或直接写文件那会绕过框架的调度与限速。四、新版入口async def start()Scrapy 2.13 引入了async def start(self)作为起始请求的新写法它是一个异步生成器逐个产出初始请求。官方说明它的默认实现与读取start_urls的行为等价。# 示例基于 Scrapy 2.13第三方库未在本机安装API 以 Scrapy 官方文档为准from scrapy import Request, Spiderclass ModernSpider(Spider):name modernasync def start(self):yield Request(https://example.com/)写新项目时请先确认你用的 Scrapy 版本支持哪种入口写法——以 Scrapy 官方文档为准。旧版只有start_requests()新版两者都提供但推荐新写法。代码里不要同时重写两个入口否则行为取决于框架版本容易踩坑。五、合规写爬虫之前先想清楚技术骨架之外真正决定爬虫能不能长期跑下去的是这几条先读robots.txt目标站的robots.txt会声明哪些路径不允许抓。Scrapy 有对应的 robots 中间件默认遵循该协议若有人为了快关掉它那是违规的开始。限速在配置里设置下载延迟并发上限别把对方站点打挂。宁可慢一点、跑久一点。真实可辨识的 User-Agent用能表明身份与用途的 UA方便对方在出问题时联系你伪造浏览器 UA 去骗过校验不是合规做法。不绕登录墙 / 付费墙需要登录才能看的内容不在公开可抓范围内不能拿爬虫去绕。遵守站点条款与当地法律爬取的是公开数据也要看对方是否明示禁止。# 示例基于 Scrapy 2.x第三方库未在本机安装配置项以 Scrapy 官方文档为准# settings 片段放慢节奏、标明身份写在项目配置里不是写在 Spider 里DOWNLOAD_DELAY 1 # 每次请求之间的延迟秒CONCURRENT_REQUESTS 4 # 并发上限别开太大USER_AGENT MyResearchBot/1.0 (contact: adminexample.com)常见坑点坑 1name重复或缺失。❌ 两个爬虫都叫spider—— 命令行启动时报已存在同名爬虫。✅ 每个爬虫给唯一name并保持简短可读。坑 2在parse里直接return数据而不yield。❌def parse(self, response): return response.text—— 框架拿不到结构化数据项。✅ 用yield {field: value}逐个产出多个结果就多次yield。坑 3自己在回调里写文件或开线程。❌ 在parse里open(out.txt, a).write(...)或起线程并发抓取。✅ 让框架负责输出Feed Export和调度自己只产出数据项与请求。坑 4把allowed_domains当安全边界。❌ 以为限制了域名就等于对方允许我爬。✅ 它只是防跑偏的范围控制合规与否看robots.txt、条款与限速。坑 5为了速度关掉 robots 中间件、把并发拉满。❌ 这类优化常把目标站压慢甚至打挂属于违规且不道德。✅ 保留 robots 遵循设置合理延迟与并发。坑 6新老入口写法混用。❌ 同时重写start_requests()和async def start()—— 行为依赖框架版本。✅ 按所用 Scrapy 版本的官方文档二选一。坑 7把response.text与response.body搞混。❌ 想拿文本却用了bodybytes后面做字符串处理报类型错误。✅ 文本用response.text原始字节用response.body编码猜测以官方文档为准。总结要素说明Spider是什么Scrapy 第三方框架里的爬虫基类非标准库必需成员name起始地址start_urls或用start_requests()/async start()自定义解析入口parse()等回调用yield产出数据项与请求范围控制allowed_domains只防跑偏不等于授权合规底线遵守robots.txt、限速、真实 UA、不绕登录与付费墙版本差异async def start()自 Scrapy 2.13 起提供以官方文档为准一句话总结Spider类只负责请求哪些 URL、怎么解析响应这两件事调度与限速由框架承担把它用好一半靠写对name、start_urls、parse这套骨架另一半靠合规——先读robots.txt、放慢节奏、如实标注身份才能既拿到数据又不给目标站添麻烦。
阅读完成 · 觉得有帮助?