# Leetcode-Api
**Repository Path**: nesercode/Leetcode-Api
## Basic Information
- **Project Name**: Leetcode-Api
- **Description**: HttpRequest api for leetcode(zh-cn). / 关于力扣的网络请求接口。
- **Primary Language**: JavaScript
- **License**: GPL-3.0
- **Default Branch**: NeserCode
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 2
- **Forks**: 0
- **Created**: 2022-06-05
- **Last Updated**: 2025-06-16
## Categories & Tags
**Categories**: Uncategorized
**Tags**: JavaScript, LeetCode, API
## README
# Leetcode-Api
[English Document](README.md)
关于 力扣 的网络请求接口。
!!!注意,由于 Leetcode 中文站的域名更改,[提交ID API](#提交ID)已被临时重定向(304),并更改为官方禁止的提交方法(GET)。[提交ID API](#提交ID)暂时被弃用,稍后将进行更新。
## 目录
* [免责声明](#免责声明)
* [使用](#使用)
* [项目总览](#项目总览)
* [接口相关](#接口相关)
* [接口详情](#接口详情)
## 免责声明
**本项目仅供学习交流参考,在任意情况下均不得用于任何商业用途。如若违反声明,后果自负,本人不承担任何责任。**
## 使用
点击位于右侧的 package 选项卡,或者您可以点击 [这里](https://github.com/NeserCode/Leetcode-Api/packages/1376786) 。
## 项目总览
本项目提供的是 **力扣** 官方网站的 **WebApi** 集合,提出的 Api 均已试验成功。
本项目仅包含一个入口 Javascript 文件,将本文档中提出的 WebApi 全部封装到 $Leetcode 类中。
所以,想使用 Leetcode-Api,你只需:
```javascript
import $Leetcode from "Leetcode-Api"
const variable = new $Leetcode()
```
然后通过上例中的 variable 使用 Leetcode-Api 中的函数方法。
## 接口相关
力扣 官网使用了 [**GraphQL**](https://graphql.org/) 技术来获取数据,即 **按需分配数据** 的模式。同时,全部网络请求需要附着 Cookie 访问,部分网络请求需要确认 **Referer** 是否属于力扣域名之下。请使用这些 WebApi 之前制定好相关解决方案。
本项目接口内容**随缘更新**。可以人工催促。当然,这都必须建立在**合理**的基础上。
### 部分解决方案
在传统的 HTML5 项目中,如:
```html
|-images
|--images01.jpg
|-js
|--example.js
|-style
|--style.css
|-index.html
```
这种项目中,由于伪造 Referer 带来的不安全和危险,一般不会允许用户通过 Javascript 脚本去修改 HttpRequest 的表头中的几项,也就是 RequestHeader 中的几项,其中就包含有 Referer 项。
而在 Vue 的脚手架中可以使用 Webpack 相关的 **DevProxy** 项设置相关的请求表头,从而起到伪造 Referer 以获取数据的效果。
这样的例子在互联网上有许多,本人不在这里一一赘述,正好最近在写一个新的 [**Electron**](https://www.electronjs.org/) 项目,用到了伪造 Referer 的功能,在这里可以举例一番。
```javascript
import { remote } from "electron"
const {session} = remote
;function someFn(){
session.defaultSession.webRequest.onBeforeSendHeaders({ urls: ['https://leetcode-cn.com/*'] }, (details, callback) => {
details.requestHeaders['Referer'] = `https://leetcode-cn.com/`
callback({ cancel: false, requestHeaders: details.requestHeaders })
})
//...
}
```
在给出的实例化的对象中,所有的函数方法都会返回 [**axios**](https://www.axios-http.cn/) 对象。所以,你可以从函数的 **then** 回调中获取数据,例如:
```javascript
import { remote } from "electron"
const { session } = remote
,$leetcode = new $Leetcode()
;function someFn(questionSlug){
$leetcode.getUserStatus().then((response)=>{
if(response.status == 200)
const { userStatus } = response.data.data
else
console.log(response)
//...
})
}
```
相关的文档请移步相关技术或者自行查询。
## 接口详情
所有接口在文档更新时均已通过测试。
- [用户状态](#用户状态)
- [题目集合](#题目集合)
- [题目详情](#题目详情)
- [题目状态](#题目状态)
- [提交ID](#提交ID)
- [提交详情](#提交详情)
下文表格中提到的 Cookie 项,是指用户在登录力扣官方网站生成的 **LEETCODE_SESSION** 与 **x-csrftoken** 项,获取方法:使用浏览器登录成功后,打开开发人员工具中的网络一项,寻找成功状态的 graphql 请求,在请求信息中可以找到这两项的值。
> 接口中标注 `必须使用Cookie` 时,即必须携带上述两项 Cookie 进行网络请求才能获取到数据;接口中标注 `可以不使用Cookie` 时,即携带上述两项 Cookie 进行网络请求才能获取到完整数据(表项中带有 * 的需要携带 Cookie 才能正常获取);无标注即为普通的网络请求,不需要携带 Cookie 也能正常获取到完整数据。
### 用户状态
! **必须使用Cookie**
```javascript
const $leetcode = new $Leetcode()
;$leetcode.getUserStatus().then((response)=>{
if(response.status == 200)
const { commonNojPermissionTypes, jobsMyCompany, userStatus } = response.data.data
else
console.log(response)
//...
}) // must with cookie [LEETCODE_SESSION,x-csrftoken]
```
请求数据项:
| Item | Value |
| :--------: | :-------------------------------------------- |
| Type | `POST` |
| Parameters | `NULL` |
| URL | `https://leetcode-cn.com/graphql` |
| Require | `Cookie Item [LEETCODE_SESSION, x-csrftoken]` |
获取到的数据项:
| Key | Value | Describe |
| :-------------------------- | :------------: | :--------------- |
| commonNojPermissionTypes | Array[Object?] | 未知 |
| jobsMyCompany | Object | 用户公司 |
| userStatus | Object | 用户状态 |
| userStatus.avatar | String | 用户头像 |
| userStatus.isAdmin | Boolean | 是否是管理员 |
| userStatus.isPhoneVerified | Boolean | 是否通过手机验证 |
| userStatus.isPremium | Boolean | 未知 |
| userStatus.isSignedIn | Boolean | 是否登录 |
| userStatus.isSuperuser | Boolean | 是否是VIP |
| userStatus.isTranslator | Boolean | 是否是翻译 |
| userStatus.isVerified | Boolean | 是否通过身份验证 |
| userStatus.premiumExpiredAt | Number | 未知 |
| userStatus.realName | String | 用户昵称 |
| userStatus.useTranslation | Boolean | 是否使用翻译 |
| userStatus.userSlug | String | 用户标签 |
| userStatus.username | String | 用户名 |
### 题目集合
! **可以不使用Cookie**
```javascript
const $leetcode = new $Leetcode()
,categorySlug = "" //defalut
,skip = 0 //defalut
,limit = 25 //defalut
;$leetcode.getQuestionSet(categorySlug, skip, limit).then((response)=>{
if(response.status == 200)
const { problemsetQuestionList } = response.data.data
else
console.log(response)
//...
}) // with cookie [LEETCODE_SESSION,x-csrftoken] or not
```
请求数据项:
| Item | Value |
| :--------: | :----------------------------------------------------- |
| Type | `POST` |
| Parameters | `categorySlug`, `skip`, `limit` |
| URL | `https://leetcode-cn.com/graphql` |
| Require | `NULL` / `Cookie Item [LEETCODE_SESSION, x-csrftoken]` |
参数项:
- `categorySlug`,分类名,获取的题目集合将只含有此分类,默认分类为空字符串。
- `skip`,跳过数,分页相关,获取数量从头部减去 skip 条,默认为 0 条。
- `limit`,数据数量,分页相关,获取数据的数量,默认为 25 条。
获取到的数据项:
| Key | Value | Describe |
| :----------------------------------------------------------- | :-----------: | :----------------------------------- |
| problemsetQuestionList | Array[Object] | 题目集合对象 |
| problemsetQuestionList.hasMore | Boolean | 是否有更多题目 |
| problemsetQuestionList.questions | Array[Object] | 题目集合 |
| problemsetQuestionList.questions.acRate | Number | 题目通过率 |
| problemsetQuestionList.questions.difficulty | String | 题目难度 |
| problemsetQuestionList.questions.extra | Object | 题目额外信息 |
| problemsetQuestionList.questions.extra.companyTagNum | Number | 公司数量 |
| problemsetQuestionList.questions.extra.hasVideoSolution | Boolean | 该题是否有解法视频 |
| problemsetQuestionList.questions.extra.topCompanyTags | Array[Object] | 相关公司集合 |
| problemsetQuestionList.questions.extra.topCompanyTags.imgUrl | String | 相关公司头像 |
| problemsetQuestionList.questions.extra.topCompanyTags.slug | String | 相关公司标题 |
| problemsetQuestionList.questions.freqBar | Boolean | 未知 |
| problemsetQuestionList.questions.frontendQuestionId | String | 题目的前端ID |
| *problemsetQuestionList.questions.isFavor | Boolean | 题目是否被收藏,需要用户登录 |
| problemsetQuestionList.questions.paidOnly | Boolean | 题目是否付费 |
| problemsetQuestionList.questions.solutionNum | Number | 题目已知解法数量 |
| *problemsetQuestionList.questions.status | String | 题目通过状态,需要用户登录,默认NULL |
| problemsetQuestionList.questions.title | String | 题目的题名 |
| problemsetQuestionList.questions.titleCn | String | 题目的题名(中文) |
| problemsetQuestionList.questions.titleSlug | String | 题目的标题 |
| problemsetQuestionList.questions.topicTags | Array[Object] | 题目相关话题集合 |
| problemsetQuestionList.questions.topicTags.id | String | 话题ID |
| problemsetQuestionList.questions.topicTags.name | String | 话题名称 |
| problemsetQuestionList.questions.topicTags.nameTranslated | String | 话题名称(中文) |
| problemsetQuestionList.questions.topicTags.slug | String | 话题标题 |
| problemsetQuestionList.total | Number | 题目总数 |
### 题目详情
! **可以不使用Cookie**
```javascript
const $leetcode = new $Leetcode()
,questionSlug = "two-sum"
;$leetcode.getQuestion(questionSlug).then((res)=>{
if(res.status == 200)
const { question } = res.data.data
}) // with cookie [LEETCODE_SESSION,x-csrftoken] or not
```
请求数据项:
| Item | Value |
| :--------: | :----------------------------------------------------- |
| Type | `POST` |
| Parameters | `questionSlug` |
| URL | `https://leetcode-cn.com/graphql` |
| Require | `NULL` / `Cookie Item [LEETCODE_SESSION, x-csrftoken]` |
参数项:
- `questionSlug`,题目标题,必须是本 Api 中 `question.titleSlug` 的可选值。
获取到的数据项:
| Key | Value | Describe |
| :-------------------------------- | :------------: | :-------------------------------- |
| question | Object | 题目对象 |
| question.book | Object? | 题目书籍 |
| question.boundTopicId | Object | 题目相关话题数量 |
| question.categoryTitle | String | 题目分类名 |
| question.codeSnippets | String | 题目代码对象 |
| question.codeSnippets.code | String | 题目代码内容(初始值) |
| question.codeSnippets.lang | String | 题目代码语言 |
| question.codeSnippets.langSlug | String | 题目代码语言标题 |
| question.companyTagStats | String? | 未知,题目相关公司? |
| question.content | String | 题目内容 |
| question.contributors | Array[Object?] | 未知,题目贡献者? |
| question.dailyRecordStatus | String | 题目每日状态记录 |
| question.difficulty | String | 题目难度 |
| question.dislikes | Number | 题目踩数量 |
| question.editorType | String | 未知,题目编辑器风格? |
| question.enableRunCode | Boolean | 是否可以运行代码 |
| question.envInfo | String | 题目警告信息 |
| question.exampleTestcases | String | 题目样例 |
| question.hints | Array[String] | 题目提示 |
| question.isDailyQuestion | Boolean | 是否是每日一题 |
| *question.isLiked | String? | 题目是否点赞 |
| question.isPaidOnly | Boolean | 题目是否付费 |
| *question.isSubscribed | Boolean | 是否订阅题目 |
| question.judgeType | String | 未知,题目判定类型? |
| question.judgerAvailable | Boolean | 未知,判定是否可用? |
| question.langToValidPlayground | String | 题目可用的语言 |
| question.likes | Number | 题目赞数量 |
| question.metaData | String | 题目预设信息 |
| question.mysqlSchemas | Array[Object?] | 未知,题目数据库信息? |
| question.questionFrontendId | String | 题目前端ID |
| question.questionId | String | 题目ID |
| question.sampleTestCase | String | 题目一般测试用例 |
| question.similarQuestions | String | 相似题目对象(JSON.stringfy) |
| question.solution | Object | 题目解法对象 |
| question.solution.canSeeDetail | Boolean | 未知,题目解法细节是否可见? |
| question.solution.id | String | 题目解法ID |
| question.stats | String | 题目通过状态(总体)(JSON.stringfy) |
| *question.status | String | 题目通过状态,需要用户登录 |
| question.style | String | 未知,题目风格? |
| question.title | String | 题目题名 |
| question.titleSlug | String | 题目标题 |
| question.topicTags | Array[Object] | 题目话题标签 |
| question.topicTags.name | String | 题目话题标签名 |
| question.topicTags.slug | String | 题目话题标签标题 |
| question.topicTags.translatedName | String | 题目话题标签名(中文) |
| question.translatedContent | String | 题目内容(中文) |
| question.translatedTitle | String | 题目题名(中文) |
| question.ugcQuestionId | String | 未知,题目UGCID? |
### 题目状态
! **必须使用Cookie**
```javascript
const $leetcode = new $Leetcode()
;$leetcode.getQuestionStatus().then((res)=>{
if(res.status == 200)
const { allQuestionsBeta } = res.data.data
}) // must with cookie [LEETCODE_SESSION,x-csrftoken]
```
请求数据项:
| Item | Value |
| :--------: | :-------------------------------------------- |
| Type | `POST` |
| Parameters | `NULL` |
| URL | `https://leetcode-cn.com/graphql` |
| Require | `Cookie Item [LEETCODE_SESSION, x-csrftoken]` |
获取到的数据项:
| Key | Value | Describe |
| :-------------------------- | :-----------: | :----------- |
| allQuestionsBeta | Array[Object] | 题目状态对象 |
| allQuestionsBeta.questionId | String | 题目ID |
| allQuestionsBeta.status | String | 题目状态 |
### 提交ID
! **必须使用Cookie、伪造referer**
```javascript
const $leetcode = new $Leetcode()
,question_id = 1
,lang = 'cpp'
,typd_code = "..."
,questionSlug = "two-sum"
;$leetcode.getSubmissionID(question_id, lang, typed_code, questionSlug).then((res)=>{
session.defaultSession.webRequest.onBeforeSendHeaders({ urls: ['https://leetcode-cn.com/problems/*'] }, (details, callback) => {
details.requestHeaders['Referer'] = `https://leetcode-cn.com/problems/${questionSlug}/submissions/`
callback({ cancel: false, requestHeaders: details.requestHeaders })
})
if(res.status == 200)
const { submission_id } = res.data
}) // must with cookie [LEETCODE_SESSION,x-csrftoken] and referer [https://leetcode-cn.com/problems/${questionSlug}/submissions/]
```
> 注意,在这个 Api 中,Cookies 必须被携带在 `https://leetcode-cn.com/problems/${questionSlug}/submit`,即访问的 URL ,否则会触发力扣的 **CSRF** 校验失败。同时,此 Api 还需要伪造 Referer 为 `https://leetcode-cn.com/problems/${questionSlug}/submissions/`,其中字符串模板中的变量 questionSlug 为题目标题,必须为 [题目详情 API](#题目详情) 中 `question.titleSlug` 的可选值
请求数据项:
| Item | Value |
| :--------: | :----------------------------------------------------------- |
| Type | `POST` |
| Parameters | `question_id`, `lang`, `typed_code`, `questionSlug` |
| URL | `https://leetcode-cn.com/problems/${questionSlug}/submit/` |
| Require | `Cookie Item [LEETCODE_SESSION, x-csrftoken]`, `referer [https://leetcode-cn.com/problems/${questionSlug}/submissions/]` |
参数项:
- `question_id`,题目ID,必须是 [题目详情API](#题目详情) 中 `question.questionId` 的可选值。
- `lang`,题目语言,必须是 [题目详情API](#题目详情) 中 `question.codeSnippets.langSlug` 的可选值。
- `typed_code`,运行代码,将测试运行的题解代码。
- `questionSlug`,题目标题,必须是 [题目详情API](#题目详情) 中 `question.titleSlug` 的可选值。
- `test_mode`,测试模式。
- `test_judger`,测试判定器。
获取到的数据项:
| Key | Value | Describe |
| :------------ | :----: | :--------- |
| submission_id | Number | 题目提交ID |
### 提交详情
```javascript
const $leetcode = new $Leetcode()
,submission_id = 123456789
;$leetcode.getSubumissionStatus(submission_id).then((res)=>{
if(res.status == 200)
const { data } = res
}) // can without anything.
```
请求数据项:
| Item | Value |
| :--------: | :----------------------------------------------------------- |
| Type | `GET` |
| Parameters | `submission_id` |
| URL | `https://leetcode-cn.com/submissions/detail/${submissionID}/check/` |
| Require | `NULL` |
参数项:
- `submission_id`,题目ID,必须是 [提交ID API](#提交ID) 中 `submission_id` 的可选值。
获取到的数据项:
| Key | Value | Describe |
| :---------------------- | :-----: | :--------------------- |
| data | Object | 题目提交ID |
| data.compile_error | String | 题解编译错误 |
| data.elapsed_time | Number | 题解运行时间 |
| data.fast_submit | Boolean | 是否快速提交 |
| data.finished | Boolean | 是否运行完毕? |
| data.full_compile_error | String | 题解编译错误(完整) |
| data.lang | String | 题解语言 |
| data.memory | Number | 题解运行占用内存空间 |
| data.memory_percentile | String? | 题解运行占用内存百分比 |
| data.pretty_lang | String | 题解语言(还原化) |
| data.question_id | String | 题解对应题目ID |
| data.run_success | Boolean | 题解是否成功运行 |
| data.runtime_percentile | String? | 题解运行时间百分比? |
| data.state | String | 题解当前判定状态 |
| data.status_code | Number | 题解判定状态码 |
| data.status_memory | String | 判定状态占用内存 |
| data.status_msg | String | 判定状态消息 |
| data.status_runtime | String | 判定状态运行时间 |
| data.submission_id | String | 题解提交ID |
| data.task_finish_time | Number | 题解提交时间? |
| data.task_name | String | 题解判定器名称 |
| data.total_correct | Number? | 题解通过的测试用例 |
| data.total_testcases | Number? | 题解全部的测试用例 |