我正在开发一个 Scrapy 蜘蛛来从网站的多个页面中抓取数据。目标是爬行每个起始 URL 的所有页面,但我希望蜘蛛在爬行每个起始 URL 的最大页面后停止。然而,蜘蛛并没有按预期工作,它并没有爬过所有页面。
我尝试使用字典来实现计数管理,以跟踪每个 URL 抓取的页面数量。这是我当前的实现:
def parse(self, response):
# Get the current count from the request's
self.counts = {url: 1 for url in self.start_urls} # Initialize count for each start URL
# Check if the count has reached 100
count = self.counts[response.url]
if count > 100:
return # Stop crawling further
# Increment the count for the next page
self.counts[response.url] += 1
# Parse the items on the current page
for result in response.xpath(".//h2/a"):
yield scrapy.Request(url=result.xpath("@href").extract_first(), callback=self.parse_item)
# Generate the URL for the next page and request it
next_page_url = response.url + f"?page={count}"
yield scrapy.Request(next_page_url, callback=self.parse)
蜘蛛似乎启动并爬行了一些页面,但它在到达每个起始 URL 的所有页面之前停止了。我不确定我哪里出错了。如何修改蜘蛛程序以确保其爬行每个起始 URL 的所有页面(最多 100 页)?任何帮助或见解将不胜感激。
提前谢谢您!
您的方法存在很多问题。
您正在初始化解析方法内部的计数机制。这意味着每次调用 parse 方法时,它都会重建对象并删除以前的版本。
然后在下一行查询当前 url 的计数,因此结果要么为 1,要么在 request.url 不在其中的情况下抛出 KeyError 异常start_urls。
然后检查计数是否大于 100,这将始终为 False,因为如果它在上一步中幸存下来,则意味着它位于
start_urls
中,因此它的计数将为 1,因为您之前刚刚初始化了 2 条指令。
最后,您将为下一页生成一个新的 url,并创建一个由相同方法解析的请求,这意味着该请求可能不会在
start_urls
中,几乎保证它会抛出我之前提到的 KeyError 异常。
所以你所做的实际上是创建一种方法,几乎可以保证你永远不会超过 start_urls 中任何 url 的第一页,并且你的计数器永远没有机会达到 3,更不用说 100 了。
更好的选择是在解析方法之外初始化计数器字典,并将其作为蜘蛛的类属性而不是实例属性。但即便如此,这也无法实现您期望的目标,因为每个
next_page
请求生成的每个 start_url
都将具有唯一的 url,因此不会以您正在寻求的方式对计数器做出贡献。
更好的替代方法是重写 start_requests 方法,并在初始请求的 cb_kwargs 参数中包含一个计数器,您可以手动递增该计数器并将其传递到每个下一页,直到达到 100。
例如:
class MySpider(scrapy.Spider):
name = "spidername"
start_urls = [...]
def start_requests(self):
for url in self.start_urls:
yield scrapy.Request(url, callback=self.parse, cb_kwargs={"count": 1})
def parse(self, response, count=None):
if count >= 100:
return
for result in response.xpath(".//h2/a"):
yield scrapy.Request(url=result.xpath("@href").extract_first(), callback=self.parse_item)
next_page_url = response.url + f"?page={count}"
yield scrapy.Request(next_page_url, callback=self.parse, cb_kwargs={"count": count + 1})