Export all Yuque documents as markdown files (no super membership required)

Foreword: On October 23, 2023, Yuque hung up for a while, which made me unable to write documents. This made me realize that it was unreliable to put all the documents on the cloud server. Make a local backup, so the content of this article is available.
Important note: The code has not been rigorously tested, but I have no problem using it myself, so I don’t care. I don’t want to waste too much time on this. The exported file will < strong>Stored in one directory per knowledge base

1. First import the apache httpclient dependency

<!-- apache http -->
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.10</version>
</dependency>

2. Get your authToken and csrfToken

First enter any of your knowledge bases, press F12 to open the developer tools, then click on the network, enter “yuque”, then clear the log, click on any article, and then Yuque will send a request to Yuque’s server To get comments on your article, this request carries your authToken and csrfToken

Then scroll all the way down in Headers on the right and find Request Headers. You will see authToken and csrfToken, and copy them to Just replace it in the code below

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
import org.json.JSONObject;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;

public class YuqueAPIClient {

    static String authToken = "to be replaced";

    static String csrfToken = "to be replaced";

    public static void main(String[] args) {
        String baseURL = "https://www.yuque.com/api";
        String personalBooksURL = baseURL + "/mine/personal_books";

        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            // Step 1: Get the IDs of all knowledge bases
            HttpGet personalBooksRequest = new HttpGet(personalBooksURL);
            personalBooksRequest.setHeader("Cookie", authToken);
            personalBooksRequest.setHeader("X-Csrf-Token", csrfToken);

            HttpResponse personalBooksResponse = httpClient.execute(personalBooksRequest);
            HttpEntity personalBooksEntity = personalBooksResponse.getEntity();
            String personalBooksResponseString = EntityUtils.toString(personalBooksEntity);
            JSONObject personalBooksData = new JSONObject(personalBooksResponseString);
            JSONArray personalBooks = personalBooksData.getJSONArray("data");
            // 1.1. Traverse the knowledge base
            for (int i = 0; i < personalBooks.length(); i + + ) {
                JSONObject book = personalBooks.getJSONObject(i);
                String bookId = String.valueOf(book.get("id"));
                String bookName = (String) book.get("name");

                // Step 2: Get all articles under the knowledge base
                String bookURL = baseURL + "/docs/?book_id=" + bookId;
                HttpGet docRequest = new HttpGet(bookURL);
                docRequest.setHeader("Cookie", authToken);
                docRequest.setHeader("X-Csrf-Token", csrfToken);

                HttpResponse docResponse = httpClient.execute(docRequest);
                HttpEntity docEntity = docResponse.getEntity();
                String docResponseString = EntityUtils.toString(docEntity);
                JSONObject docData = new JSONObject(docResponseString);
                JSONArray docs = docData.getJSONArray("data");

                // Step 3: Traverse all articles in the knowledge base
                for (int j = 0; j < docs.length(); j + + ) {
                    JSONObject docEntry = docs.getJSONObject(j);
                    String docId = String.valueOf(docEntry.get("id"));

                    String exportURL = baseURL + "/docs/" + docId + "/export";
                    HttpPost exportRequest = new HttpPost(exportURL);
                    exportRequest.setHeader("Cookie", authToken);
                    exportRequest.setHeader("X-Csrf-Token", csrfToken);
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("type", "markdown");
                    jsonObject.put("force", 0);

                    // jsonObject.put("options", "{"latexType": 2,"enableAnchor": 0,"enableBreak": 0 }");
                    // latexType: 1. Export LaTeX formula images 2. Export LaTeX formulas as Markdown syntax
                    // enableAnchor: export the anchor point that keeps Yuque
                    // enableBreak: Export line breaks that keep Yuque
                    jsonObject.put("options", "{"latexType":2}");
                    StringEntity entity = new StringEntity(jsonObject.toString());
                    entity.setContentType("application/json");
                    exportRequest.setEntity(entity);

                    HttpResponse exportResponse = httpClient.execute(exportRequest);
                    HttpEntity exportEntity = exportResponse.getEntity();
                    String exportResponseString = EntityUtils.toString(exportEntity);
                    JSONObject exportData = new JSONObject(exportResponseString).getJSONObject("data");
                    String downloadURL = (String) exportData.get("url");

                    try {
                        // Step 3.1: Save the article locally
                        saveFileFromURL(downloadURL, bookName);
                    }
                    catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void saveFileFromURL(String fileURL, String bookName) {
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpGet httpGet = new HttpGet(fileURL);
            httpGet.setHeader("Cookie", authToken);
            httpGet.setHeader("X-Csrf-Token", csrfToken);

            HttpResponse response = httpClient.execute(httpGet);
            HttpEntity entity = response.getEntity();
            String fileName;
            if (response.getHeaders("Content-Disposition")[0].getElements()[0].getParameters().length == 2) {
                String file = response.getHeaders("Content-Disposition")[0].getElements()[0].getParameters()[1].getValue();
                fileName = URLDecoder.decode(file);
                fileName = fileName.substring(fileName.lastIndexOf("'"));
            }
            else
                fileName = response.getHeaders("Content-Disposition")[0].getElements()[0].getParameters()[0].getValue();
            if (entity != null) {
                try (InputStream inputStream = entity.getContent();
                     FileOutputStream outputStream = new FileOutputStream("./files/" + bookName + "/" + fileName)) {
                    byte[] buffer = new byte[1024];
                    int n;
                    while ((n = inputStream.read(buffer)) != -1) {
                        outputStream.write(buffer, 0, n);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

The knowledge points of the article match the official knowledge files, and you can further learn related knowledge. Network Skill TreeHomepageOverview 41965 people are learning the system