You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Google Apps Script中通过URL获取图片EXIF信息?无需存Drive方案

无需保存到Google Drive提取JPEG图片EXIF的解决方案

首先,你之前遇到的ReferenceError: Drive is not defined错误,是因为你使用了Google Drive的高级API服务,但没在脚本编辑器里启用它。不过既然你不想把图片存到Drive,咱们直接换个思路——直接解析图片的二进制数据提取EXIF,或者用本地工具批量处理,下面给你两个可行方案:

方案一:在Google Apps Script中直接解析(无需存Drive)

这个方案不用把图片存到Drive,直接通过UrlFetch获取图片的二进制数据,手动解析JPEG里的EXIF信息,最后生成Google表格:

function extractExifFromUrl(imageUrl) {
  // 获取图片的二进制数据
  const response = UrlFetchApp.fetch(imageUrl);
  const bytes = response.getBlob().getBytes();
  
  // 核心解析函数:从二进制数据中提取EXIF
  function getExifData(rawBytes) {
    const exifData = {};
    // 先验证是不是JPEG格式
    if (rawBytes[0] !== 0xFF || rawBytes[1] !== 0xD8) return null;

    let offset = 2;
    const totalLength = rawBytes.length;

    // 遍历JPEG的APP段,找到存储EXIF的APP1段
    while (offset < totalLength) {
      if (rawBytes[offset] === 0xFF && rawBytes[offset + 1] === 0xE1) {
        const appSegmentLength = (rawBytes[offset + 2] << 8) | rawBytes[offset + 3];
        const exifHeader = Utilities.newBlob(rawBytes.slice(offset + 4, offset + 10)).getDataAsString();
        
        if (exifHeader === "Exif\0\0") {
          // 解析TIFF头和IFD标签
          let tiffStart = offset + 10;
          const endianType = rawBytes[tiffStart] === 0x49 ? "LE" : "BE";
          const ifdOffset = tiffStart + 8;
          const tagCount = endianType === "BE" 
            ? (rawBytes[ifdOffset] << 8) | rawBytes[ifdOffset + 1] 
            : (rawBytes[ifdOffset + 1] << 8) | rawBytes[ifdOffset];

          // 遍历每个EXIF标签,提取常用字段
          for (let i = 0; i < tagCount; i++) {
            const tagPos = ifdOffset + 2 + i * 12;
            const tagId = endianType === "BE" 
              ? (rawBytes[tagPos] << 8) | rawBytes[tagPos + 1] 
              : (rawBytes[tagPos + 1] << 8) | rawBytes[tagPos];
            const tagType = endianType === "BE" 
              ? (rawBytes[tagPos + 2] << 8) | rawBytes[tagPos + 3] 
              : (rawBytes[tagPos + 3] << 8) | rawBytes[tagPos + 2];
            const valueCount = endianType === "BE" 
              ? ((rawBytes[tagPos + 4] << 24) | (rawBytes[tagPos + 5] << 16) | (rawBytes[tagPos + 6] << 8) | rawBytes[tagPos + 7])
              : ((rawBytes[tagPos + 7] << 24) | (rawBytes[tagPos + 6] << 16) | (rawBytes[tagPos + 5] << 8) | rawBytes[tagPos + 4]);

            let tagValue;
            // 处理ASCII字符串类型的标签(比如相机品牌、型号)
            if (tagType === 2) {
              const valueStart = endianType === "BE" 
                ? ((rawBytes[tagPos + 8] << 24) | (rawBytes[tagPos + 9] << 16) | (rawBytes[tagPos + 10] << 8) | rawBytes[tagPos + 11])
                : ((rawBytes[tagPos + 11] << 24) | (rawBytes[tagPos + 10] << 16) | (rawBytes[tagPos + 9] << 8) | rawBytes[tagPos + 8]);
              tagValue = Utilities.newBlob(rawBytes.slice(valueStart, valueStart + valueCount - 1)).getDataAsString();
            }
            // 处理SHORT类型的标签(比如光圈值)
            else if (tagType === 3 && valueCount === 1) {
              tagValue = endianType === "BE" 
                ? (rawBytes[tagPos + 8] << 8) | rawBytes[tagPos + 9] 
                : (rawBytes[tagPos + 9] << 8) | rawBytes[tagPos + 8];
            }

            // 映射标签ID到易懂的名称
            switch(tagId) {
              case 0x010F: exifData["CameraMake"] = tagValue; break;
              case 0x0110: exifData["CameraModel"] = tagValue; break;
              case 0x0132: exifData["DateTimeOriginal"] = tagValue; break;
              case 0x829A: exifData["ExposureTime"] = tagValue; break;
              case 0x829D: exifData["FNumber"] = tagValue; break;
            }
          }
          return exifData;
        }
      }
      // 移动到下一个APP段
      const segmentLength = (rawBytes[offset + 2] << 8) | rawBytes[offset + 3];
      offset += segmentLength + 2;
    }
    return null;
  }

  return getExifData(bytes);
}

// 生成EXIF表格的主函数
function generateExifSpreadsheet() {
  // 替换成你的亚马逊S3图片URL列表
  const imageUrls = [
    "https://your-s3-image-url-1.jpg",
    "https://your-s3-image-url-2.jpg"
    // 可以添加更多URL
  ];

  // 表格表头
  const tableHeaders = ["图片URL", "相机品牌", "相机型号", "拍摄日期", "曝光时间", "光圈值"];
  const tableRows = [tableHeaders];

  // 批量处理每个图片URL
  imageUrls.forEach(url => {
    const exifInfo = extractExifFromUrl(url);
    tableRows.push([
      url,
      exifInfo?.CameraMake || "无",
      exifInfo?.CameraModel || "无",
      exifInfo?.DateTimeOriginal || "无",
      exifInfo?.ExposureTime ? `${exifInfo.ExposureTime}s` : "无",
      exifInfo?.FNumber ? `f/${exifInfo.FNumber}` : "无"
    ]);
  });

  // 创建新的Google表格并写入数据
  const newSheet = SpreadsheetApp.create("图片EXIF信息汇总表").getActiveSheet();
  newSheet.getRange(1, 1, tableRows.length, tableRows[0].length).setValues(tableRows);
  
  // 打印表格链接,方便你查看
  Logger.log("EXIF表格已生成,链接:" + SpreadsheetApp.getActiveSpreadsheet().getUrl());
}

使用步骤:

  1. 打开Google Apps Script编辑器(https://script.google.com)
  2. 新建一个脚本项目,把上面的代码粘贴进去
  3. imageUrls数组替换成你的亚马逊S3图片URL列表
  4. 点击运行generateExifSpreadsheet,第一次运行需要授权脚本访问网络和表格服务

方案二:用Python本地批量处理(更灵活)

如果你有Python环境,这个方案会更简单——用exifread库解析图片EXIF,pandas生成Excel表格,完全不需要依赖Google服务:

import requests
import exifread
import pandas as pd

# 替换成你的图片URL列表
image_urls = [
    "https://your-s3-image-url-1.jpg",
    "https://your-s3-image-url-2.jpg"
]

exif_records = []

# 批量处理每个URL
for url in image_urls:
    try:
        # 流式请求图片,避免下载整个文件
        response = requests.get(url, stream=True, timeout=10)
        response.raise_for_status()
        
        # 解析EXIF信息
        exif_tags = exifread.process_file(response.raw, details=False)
        
        # 整理需要的字段
        record = {
            "图片URL": url,
            "相机品牌": str(exif_tags.get("Image Make", "无")),
            "相机型号": str(exif_tags.get("Image Model", "无")),
            "拍摄日期": str(exif_tags.get("EXIF DateTimeOriginal", "无")),
            "曝光时间": str(exif_tags.get("EXIF ExposureTime", "无")),
            "光圈值": str(exif_tags.get("EXIF FNumber", "无"))
        }
        exif_records.append(record)
    except Exception as e:
        print(f"处理URL {url} 出错:{str(e)}")
        exif_records.append({"图片URL": url, "相机品牌": "解析失败", "相机型号": "解析失败", "拍摄日期": "解析失败", "曝光时间": "解析失败", "光圈值": "解析失败"})

# 生成Excel表格
df = pd.DataFrame(exif_records)
df.to_excel("图片EXIF信息表.xlsx", index=False)
print("EXIF表格已生成,保存为:图片EXIF信息表.xlsx")

使用步骤:

  1. 安装依赖库:在命令行执行pip install requests exifread pandas openpyxl
  2. 把代码里的image_urls替换成你的URL列表
  3. 运行脚本,会在当前目录生成Excel表格

内容的提问来源于stack exchange,提问作者Андрей Малахов

火山引擎 最新活动