爬取LeetCode题目——如何发送GraphQL Query获取数据

前言

  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

过程

  若是直接搜索以 Java 语言为载体的 GraphQL 的话,一大部分搜索结果都是介绍使用 graphql-java 来搭建查询服务,而咱们的目的是利用 GraphQL 来获取想要的数据,并不是本身搭建一个查询服务,所以若是一开始就选错了工具,就会致使后面的方向都是错误的。   以 LeetCode 第一题 1.Two Sum 为例,获取其后端发送过来的数据。利用 F12 功能调出以下界面,选 Network git

找到 graphql 文件(有好多 graphql 文件,能够依次点击查找本身想要的那个,这里找到包含有题目信息的),从 preview 中咱们能够看到 data 返回了题目相关的信息
  那么,如何构造 GraphQL Query 来获取信息呢?从 Header 中的 Request Payload 中咱们能够看到一个 query的字段,这是咱们要构造的 GraphQL Query 的一个重要信息。
  咱们并不一开始就用代码来获取题目信息,而是先利用 Postman 来看看如何获取题目信息。右键 Network 下的 graphql 文件—>Copy—>Copy as cURL(bash),以下图所示:
以后,打开 Postman—>左上角Import—>Paste Raw Text粘贴,从 Body中能够看到,构造好了的 GraphQL Query 与咱们在 Request Payload 中看到的 query 的字段相仿(由于有一点须要更改的细节)
固然,若是不想直接粘贴复制的 cURL,那么咱们能够本身在 Postman 中写 Header 和 Body,须要注意的是这边的 Content-Typeapplication/graphql,Body 中的 GraphQL 构造,参照 Request Payload 中的 query的字段来构造
获取到的结果以下:
咱们在实际中,可能并不须要提供的全部信息,只想要某一部分,那么只需更改 query便可,这也是 GraphQL 的强大之处。好比咱们只想要题目的 content信息,那么其 query则为

query{question(titleSlug:"two-sum") {content}}
复制代码

代码

在上边,已经利用 Postman 查询到想要的数据了,而如今咱们要作的就是用代码将上述操做展现出来。这边,使用 OkHttp 来进行题目信息获取。github

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());

    }
}
复制代码

执行结果: 后端

相关文章
相关标签/搜索