一系列json页面通过该页面上的最后一个id相互链接。该网页的网址为example.com/20/id
所以我想抓取第一页,保存数据,获取该页面的最后一个ID并抓取另一页:example.com/40/new_id
依此类推,每次都会有20个结果。我不知道有多少页面,所以当没有id时我会停下来。
这应该是一个简单的递归,但我不知道如何做,并在同一时间保存数据。我对此感到困惑:
yield scrapy.Request(url, self.parse)
在我看来应该递归,直到没有id,但它只运行2次。
import scrapy
import json
import logging
from w3lib.url import add_or_replace_parameter
import re
class MySpider(scrapy.Spider):
name = 'myspider'
start_urls = ['https://www.example/0/1234']
def parse(self, response): # check if there is an id
data = json.loads(str(response.body, 'utf-8'))
dataLength = len(data)
page = 0
if data[dataLength - 1]["id"]:
page += 20
url = add_or_replace_parameter(response.url, 'after', data[dataLength - 1]["id"])
url = re.sub(r"([0-9]){1,9}(?=\?)", str(page), url) # build the new url
yield scrapy.Request(url, self.parse_page) #save data
yield scrapy.Request(url, self.parse) #do it again with the new url recursively, this bit doesn't work
yield from self.parse_page(response) # do it for the first page
def parse_page(self, response):
data = json.loads(str(response.body, 'utf-8'))
for item in data:
finalData = {"language": item["languageName"]}
yield finalData
在控制台scrapy runspider scrap_kaggle.py -o file.csv -t csv
中运行只保存csv文件中的前2个网址。
答案 0 :(得分:1)
首先,我想解释为什么你只得到两个回应。您有一个逻辑错误:在parse
函数中,您初始化page=0
,以便以下请求始终为page=20
,不再包含任何页面。
然后我想给你一些建议,因为递归爬行的逻辑性有点大。根据{{3}}:
解析(响应) 这是Scrapy在其请求未指定回调时用于处理下载响应的默认回调。
解析方法负责处理响应并返回要删除的数据和/或更多URL。其他请求回调与Spider类具有相同的要求。
此方法以及任何其他请求回调 必须返回可迭代的Request和/或dicts或Item对象 。
(注意我标记的粗体部分)。这意味着parse
函数本身可以执行两个操作:解析项目(在您的情况下保存操作)并跟随下一个请求(在您的情况下,递归操作)。因此,您不需要两个不同的parse
函数。
最后,我想提供一个伪代码来解释这个想法。请确保可以正确构建下一个请求URL。我无法测试您负责的代码:
import scrapy
import json
import logging
from w3lib.url import add_or_replace_parameter
import re
class MySpider(scrapy.Spider):
name = 'myspider'
start_urls = ['https://www.example/0/1234']
def parse(self, response): # check if there is an id
data = json.loads(str(response.body, 'utf-8'))
# SAVE ITEMS OPERATION
for item in data:
finalData = {"language": item["languageName"]}
yield finalData
dataLength = len(data)
# YOU NEED TO DETERMINE THE PAGE NUMBER TO BUILD NEXT REQUEST URL
page = GET_PREV_PAGE #get the previous page number by response.url
if data[dataLength - 1]["id"]:
page += 20
url = add_or_replace_parameter(response.url, 'after', data[dataLength - 1]["id"])
url = re.sub(r"([0-9]){1,9}(?=\?)", str(page), url) # build the new url
# SEND NEXT REQUEST, THE RECURSION OPERATION
yield scrapy.Request(url, self.parse)
如您所见,保存操作和后续操作都可以放在一个parse
函数中。以下操作中最重要的部分是确定下一个请求的URL。对于您的情况,您可以通过解析响应数据和响应URL来确定它。如果您需要更多信息来确定下一个网址,可以将这些数据放入meta
请求中,然后通过meta
响应进行检索,请检查scrapy spider docs。例如,在产生请求时,您可以:
yield Request(url, meta=dict(page=CURRENT_PAGE_ID)
在您的parse
函数中,处理响应时,您可以检索此元数据以构建下一个请求:
page = response.meta['page']
next_page = page + 20
这仅适用于复杂的情况。在你的情况下,页面很容易获得,你不需要。
希望这会有所帮助。 感谢。