Google Driveで、Drive上のPDFや画像ファイルを「Google Documentで開く」すると、元ファイルがGoogle Documentに変換され、そこからテキストだけを抽出できるようになります。
Drive APIでも Files: create
https://developers.google.com/drive/api/v3/reference/files/create の機能を使ってファイルをGoogle Documentとしてアップロードすることで、同様のことができます。
当然Drive上のファイルをAPIからGoogle Documentに変換することもできると思ってAPIを眺めたら、たぶん Files: export
https://developers.google.com/drive/api/v3/reference/files/export に最初は目が行きますが、これだと 元ファイルがGoogle Documentである
という条件があり、目的の画像やPDFのOCRではなさそうです。Files: get
を使うのか?とも思いますが、これは単純にダウンロードしてしまうものなので、Files:Export
と同じことになりそうです。
でもできないことはないだろうと探したところ Files: Copy
https://developers.google.com/drive/api/v3/reference/files/copy を使い、コピー先のファイルの mimetype
をapplication/vnd.google-apps.document
に指定することで、Drive上だけでOCR(Google Documentへの変換)が可能でした。
下記はServiceAccountでjsonのキーファイル(serviceaccount.jsonで保存)を保存して、Drive上のファイルをGoogle Documentに変換してテキストを抜きだすサンプルです。
package ocr
import (
"io/ioutil"
"log"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"google.golang.org/api/docs/v1"
"google.golang.org/api/drive/v3"
)
func copyFileAsGoogleDocument(fileID string) (*drive.File, error) {
driveService, err := newDriveService()
if err != nil {
return nil, err
}
dst := &drive.File{
Name: fileID + "_copied_document",
MimeType: "application/vnd.google-apps.document",
}
return driveService.Files.Copy(fileID, dst).Do()
}
func extractText(documentID string) (string, error) {
docsService, err := newDocsService()
if err != nil {
return "", err
}
document, err := docsService.Documents.Get(documentID).
Fields("body/content/paragraph/elements/textRun/content", "title").
Do()
if err != nil {
return "", err
}
text := ""
for _, content := range document.Body.Content {
if content.Paragraph == nil || content.Paragraph.Elements == nil {
continue
}
for _, paragraphElement := range content.Paragraph.Elements {
if paragraphElement.TextRun == nil {
continue
}
text = text + paragraphElement.TextRun.Content
}
}
return text, nil
}
func deleteFile(fileID string) error {
driveService, err := newDriveService()
if err != nil {
return err
}
return driveService.Files.Delete(fileID).Do()
}
func newDriveService() (*drive.Service, error) {
conf, err := google.JWTConfigFromJSON(jwt, drive.DriveScope)
if err != nil {
return nil, err
}
return drive.New(conf.Client(oauth2.NoContext))
}
func newDocsService() (*docs.Service, error) {
conf, err := google.JWTConfigFromJSON(jwt, docs.DocumentsScope)
if err != nil {
return nil, err
}
return docs.New(conf.Client(oauth2.NoContext))
}
var jwt []byte
func init() {
bytes, err := ioutil.ReadFile("serviceaccount.json")
if err != nil {
log.Fatalf("%#v", err)
}
jwt = bytes
}
package ocr
import "testing"
func TestOCR(t *testing.T) {
fileID := "対象のファイルID"
copy, err := copyFileAsGoogleDocument(fileID)
if err != nil {
t.Fatalf("%v", err)
}
defer deleteFile(copy.Id)
text, err := extractText(copy.Id)
t.Logf("%v", text)
}