GASでCSVを
スプレッドシートに取り込む方法
手作業のコピペで文字化けや列ズレに悩まされていませんか。Utilities.parseCsv(CSV文字列を二次元配列に変換するGASの標準メソッド)を使えば、CSVの取り込みをコードで安全に自動化できます。
Table of Contents
CSV取り込みでつまずくポイント
CSV(カンマ区切りのテキストファイル)の取り込みは単純そうに見えて、手作業や自作のコードでは次のような落とし穴があります。 GASの標準メソッドを使えば、この多くを避けられます。
セル内のカンマで列がズレる
住所や備考にカンマが混ざると、split(",")では列がずれてしまう
日本語が文字化けする
ExcelのCSVはShift_JISが多く、UTF-8として読むと文字が壊れる
改行を含むセルで行が崩れる
セル内改行があると、1行として扱えず取り込みが破綻する
毎回の手作業が地味に重い
定期的に届くCSVを人が貼り付けるのは手間もミスも増える
Utilities.parseCsvの基本
Utilities.parseCsv(文字列)は、CSV文字列を二次元配列(行の配列。各行がセルの配列)に変換します。 二重引用符で囲まれたカンマは1つのセルとして正しく扱われるため、split(",")の自作より安全です。
function parseCsvBasic() {
const csv =
'氏名,メール,備考\n' +
'山田太郎,taro@example.com,"東京都,渋谷区"\n' +
'佐藤花子,hanako@example.com,リピーター';
// 文字列を二次元配列に変換する
const data = Utilities.parseCsv(csv);
Logger.log(data.length); // 3(ヘッダー含む)
Logger.log(data[1][0]); // 山田太郎
Logger.log(data[1][2]); // 東京都,渋谷区(引用符内のカンマも1セル扱い)
}返ってくる値はすべて文字列です。数値として計算したい場合は、後でNumber()で変換します。
Driveに置いたCSVを取り込む
実務で多いのは、Googleドライブに保存されたCSVを取り込むパターンです。DriveApp.getFileByIdでファイルを取得し、Blob(ファイルの中身)を文字列にしてからparseCsvにかけ、setValuesでシートに一括書き込みします。
function importCsvFromDrive(fileId, sheetName) {
// Driveに置いたCSVファイルを読み込む
const blob = DriveApp.getFileById(fileId).getBlob();
const csv = blob.getDataAsString("UTF-8");
const data = Utilities.parseCsv(csv);
if (data.length === 0) return;
const sheet = SpreadsheetApp.getActive().getSheetByName(sheetName);
sheet.clearContents(); // 既存の内容を消してから丸ごと入れ替える
sheet
.getRange(1, 1, data.length, data[0].length)
.setValues(data);
Logger.log(data.length + "行を取り込みました");
}ファイルIDはDriveでファイルを開いたときのURLの/d/~/の部分です。上のコードはシートを丸ごと入れ替える方式で、マスタデータの更新に向いています。
文字化け(Shift_JIS)を防ぐ
取り込んだ日本語が「譁�喧縺�」のように化けるときは、文字コードの指定が原因です。 ExcelやWindowsの基幹システムが出力するCSVはShift_JIS(Windows-31J)のことが多く、UTF-8として読むと文字化けします。getDataAsStringに文字コードを渡して明示しましょう。
function importShiftJisCsv(fileId, sheetName) {
const blob = DriveApp.getFileById(fileId).getBlob();
// Excelや基幹システムが吐き出すCSVはShift_JISが多い。
// UTF-8として読むと日本語が文字化けするため文字コードを明示する。
const csv = blob.getDataAsString("Shift_JIS");
const data = Utilities.parseCsv(csv);
const sheet = SpreadsheetApp.getActive().getSheetByName(sheetName);
sheet.clearContents();
sheet.getRange(1, 1, data.length, data[0].length).setValues(data);
}どちらの文字コードか分からないときは、"UTF-8"と"Shift_JIS"の両方で読み、正しく表示される方を選びます。
URLから取得したCSVを取り込む
外部システムやオープンデータが公開するCSVは、UrlFetchApp.fetchでダウンロードしてそのまま取り込めます。取得に失敗したときのために、ステータスコードの確認を入れておくと安全です。
function importCsvFromUrl(url, sheetName) {
const res = UrlFetchApp.fetch(url, { muteHttpExceptions: true });
if (res.getResponseCode() !== 200) {
throw new Error("CSVの取得に失敗しました: " + res.getResponseCode());
}
// getContentTextに文字コードを渡すこともできる(既定はUTF-8)
const data = Utilities.parseCsv(res.getContentText("UTF-8"));
const sheet = SpreadsheetApp.getActive().getSheetByName(sheetName);
sheet.clearContents();
sheet.getRange(1, 1, data.length, data[0].length).setValues(data);
}重複を避けて差分だけ追記する
毎回シートを入れ替えるのではなく、既存データはそのままに新しい行だけを足したい場合は、 キー列(IDやメールなど一意になる列)で「取り込み済み」を判定してから追記します。Setで既出チェックすると高速です。
function appendNewRowsFromCsv(fileId, sheetName, keyColIndex) {
const csv = DriveApp.getFileById(fileId).getBlob().getDataAsString("UTF-8");
const rows = Utilities.parseCsv(csv).slice(1); // ヘッダー行を除く
const sheet = SpreadsheetApp.getActive().getSheetByName(sheetName);
// 既存シートのキー列を集めて「取り込み済み」の集合を作る
const existing = sheet.getDataRange().getValues().slice(1);
const seen = new Set(existing.map((r) => String(r[keyColIndex]).trim()));
const newRows = rows.filter(
(r) => !seen.has(String(r[keyColIndex]).trim())
);
if (newRows.length > 0) {
sheet
.getRange(sheet.getLastRow() + 1, 1, newRows.length, newRows[0].length)
.setValues(newRows);
}
Logger.log(newRows.length + "件を新規追加しました");
}同じCSVを2回取り込んでも二重登録されないため、定期実行と組み合わせやすいのが利点です。
タブ区切り(TSV)と定期実行
parseCsvは第2引数で区切り文字を指定できます。タブ区切り(TSV)やセミコロン区切りのファイルも同じ関数で扱えます。
function parseTsv() {
const tsv = "商品\t単価\nりんご\t120\nみかん\t80";
// 第2引数で区切り文字を指定できる(タブ・セミコロンなど1文字)
const data = Utilities.parseCsv(tsv, "\t");
Logger.log(data[1][0]); // りんご
Logger.log(data[1][1]); // 120
return data;
}最後に、時間主導トリガーで取り込みを自動化します。差分追記の関数と組み合わせれば、毎朝新しいデータだけを安全に反映できます。
function createDailyImportTrigger() {
ScriptApp.newTrigger("dailyImportJob")
.timeBased()
.everyDays(1)
.atHour(7)
.create();
}
function dailyImportJob() {
const FILE_ID = "取り込みたいCSVのファイルID";
// キー列(例: 0列目のID)で重複を避けながら差分だけ追記する
appendNewRowsFromCsv(FILE_ID, "取込データ", 0);
}まとめ
CSVの取り込みは、Utilities.parseCsvで二次元配列に変換し、setValuesで一括書き込みするのが基本形です。文字コードの明示で文字化けを防ぎ、キー列での重複判定と定期トリガーを加えれば、 手作業ゼロで安全なデータ連携が組めます。取り込みの逆方向(CSV出力)や取り込み後の重複整理も、同じ考え方で自動化できます。
よくある質問
split(",")はセルの中身にカンマや改行が含まれると壊れてしまいます。CSVは値にカンマや改行を含めるとき二重引用符("...")で囲む決まりがあり、Utilities.parseCsvはこの引用符を正しく解釈して二次元配列に変換します。実務のCSVでは住所や備考にカンマが混ざることが多いので、自作のsplitではなくparseCsvを使うのが安全です。
ExcelやWindowsで保存したCSVはShift_JIS(Windows-31J)のことが多く、UTF-8として読むと文字化けします。Blobを文字列にするときにgetDataAsString("Shift_JIS")のように文字コードを明示すると直ります。逆にUTF-8のファイルはgetDataAsString("UTF-8")、迷ったら両方試して正しく表示される方を選びます。
parseCsvの結果はすべて文字列ですが、setValuesで書き込むとスプレッドシート側が「012」を数値の12、「2026-07-20」を日付として自動変換します。電話番号や郵便番号など文字列のまま残したい列は、事前にsetNumberFormat("@")で書式を「書式なしテキスト」にしておくと変換を防げます。
読み込めます。Utilities.parseCsvは第2引数に区切り文字を指定できるので、Utilities.parseCsv(text, "\t")とすればタブ区切り、セミコロン区切りなら";"を渡します。区切り文字は1文字だけ指定できます。
数万行を超えるCSVでは、6分の実行時間制限に達したり、setValuesで一度に書き込むデータ量が大きすぎてエラーになることがあります。行を数千件ずつに区切って複数回に分けて書き込む、処理位置をPropertiesServiceに保存して分割実行するなどの対策が有効です。
できます。時間主導トリガー(ScriptApp.newTrigger)で毎朝決まった時刻に取り込み関数を実行すれば、Driveの決まったフォルダに置かれたCSVや、外部システムが公開するCSV URLを自動で反映できます。重複を避ける追記処理と組み合わせると、差分だけを安全に取り込めます。
GAS開発・業務Webシステムを
相談する。
CSV取り込み以外にも、基幹システムとのデータ連携・帳票出力・Gmail自動化など、日々の業務を自動化するGAS開発をご相談いただけます。