GASでPDFからテキストを抽出する方法 〜大学教授の戦い編〜
今どきの学生というのは、なかなか手の込んだやり方で手抜きをする。レポートの提出時に、わざわざ一度画像に変換し、それを貼り付けてPDFにして提出してくる輩が現れたのだ。それでコピペがバレないとでも思っているのだろうか。
Wordファイルからコピペを検出するツールが教授仲間で共有され、さほど手間をかけずにコピペレポートの判定が出来ることが学生内にも広まってきたことから、新たな工夫が生まれたのだろう、まるで「先生も頑張ってくださいね」とでも言わんばかりに、PDF形式で提出してくる。だが、私はそんな手段で簡単に引き下がる教授じゃない。GASを使って、PDFの中からテキストを引っ張り出し、その手抜き具合を暴く方法なんていくらでもある。今回は、そんな学生たちとの「戦い」を念頭に、PDFからテキストを抽出する方法を紹介する。
1. Google Drive APIを使ったOCRでテキスト抽出
状況説明
最も簡単な方法は、Google Drive APIのOCR機能を使うことだ。学生が「どうせ画像化したPDFなら先生も諦めるだろう」と思って提出した画像PDFからも、Drive APIの力でテキストはすべて抽出できる。彼らの「安易な策」はこれでほぼ通用しない。
実装方法
以下のコードでは、GoogleドライブにアップロードされたPDFをOCRで処理し、文字を抽出する。
function extractTextFromPdfWithOCR(fileId) {
const file = DriveApp.getFileById(fileId);
const resource = {
title: file.getName(),
mimeType: MimeType.GOOGLE_DOCS
};
const blob = file.getBlob();
const docFile = Drive.Files.create(resource, blob, {
ocr: true
});
const doc = DocumentApp.openById(docFile.id);
const text = doc.getBody().getText();
return text;
}
教授Aのコメント
「まったく、どうして学生たちはこんな姑息な手段に走るのかね…。これでコピー元が判明したら、いったいどんな顔をするのか見物だよ。」
メリット
- GoogleのOCR機能は優秀で、日本語を含めた多言語に対応している。つまり、どんな言語で書かれたPDFであっても、学生が隠している「共通のフレーズ」は見逃さない。
- 手書きレポートのスキャンでも、ある程度は認識してくれる。学生が「手書きならバレない」と思っても無駄だ。
デメリット
- いかに最近のOCR機能が優秀であっても、100%の精度が保証されるわけではない。宇宙のエントロピーは常に増大し、完全な正解へと至る道は、他の些末なミスを含んだ枝葉に埋もれてしまうのは世の常である。
2. 外部API(CloudConvert)を使った高度なテキスト抽出
状況説明
少し手強いPDFには、外部の力を借りる必要がある。特にCloudConvertのような外部APIは高精度で、レイアウトが複雑なレポートでもほぼ完璧にテキストを抽出してくれる。学生がどんな手段を使っても、コピペの痕跡を逃さない。
実装方法
以下のコードでは、CloudConvert APIを使ってPDFをテキストに変換している。
function extractTextFromPdfWithCloudConvert(apiKey, fileId) {
const file = DriveApp.getFileById(fileId);
const pdfBlob = file.getBlob();
const payload = {
file: pdfBlob,
inputformat: 'pdf',
outputformat: 'txt',
apikey: apiKey
};
const options = {
method: 'post',
payload: payload
};
const response = UrlFetchApp.fetch('https://api.cloudconvert.com/v2/convert', options);
const json = JSON.parse(response.getContentText());
return json.data.text;
}
教授Bのコメント
「PDFのレポートに特殊なレイアウトなんて使ったところで、CloudConvertの前では無駄なんだよな。テーブルだろうが、図表だろうが、一つ残らずテキストに変えてやるさ。」
メリット
- PDFの構造が複雑でも、精度が高い。これでどんなレポートでも、元ネタが手に取るように分かるだろう。
- OCR機能も同時に利用できるため、画像データも含めたテキスト抽出が可能だ。
デメリット
- 外部APIのため、使用量が増えるとコストがかかる。教授業も予算内でやりくりしなければならないのが悩みどころだ。
- APIリクエストが完了するまで少し時間がかかるため、大量のレポートを処理するには若干の忍耐が必要。
3. PDF.jsライブラリを使ったブラウザ内テキスト抽出
状況説明
少し厄介な学生の策として、彼らはPDFの「見た目」を利用し、フォントやレイアウトに凝った仕掛けを施し、OCRの目を欺くこうと企ててきた。こういったレポートからもテキストを抽出するため、クライアントサイドで動作するPDF.jsを使うという手段がある。学生が「この複雑なトリックならば解かれることはないだろう」と思っているところを、華麗に打ち破り、我々の顔のシワがただの年輪ではなく、大脳新皮質のシワの如く、これまでの研鑽により練り上げられたシナプスの複雑さを象徴する幾何学模様であることを証明するのだ。
実装方法
HTMLサービスを使って、ブラウザ内でPDF.jsを利用してPDFからテキストを抽出する。
function showPdfTextExtraction() {
var htmlOutput = HtmlService.createHtmlOutputFromFile('index');
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'PDF Text Extraction');
}
HTML側のコード(index.html)ではPDF.jsを使用。
<!DOCTYPE html>
<html>
<head>
<script src="https://mozilla.github.io/pdf.js/build/pdf.js"></script>
</head>
<body>
<input type="file" id="upload" />
<div id="output"></div>
<script>
document.getElementById('upload').addEventListener('change', function(event) {
var file = event.target.files[0];
var reader = new FileReader();
reader.onload = function() {
var typedarray = new Uint8Array(this.result);
pdfjsLib.getDocument(typedarray).promise.then(function(pdf) {
pdf.getPage(1).then(function(page) {
page.getTextContent().then(function(textContent) {
document.getElementById('output').innerText = textContent.items.map(item => item.str).join(' ');
});
});
});
};
reader.readAsArrayBuffer(file);
});
</script>
</body>
</html>
教授Cのコメント
「学生が偽装のために必死になるのは分かるさ。でも、PDF.jsで簡単に解析できるってことを知らないんだろうな。偽装に使った時間をレポートの中身に使えばいいということが分かるまでに、同じ過ちをどれだけ繰り返すつもりか知らんが、そこにこだわっても無駄ってことだ。」
メリット
- 高精度で、PDFのフォントやレイアウトに依存せずにテキストを抽出できる。
- レイアウトが保持されやすく、表や段組みなどの構造も比較的そのまま抽出できる。
デメリット
- クライアントサイドで実行するため、操作が少し手間。自動処理とは言えないが、学生との「頭脳戦」には十分役立つ。
- 大きなPDFを扱うと、ブラウザの処理速度が問題になることがある。
結論:抜け道を作らせないための準備を
学生はとにかく手を変え品を変え、教授を欺こうとするものだ。だが、こちらもそれに負けじと、GASと高度な技術を駆使して対策を取ることができる。
しかしまあ、そのおかげで、世の中に実在する変態的な構造をもったPDFからテキストを抽出する技術も向上してきたとも言える。そうやって無駄な時間を節約できるようになった今日という日に乾杯しようではないか。
コメント
コメントを投稿