前言
GraphQL 是一種用於 API 的查詢語言,是由 Facebook 開源的一種用於提供資料查詢服務的抽象框架。在服務端 API 開發中,很多時候定義一個介面返回的資料相對固定,因此要獲得更多資訊或者只想得到某部分資訊時,基於 RESTful API 的介面就顯得不那麼靈活。而 GraphQL 對 API 中的資料提供了一套易於理解的完整描述,使得客戶端能夠準確地獲得它需要的資料,而且沒有任何冗餘,也讓 API 更容易地隨著時間推移而演進,還能用於構建強大的開發者工具。 目前,LeetCode 和 GitHub 都藉助 GraphQL 來設計,提供了更大的靈活性,對於想借助 GitHub 來了解 GraphQL 可直接訪問 GraphQL API v4 ,或者參考 GraphQL 實戰:Github V4 API使用。而對於在 LeetCode 上使用 GraphQL 查詢,相對資料少一些,因此在這,我主要以 LeetCode 為例,來做講解(其實是因為自己業餘刷題時突發奇想,想寫一個爬蟲。
過程
如果直接搜尋以 Java 語言為載體的 GraphQL 的話,一大部分搜尋結果都是介紹使用 graphql-java 來搭建查詢服務,而我們的目的是利用 GraphQL 來獲取想要的資料,並非自己搭建一個查詢服務,因此如果一開始就選錯了工具,就會導致後面的方向都是錯誤的。 以 LeetCode 第一題 1.Two Sum 為例,獲取其後端傳送過來的資料。利用 F12 功能調出如下介面,選 Network


query
的欄位,這是我們要構造的 GraphQL Query 的一個重要資訊。


query
的欄位相仿(因為有一點需要更改的細節)

Content-Type
是application/graphql
,Body 中的 GraphQL 構造,參照 Request Payload 中的query
的欄位來構造


query
即可,這也是 GraphQL 的強大之處。比如我們只想要題目的content
資訊,那麼其query
則為
query{question(titleSlug:"two-sum") {content}}
複製程式碼
程式碼
在上邊,已經利用 Postman 查詢到想要的資料了,而現在我們要做的就是用程式碼將上述操作展示出來。這邊,使用 OkHttp 來進行題目資訊獲取。
import okhttp3.*;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import java.io.IOException;
import java.util.Map;
import static java.lang.System.out;
public class Question {
public static void main(String... args) throws IOException {
String questionUrl = "https://leetcode.com/problems/two-sum/description/";
String graphqlUrl = "https://leetcode.com/graphql";
Connection.Response response = Jsoup.connect(questionUrl)
.method(Connection.Method.GET)
.execute();
Map<String,String>cookies = response.cookies();
for (Map.Entry<String,String>entry:cookies.entrySet()){
//out.println(entry.getKey() + ": " + entry.getValue());
}
String csrftoken = response.cookie("csrftoken");
String __cfduid = response.cookie("__cfduid");
OkHttpClient client = new OkHttpClient.Builder()
.followRedirects(false)
.followSslRedirects(false)
.build();
String postBody = "query{\n" +
" question(titleSlug:\"two-sum\") {\n" +
" content\n" +
" }\n" +
"}\n";
Request request = new Request.Builder()
.addHeader("Content-Type","application/graphql")
.addHeader("Referer",questionUrl)
.addHeader("Cookie","__cfduid=" + __cfduid + ";" + "csrftoken=" + csrftoken)
.addHeader("x-csrftoken",csrftoken)
.url(graphqlUrl)
.post(RequestBody.create(MediaType.parse("application/graphql; charset=utf-8"),postBody))
.build();
Response response1 = client.newCall(request).execute();
//out.println(response1.headers());
out.println(response1.body().string());
}
}
複製程式碼
執行結果:
