Scrapy爬取Niche.com时href为#的学校链接无法跳转问题解决
解决Scrapy爬取Niche.com学校详情页的问题
遇到学校链接href为#的情况,本质是网站用JS动态控制跳转,真实链接通常藏在其他属性或页面内嵌的JSON数据里,下面是具体解决方案:
1. 定位真实详情页链接
检查自定义属性
大多数这类网站会把真实链接放在a标签的自定义属性里,比如data-url、data-href。打开开发者工具查看学校卡片的a标签,找到类似这样的结构:
<a href="#" data-url="/k12/wisconsin/abc-high-school">...</a>
直接提取data-url的值即可。
查找页面内嵌JSON数据
如果页面用React、Vue等框架渲染,真实数据通常会放在script标签里(比如id="__NEXT_DATA__"的标签),里面包含完整的学校列表和详情页URL。
抓包分析AJAX请求
滚动页面加载更多学校时,网站可能通过XHR请求获取分页数据,返回的JSON里会包含每个学校的详情链接。
2. Scrapy代码实现示例
列表页解析(提取真实链接)
import scrapy import json class NicheSchoolSpider(scrapy.Spider): name = 'niche_wi_schools' start_urls = ['https://www.niche.com/k12/search/best-schools/wisconsin/'] def parse(self, response): # 方法1:提取自定义属性中的链接 for school_card in response.css('div[class*="SchoolCard"]'): detail_path = school_card.css('a::attr(data-url)').get() if detail_path: detail_url = response.urljoin(detail_path) yield scrapy.Request(detail_url, callback=self.parse_detail) # 方法2:解析页面内嵌JSON(如果方法1无效时用) # script_content = response.css('script#__NEXT_DATA__::text').get() # if script_content: # data = json.loads(script_content) # schools = data['props']['pageProps']['searchResults']['items'] # for school in schools: # detail_url = response.urljoin(school['url']) # yield scrapy.Request(detail_url, callback=self.parse_detail) # 处理分页 next_page = response.css('a.pagination__next::attr(href)').get() if next_page: yield scrapy.Request(response.urljoin(next_page), callback=self.parse) def parse_detail(self, response): # 提取学校详情信息,根据实际页面结构调整选择器 yield { '学校名称': response.css('h1[class*="Heading__HeadingStyled"]::text').get(default='').strip(), '地址': response.css('div[class*="SchoolHeader__Address"]::text').get(default='').strip(), '电话': response.css('a[class*="SchoolHeader__PhoneLink"]::text').get(default='无'), '学费': response.css('div[class*="FactTable__Value"]:contains("Tuition")::text').get(default='').strip(), '招生人数': response.css('div[class*="FactTable__Value"]:contains("Enrollment")::text').get(default='').strip() }
3. 反爬注意事项
- 设置合理的
DOWNLOAD_DELAY(比如2-3秒),避免请求过于频繁 - 在
settings.py中配置真实的USER_AGENT,模拟浏览器请求 - 若遇到验证码或IP封禁,可考虑使用代理IP池
内容的提问来源于stack exchange,提问作者Shivam Lanke
相关产品推荐
相关产品推荐

