LeetCode Archiver(2):获取题目信息
创建爬虫 在新建好项目后,用PyCharm或其他IDE打开该项目。进入该项目文件夹,使用genspider命令新建一个爬虫: cd scrapy_project scrapy genspider QuestionSetSpider leetcode.com 其中QuestionSetSpider是爬虫的名字,leetcode.com是我们打算爬取的网站的域名。 新建好爬虫之后可以看到在项目的spiders文件夹下新增了一个名为 QuestionSetSpider.py的文件,这就是我们刚才新建的爬虫文件。这个爬虫文件会自动生成以下代码 # -*- coding: utf-8 -*- import scrapy class QuestionSetSpider(scrapy.Spider): name = 'QuestionSetSpider' allowed_domains = ['leetcode.com'] start_urls = ['http://leetcode.com/'] def parse(self, response): pass QuestionSetSpider类继承自scrapy.Spider,也就是scrapy框架中所有爬虫的基类; self.name属性是该爬虫的名字,在该爬虫文件的外部可以通过这个属性获取当前爬虫; self.allowed_domains是当前爬虫文件可以访问的域名列表,如果在爬取页面时进入了一个该域名以外的url会抛出错误; self.start_urls是一个url列表,基类中定义了start_requests函数,它会遍历self.start_urls,并对每一个url调用scrapy.Request(url, dont_filter=True),为了实现爬取题目的需求,我们需要重写self.start_urls函数 获取题目详细信息 分析 LeetCode使用了GraphQL进行数据的查询和传输,大部分页面都是通过JS渲染生成的动态页面,所以无法直接从页面上获取标签,即使使用提供JavaScript渲染服务的库(例如Splash)也无法获取全部的数据,所以只能通过发送请求来获取数据。 为了爬取题目的详细信息,我们首先要从题目列表进入每个题目对应的链接。 首先打开leetcode的problem列表,按F12打开Chrome的开发者工具,进入Network标签栏,勾选上Preserve log,刷新该页面。 可以看到,网页向 https://leetcode.com/api/problems/all/ 发送了一个名为"all/“的GET类型的Request,这就是获取所有题目链接和相关信息的请求。如果此时已经安装了Toggle JavaScript插件,我们可以直接右键点击“Open in new tab”,查看该请求返回的Response。 更方便的方法是使用postman向服务器发送一个相同的Request,并将其保存下来,这样如果我们下次需要查看相应的Response的时候就不需要再使用开发者工具了。 返回的Response是一个json对象,其中的"stat_status_pairs"键所对应的值是所有包含题目信息的list,而列表中的[“stat”][“question__title_slug”]就是题目所在的页面。以Largest Perimeter Triangle为例,将其title_slug拼接到https://leetcode.com/problems/ 后,进入页面https://leetcode.com/problems/largest-perimeter-triangle/ 。同样地,打开开发者工具,刷新页面,可以看到服务器返回了很多项graphql的查询数据,通过查看Request Payload可以找到其中operationName为"questionData"的一项,这就是当前题目的详细信息。 将Payload复制粘贴到postman的Body中,在Headers中设置Content-Type为application/json,发送请求,可以看到返回的是一个json对象,包含了该题目所对应的所有信息。 接下来我们就可以对该题目的信息进行处理了。 实现 为了获取题目列表的json对象,我们需要先重写start_requests函数。 def start_requests(self): self.Login() # 用户登录,后续会用到 questionset_url = "https://leetcode.com/api/problems/all/" yield scrapy.Request(url=questionset_url, callback=self.ParseQuestionSet) Request是scrapy的一个类对象,功能类似于requests库中的get函数,可以让scrapy框架中的Downloader向url发送一个get请求,并将获取的response交给指定的爬虫文件中的回调函数进行相应的处理,其构造函数如下 ...