
本文介绍如何使用 scrapy 实现递归爬虫,自动定位网站中包含特定标题(如“az school safety program”)的全部页面 url,避免手动查找,同时兼顾效率与服务器友好性。
本文介绍如何使用 scrapy 实现递归爬虫,自动定位网站中包含特定标题(如“az school safety program”)的全部页面 url,避免手动查找,同时兼顾效率与服务器友好性。
在实际网页抓取任务中,常遇到同一内容模块(如宣传卡片、项目简介)跨多个页面重复出现的情况。例如目标站点 lawforkids.org 中,“AZ School Safety Program”这一标题的卡片分散在 /officers、/educators、/programs 等多个路径下。手动追踪既低效又易遗漏,而 Scrapy 的递归解析能力恰好可自动化完成该任务。
以下是完整、可运行的 Spider 实现(需置于 Scrapy 项目 spiders/ 目录下):
import scrapy
class PostsSpider(scrapy.Spider):
name = "card"
# 限制爬取深度,防止过度遍历与服务器压力
custom_settings = {
'DEPTH_LIMIT': 1,
'DEPTH_PRIORITY': 1,
'ROBOTSTXT_OBEY': True, # 尊重 robots.txt
'DOWNLOAD_DELAY': 1, # 延迟 1 秒,更友好
}
def start_requests(self):
# 明确起始 URL,避免默认 start_urls 机制干扰
yield scrapy.Request(url="https://lawforkids.org", callback=self.parse)
def parse(self, response):
# 跳过非 HTML 响应(如 PDF、图片、API 返回等)
if 'text/html' not in response.headers.get('Content-Type', b'').decode('utf-8', 'ignore'):
return
# 遍历当前页所有卡片容器(.card-body),精准提取标题并匹配
for card in response.css("div.card-body"):
title = card.css("h5.card-title::text").get(default="").strip()
if title == "AZ School Safety Program":
yield {
"Url": response.url,
"Title": title,
"Status": "matched"
}
# 递归发现并跟进站内链接
for a_tag in response.css('a[href]'):
link = a_tag.css('::attr(href)').get()
if not link:
continue
absolute_link = response.urljoin(link)
# 仅跟进同域链接(确保不爬出 lawforkids.org)
if absolute_link.startswith("https://lawforkids.org"):
yield scrapy.Request(
url=absolute_link,
callback=self.parse,
# 可选:携带优先级或元数据便于调试
# cb_kwargs={"source_url": response.url}
)✅ 关键设计说明:
- 使用
start_requests()替代start_urls,确保请求可控且可扩展; -
response.urljoin()正确处理相对路径,避免 URL 拼接错误; -
DEPTH_LIMIT: 1平衡覆盖率与性能——实测已覆盖/programs/lre-academy等深层路径;若需更广覆盖,可谨慎调至2,但务必配合DOWNLOAD_DELAY和ROBOTSTXT_OBEY; -
css("div.card-body")定位卡片区块,比直接用h5::text更鲁棒(避免误匹配导航栏或无关标题); - 匹配前调用
.strip()清除空格,提升字符串比对可靠性。
运行命令:
scrapy crawl card -o matches.jsonl
输出为 JSONL 格式,每行一个匹配结果,含来源 URL 与标题信息,便于后续清洗或导入数据库。
⚠️ 注意事项:
- 切勿移除
ROBOTSTXT_OBEY或大幅降低DOWNLOAD_DELAY,尊重网站爬虫协议是合规爬取的前提; - 若目标标题存在大小写变体(如 “az school safety program”),建议改用
title.lower() == "az school safety program"; - 对于大量卡片场景,可添加
item_count计数器或日志记录,监控爬取进度与异常中断点。
通过此方案,你不仅获得了精准的 URL 列表,更掌握了一种可复用的“内容定位式递归爬虫”范式——适用于课程列表、产品页、新闻聚合等多页面共现内容的自动化采集任务。

















