Blogger 自動發文

需求很簡單,希望餵個標題跟內容,就自動產生文章貼到 Blogger 上,但弄的跌跌撞撞的,紀錄一下,留給麵包屑給未來的自己和有需要的人。

先來看一下官方作法 - 新增 Post 的做法,可以透過 Restful Web API 或是官方提供的 Java Library 來完成。理想上是這樣,看起來很間單,那為什麼我會跌的狗吃屎?

Restful Web API 的方式,參考指南這一篇,才發現 HTTP Header 還要填入 Authorization: /* OAuth 2.0 token here */,基本上就還是要透過 OAuth 2.0 的方式得到 token 才走的下去。那換成官方提供的 Java Library,反正連 Sample Code 都有了應該很簡單,貼上去才發現範例中的 OAuth2Native 根本沒有,需要自己實作。

做到這邊我心已死,成功之路沒有捷徑,只好去翻這兩份文件來看:

大概的問題就是想辦法通過 OAuth 2.0 取得 Token,再來拿這個 Token,看是要用 Restful Web API 還是 Java Library 來新增 Post 都可。步驟如下:
  1. 到 https://console.developers.google.com/ 下的 API 和驗證>API 把 Blogger API 啟用。
  2. 到 https://console.developers.google.com/ 下的 API 和驗證>同意畫面 把該填的資訊填一填。
  3. 到 https://console.developers.google.com/ 下的 API 和驗證>憑證>OAuth 建立用戶端 ID,類型選取已安裝的應用程式(我的 APP 是一個桌面執行程式)。
  4. 此時會得到用戶端 ID,用戶端密碼。
  5. 修改官方範例碼如下:
// The BlogId of a test blog.
String TEST_BLOG_ID = "8070105920543249955";
// Configure the Java API Client for Installed Native App
HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
JsonFactory JSON_FACTORY = new JacksonFactory();
// set up authorization code flow
AuthorizationCodeFlow flow = new AuthorizationCodeFlow.Builder(
BearerToken.authorizationHeaderAccessMethod(),
HTTP_TRANSPORT,
JSON_FACTORY,
new GenericUrl("https://accounts.google.com/o/oauth2/token"),
new ClientParametersAuthentication("用戶端ID", "用戶端密碼"),
"用戶端ID",
"https://accounts.google.com/o/oauth2/auth")
.setScopes(Arrays.asList(BloggerScopes.BLOGGER))
.setDataStoreFactory(MemoryDataStoreFactory.getDefaultInstance())
.build();
// authorize
LocalServerReceiver receiver = new LocalServerReceiver.Builder()
.setHost("127.0.0.1")
.setPort(8080).build();
Credential credential = new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");
// Construct the Blogger API access facade object.
Blogger blogger = Blogger.builder(HTTP_TRANSPORT, JSON_FACTORY)
.setApplicationName("Blogger-PostsInsert-Snippet/1.0")
.setHttpRequestInitializer(credential).build();
// Construct a post to insert
Post content = new Post();
content.setTitle("A test post");
content.setContent("With HTML content");
// The request action.
Insert postsInsertAction = blogger.posts().insert(TEST_BLOG_ID, content);
// Restrict the result content to just the data we need.
postsInsertAction.setFields("author/displayName,content,published,title,url");
// This step sends the request to the server.
Post post = postsInsertAction.execute();
// Now we can navigate the response.
System.out.println("Title: " + post.getTitle());
System.out.println("Author: " + post.getAuthor().getDisplayName());
System.out.println("Published: " + post.getPublished());
System.out.println("URL: " + post.getUrl());
System.out.println("Content: " + post.getContent());
當執行這段範例碼時,在 Po 文之前,瀏覽器會自動打開,告知使用者有應用程式嘗試要存取你的 Blogger ,使用者同意之後就會自動 Po 文。

但實際上這段程式碼還是需要人為介入(在瀏覽器上同意),其實在 https://console.developers.google.com/ 下的 API 和驗證>憑證>OAuth 建立用戶端 ID,有一個類型叫做服務帳戶(Service Account)可以自動通過 OAuth 認證,但因為 Blogger 平台不支援用服務帳戶來發文,所以我們會得到 HTTP 403 授權失敗的錯誤。

PS: Google 關於通過 OAuth 的範例程式碼