Scrapy爬虫无法爬满单起始URL100页,请求排查与修正方案
问题分析与修复方案
核心问题
你的爬虫提前停止的根本原因有两个:
- 计数被重复初始化:每次调用
parse方法时,都会重新执行self.counts = {url: 1 for url in self.start_urls},导致之前累计的爬取页数全部丢失,永远无法累计到100页。 - 分页URL逻辑错误:生成下一页URL时使用的是当前页的计数,而非下一页的页码,会导致重复爬取同一页,被Scrapy的去重机制拦截后提前停止。
修复方案(推荐使用meta传递页码)
这种方式不需要依赖实例变量,每个请求携带自身的页码,避免多线程并发下的计数混乱,逻辑更清晰:
import scrapy from urllib.parse import urlparse, urlunparse class YourSpider(scrapy.Spider): name = "your_spider" start_urls = ["url1", "url2", ...] # 替换为你的起始URL列表 def start_requests(self): # 为每个起始URL发起初始请求,携带初始页码1 for url in self.start_urls: yield scrapy.Request(url, callback=self.parse, meta={"page": 1}) def parse(self, response): current_page = response.meta["page"] # 达到100页则停止爬取当前URL的后续页面 if current_page > 100: return # 解析当前页的内容,生成item请求 for result in response.xpath(".//h2/a"): item_url = result.xpath("@href").extract_first() if item_url: yield scrapy.Request(url=item_url, callback=self.parse_item) # 生成下一页请求 next_page = current_page + 1 # 提取基础URL(去掉分页参数),避免重复拼接page参数 parsed_url = urlparse(response.url) base_url = urlunparse(parsed_url._replace(query="")) next_page_url = f"{base_url}?page={next_page}" yield scrapy.Request(next_page_url, callback=self.parse, meta={"page": next_page}) def parse_item(self, response): # 这里写你的item解析逻辑 pass
备选方案(修正实例变量计数逻辑)
如果你坚持使用实例变量记录计数,需要将计数初始化移到爬虫的构造方法中,同时处理带分页参数的URL映射:
import scrapy from urllib.parse import urlparse, urlunparse class YourSpider(scrapy.Spider): name = "your_spider" start_urls = ["url1", "url2", ...] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 仅初始化一次每个起始URL的计数 self.counts = {url: 1 for url in self.start_urls} def parse(self, response): # 提取不带分页参数的基础URL,作为计数的key parsed_url = urlparse(response.url) base_url = urlunparse(parsed_url._replace(query="")) count = self.counts.get(base_url, 1) if count > 100: return # 解析当前页内容 for result in response.xpath(".//h2/a"): item_url = result.xpath("@href").extract_first() if item_url: yield scrapy.Request(url=item_url, callback=self.parse_item) # 更新计数并生成下一页请求 next_count = count + 1 self.counts[base_url] = next_count next_page_url = f"{base_url}?page={next_count}" yield scrapy.Request(next_page_url, callback=self.parse) def parse_item(self, response): # 这里写你的item解析逻辑 pass
关键说明
- 基础URL提取:必须将带分页参数的URL转换为基础URL(去掉
?page=xxx部分),否则每个分页URL都会被当成新的key,计数永远停留在1。 - meta传递页码的优势:Scrapy是异步多线程爬虫,实例变量可能被多个请求同时修改导致计数错误,而每个请求携带的meta参数是独立的,完全避免了并发问题。
内容的提问来源于stack exchange,提问作者user13998985
相关产品推荐
相关产品推荐

