前言
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());}
}
复制代码
执行结果: