إخراج البيانات من واجهة برمجة التطبيقات Data Export API إلى تنسيق CSV

ألكسندر لوكاس، فريق Google Analytics API – آب (أغسطس) 2010


مقدمة

توضّح لك هذه المقالة كيفية أخذ البيانات من أي طلب بحث يتم إجراؤه على واجهة برمجة التطبيقات لتصدير البيانات في "إحصاءات Google" وإخراج النتائج إلى تنسيق CSV شائع. وهذه من المهام الأكثر شيوعًا التي يُنفّذها المستخدمون باستخدام بيانات "إحصاءات Google" التي يتم استخراجها من واجهة برمجة التطبيقات Data Export API، لذا تُعدّ التشغيل الآلي لهذه العملية طريقة سهلة لتوفير الكثير من الوقت بشكل منتظم. علاوة على ذلك، بمجرد حصولك على بعض التعليمات البرمجية لطباعة مستندات CSV من الاستعلامات، ستتمكن من دمجه في مشروعات أكبر، مثل أدوات إنشاء التقارير التلقائية، ورسائل البريد، ودوال "التصدير" للوحات المعلومات المخصصة التي كتبتها.

قبل البدء

ستحصل على أقصى استفادة من هذه المقالة إذا كان لديك ما يلي:

نظرة عامّة حول البرنامج

ستقوم التعليمة البرمجية التي تتناولها هذه المقالة بما يلي:

  1. يمكنك تفعيل إمكانية اختيار "وقت التشغيل" ما إذا كان ستتم طباعة الرمز على وحدة التحكّم أو عملية بث ملف.
  2. يمكنك طباعة البيانات بتنسيق CSV بناءً على عنصر DataFeed كمَعلمة:
    • طباعة رؤوس الصفوف.
    • يمكنك طباعة صفوف البيانات، حيث يشكّل كل DataEntry صفًا واحدًا في الناتج الناتج.
    • نفِّذ كل قيمة من خلال طريقة تنقيح للحصول على نتائج آمنة بتنسيق CSV.
  3. اكتب طريقة "Sanitizer" التي تجعل جميع إدخالات CSV آمنة.
  4. يتم تزويدك بفئة Java يمكنها قبول أي طلب بحث في واجهة برمجة التطبيقات لتصدير البيانات وتحويله إلى ملف CSV.

الرجوع إلى أعلى الصفحة

السماح بساحات بث قابلة للضبط

أول شئ يجب فعله هو إعداد ساحة مشاركات قابلة للتهيئة لفصلك من أجل الطباعة. بهذه الطريقة، يمكن لأي رمز يستخدم فئتك أن يقرر ما إذا كان يجب أن يتم إخراج الإخراج من القاعدة أو إلى ملف مباشرة. ما عليك سوى إعداد طريقة getter/setter لكائن PrintStream. سيكون هذا هو الهدف من كل عمليات الطباعة التي تقوم بها الفصل.

private PrintStream printStream = System.out;

public PrintStream getPrintStream() {
  return printStream;
}

public void setPrintStream(PrintStream printStream) {
  this.printStream = printStream;
}

يُعد أيضًا ضبط المخرجات على ملف أمرًا سهلاً للغاية. يحتاج المستخدم إلى اسم الملف فقط لإنشاء كائن PrintStream لهذا الملف.

FileOutputStream fstream = new FileOutputStream(filename);
PrintStream stream = new PrintStream(fstream);
csvprinter.setPrintStream(stream);

الرجوع إلى أعلى الصفحة

التكرار من خلال البيانات

الصف الأول من ملف CSV هو صف أسماء الأعمدة. يمثل كل عمود سمة أو مقياس من خلاصة البيانات. لطباعة هذا الصف الأول، عليك إجراء ما يلي.

  1. الحصول على الإدخال الأول من الخلاصة
  2. كرِّر هذه الخطوة من خلال قائمة السمات باستخدام طريقة getDimensions لذلك الإدخال.
  3. اطبع اسم كل سمة باستخدام طريقة Dimension.getName() متبوعة بفاصلة.
  4. نفِّذ الإجراء نفسه مع المقاييس التي تستخدم طريقة getMetrics(). اطبع الفواصل بعد كل شيء باستثناء المقياس الأخير.

في ما يلي تنفيذ واحد لطريقة طباعة رؤوس الصفوف. لاحظ أن هذه التعليمة البرمجية لا تعرض سلسلة تمثل الصف الكامل: فإنها تطبع إلى تدفق إخراج أثناء معالجة القيم.

public void printRowHeaders(DataFeed feed) {
    if(feed.getEntries().size() == 0) {
      return;
    }

    DataEntry firstEntry = feed.getEntries().get(0);

    Iterator<Dimension> dimensions = firstEntry.getDimensions().iterator();
    while (dimensions.hasNext()) {
      printStream.print(sanitizeForCsv(dimensions.next().getName()));
      printStream.print(",");
    }

    Iterator<Metric> metrics = firstEntry.getMetrics().iterator();
    while (metrics.hasNext()) {
      printStream.print(sanitizeForCsv(metrics.next().getName()));
      if (metrics.hasNext()) {
        printStream.print(",");
      }
    }
    printStream.println();
  }

تتشابه طباعة "النص الأساسي" لملف CSV (كل شيء أسفل صف أسماء الأعمدة) إلى حد كبير. هناك اختلافان رئيسيان فقط. أولاً، إنه ليس فقط الإدخال الأول الذي يتم تقييمه. ويجب أن يتكرر الرمز بين كل الإدخالات في عنصر الخلاصة. ثانيًا، بدلاً من استخدام الطريقة getName() لسحب القيمة ليتم تصحيحها وطباعتها، استخدِم getValue() بدلاً من ذلك.

public void printBody(DataFeed feed) {
    if(feed.getEntries().size() == 0) {
      return;
    }

    for (DataEntry entry : feed.getEntries()) {
      printEntry(entry);
    }
  }

  public void printEntry(DataEntry entry) {
    Iterator<Dimension> dimensions = entry.getDimensions().iterator();
    while (dimensions.hasNext()) {
      printStream.print(sanitizeForCsv(dimensions.next().getValue()));
      printStream.print(",");
    }

    Iterator<Metric> metrics = entry.getMetrics().iterator();
    while (metrics.hasNext()) {
      printStream.print(sanitizeForCsv(metrics.next().getValue()));
      if (metrics.hasNext()) {
        printStream.print(",");
      }
    }
    printStream.println();
  }

تقسّم هذه التعليمة البرمجية خلاصتك إلى إدخالات، وتقسم إدخالاتك إلى قيم لتتم طباعتها في إخراج. ولكن كيف نجعل هذه القيم متوافقة مع ملفات CSV؟ ماذا لو كانت القيمة الموجودة في ملف "القيم المفصولة بفواصل" تحتوي على فاصلة؟ يجب تطهير هذه القيم.

الرجوع إلى أعلى الصفحة

كيفية تصحيح البيانات من أجل التوافق مع ملف CSV

CSV هو تنسيق مباشر. يمثل ملف CSV جدول بيانات، ويمثل كل سطر صفًا في هذا الجدول. يتم فصل القيم الموجودة في هذا الصف بفواصل. يعني السطر الجديد صفًا جديدًا من البيانات.

لسوء الحظ، يجعل هذا التنسيق المباشر من السهل بشكل مخادع التخلص من البيانات السيئة. ماذا لو كانت القيمة تحتوي على فاصلة؟ ماذا لو كانت إحدى القيم الخاصة بك تحتوي على فواصل أسطر داخلها؟ ماذا يجب أن يحدث مع المسافة بين الفواصل والقيم؟ يمكن حساب كل هذه المواقف باستخدام بعض القواعد البسيطة.

  • وإذا كانت السلسلة تحتوي على علامة اقتباس مزدوجة، عليك تخطيها بحرف اقتباس مزدوج ثانٍ.
  • إذا كانت هناك فاصلة في السلسلة، يجب لف السلسلة بأكملها بعلامتَي اقتباس مزدوجة (إلا إذا سبق لك ذلك).
  • إذا كان هناك فاصل أسطر في السلسلة، يجب لف السلسلة بأكملها بعلامتَي اقتباس مزدوجة (إلا إذا سبق لك ذلك).
  • إذا كانت السلسلة تبدأ أو تنتهي بأي نوع من المساحات البيضاء، عليك لف السلسلة بالكامل بين علامتَي اقتباس مزدوجتَين (إلا إذا سبق لك ذلك).

قد يكون من الصعب تصور الشكل الذي يجب أن تبدو عليه قيمك في هذه المرحلة، لذا إليك بعض الأمثلة. تذكر أن كل مثال يمثل قيمة واحدة، ويتم تخطيها على هذا النحو. من أجل الوضوح، ستظهر المسافات كحرف _.

قبل بعد
بدون تغيير بدون تغيير
علامة اقتباس مزدوجة " عشوائية علامة اقتباس مزدوجة "" عشوائية
فاصلة، مفصولة "فاصلة، مفصولة"
سطران
"سطران
"
_leading مفتاح وفاصلة "_leading space وفاصلة"
"اقتباس رئيسي، فاصلة """علامة اقتباس سابقة، فاصلة"
_space، وفاصلة
سطر ثوانٍ، وعلامة اقتباس مزدوجة"
" _space والفاصلة
السطر الثاني والاقتباس المزدوج"""

أسهل طريقة للتعامل مع كل هذه الشروط هي كتابة طريقة تعقيم. تدخل البيانات مشكوك فيها، وتخرج قيم CSV جيدة ونظيفة. إليك نموذج جيد لتنفيذ مثل هذه الطريقة بالضبط.

private String sanitizeForCsv(String cellData) {
  StringBuilder resultBuilder = new StringBuilder(cellData);

  // Look for doublequotes, escape as necessary.
  int lastIndex = 0;
  while (resultBuilder.indexOf("\"", lastIndex) >= 0) {
    int quoteIndex = resultBuilder.indexOf("\"", lastIndex);
    resultBuilder.replace(quoteIndex, quoteIndex + 1, "\"\"");
    lastIndex = quoteIndex + 2;
  }

  char firstChar = cellData.charAt(0);
  char lastChar = cellData.charAt(cellData.length() - 1);

  if (cellData.contains(",") || // Check for commas
      cellData.contains("\n") ||  // Check for line breaks
      Character.isWhitespace(firstChar) || // Check for leading whitespace.
      Character.isWhitespace(lastChar)) { // Check for trailing whitespace
      resultBuilder.insert(0, "\"").append("\""); // Wrap in doublequotes.
  }
    return resultBuilder.toString();
}

تبدأ الطريقة بالتحقق من علامات الاقتباس المزدوجة الحالية. وينبغي القيام بذلك قبل جميع عمليات التحقق الأخرى، لأنها تتضمن إحاطة سلسلة بعلامات اقتباس مزدوجة وسيكون من الصعب تحديد الفرق بين علامات الاقتباس المزدوجة التي كانت جزءًا من القيمة وعلامات الاقتباس المزدوجة التي تمت إضافتها سابقًا بهذه الطريقة. يسهل تجنبها - يجب مضاعفتها فقط. تصبح كل " علامة ""، تصبح كل "" علامة """"، وهكذا.

بمجرد استيفاء هذا الشرط، يمكن التحقق من جميع الشروط الأخرى (المسافة البيضاء الخالية والفواصل وفواصل الأسطر). إذا كان أي منها موجودًا، فما عليك سوى لف القيمة بين علامتَي اقتباس.

يُرجى العِلم أنّ ما سبق يستخدم كائن StringBuilder، ولا يؤدي مطلقًا إلى معالجة سلسلة أولية. ويرجع ذلك إلى أنّ السمة StringBuilder تتيح لك إمكانية معالجة السلسلة بدون إنشاء نُسخ مؤقتة في الذاكرة. نظرًا لأن السلاسل في Java غير قابلة للتغيير، فإن كل تعديل بسيط تجريه ستنشئ سلسلة جديدة تمامًا. عند التنقل عبر بيانات جداول البيانات، يمكن أن يضيف ذلك بسرعة كبيرة.

عدد الصفوف x القيم لكل صف x التغييرات في القيمة = إجمالي السلاسل الجديدة التي تم إنشاؤها
10,000 10 3 300000

الرجوع إلى أعلى الصفحة

الخطوات التالية

الآن بعد أن حصلت على مطرقة ذهبية، من الطبيعي أن تذهب لصيد الأظافر. إليك بعض الأفكار لمساعدتك على البدء.

  • ألقِ نظرة على نموذج رمز مصدر التطبيق الذي يستخدم هذه الفئة لطباعة ملف CSV استنادًا إلى نموذج طلب بحث. يأخذ اسم ملف الإخراج كمعلمة سطر الأوامر، ويطبع الاسم القياسي بشكل افتراضي. استخدمه كنقطة بداية وأنشئ شيئًا رائعًا!
  • CSV هو مجرد تنسيق واحد من العديد من التنسيقات الشائعة. ويمكنك تعديل الصف لإنشاء المحتوى بتنسيق مختلف، مثل TSV أو YAML أو JSON أو XML.
  • اكتب تطبيقًا ينشئ ملفات CSV ويرسلها بالبريد عند الانتهاء. إعداد تقارير شهرية مبرمَجة وسهلة
  • اكتب تطبيقًا يتيح لك إدخال طلبات البحث بشكل تفاعلي، للحصول على واجهة فعّالة للتنقّل في بياناتك.