Alexander Lucas, zespół Google Analytics API – sierpień 2010 r.
Wstęp
Z tego artykułu dowiesz się, jak pobrać dane z dowolnego zapytania wysłanego do interfejsu Google Analytics Data Export API i uzyskać wyniki w popularnym formacie CSV. Jest to jedno z najczęstszych zadań związanych z danymi Analytics pobranymi z interfejsu Data Export API, dlatego automatyzacja tego procesu to łatwy sposób na regularne zaoszczędzenie mnóstwo czasu. Mając już kod do drukowania dokumentów CSV z zapytań, możesz zintegrować go z większymi projektami, takimi jak automatyczne generatory raportów, wiadomości pocztowe i funkcje eksportowania napisanych przez siebie niestandardowych paneli.
Zanim rozpoczniesz
Aby w pełni wykorzystać możliwości tego artykułu, musisz mieć:
- Praktyczna znajomość języka Java.
- praktycznej wiedzy z zakresu Google Analytics, w tym znajomości wymiarów i danych;
- Dostęp do aktywnego konta Google Analytics z rzeczywistymi danymi.
- Zapoznanie się z wprowadzeniem do interfejsu API eksportowania danych w języku Java W tym artykule zakładamy, że wiesz już wszystko, co jest omówione w tym przewodniku.
- Lokalna kopia pełnego kodu źródłowego, który można pobrać pod adresem AnalyticsCvsPrinter.java. Przykładową aplikację wykorzystującą ten kod znajdziesz w AnalyticsCsvDemo.java.
Omówienie programu
Kod omówiony w tym artykule:
- Włącz określanie w czasie działania, czy kod ma być drukowany w konsoli czy w strumieniu plików.
- Mając obiekt
DataFeed
jako parametr, wydrukuj dane w formacie CSV:- Drukuj nagłówki wierszy.
- Drukuj wiersze danych, w których każdy element
DataEntry
tworzy 1 wiersz wynikowych danych wyjściowych. - Uruchom każdą wartość za pomocą metody oczyszczania, aby uzyskać dane wyjściowe bezpieczne w formacie CSV.
- Utwórz metodę „Sanitizer”, która sprawi, że wszystkie wejściowe dane CSV będą bezpieczne.
- Udostępnij klasę Javy, która może przekształcić dowolne zapytanie interfejsu API eksportu danych i przekształcić je w plik CSV.
Zezwalaj na konfigurowalne strumienie wyjściowe
Najpierw musisz skonfigurować konfigurowalny strumień danych wyjściowych, w którym Twoja klasa będzie drukować. Dzięki temu każdy kod korzystający z klasy decyduje, czy dane wyjściowe powinny zostać udostępnione w standardzie czy bezpośrednio do pliku. Wystarczy skonfigurować metodę getter/setter dla obiektu PrintStream
. Będzie to cel wszystkich drukowania
wykonywanych przez klasę.
private PrintStream printStream = System.out; public PrintStream getPrintStream() { return printStream; } public void setPrintStream(PrintStream printStream) { this.printStream = printStream; }
Ustawienie danych wyjściowych na plik również jest bardzo łatwe. Wystarczy nazwa pliku, aby utworzyć dla niego obiekt PrintStream
.
FileOutputStream fstream = new FileOutputStream(filename); PrintStream stream = new PrintStream(fstream); csvprinter.setPrintStream(stream);
Przechodzenie między danymi
Pierwszy wiersz pliku CSV zawiera nazwy kolumn. Każda kolumna reprezentuje wymiar lub dane z pliku danych, więc aby wydrukować pierwszy wiersz, wykonaj te czynności.
- Pobierz pierwszy wpis z kanału.
- Przejrzyj listę wymiarów przy użyciu metody
getDimensions
tego wpisu. - Wydrukuj nazwę każdego wymiaru za pomocą metody
Dimension.getName()
, po których następuje przecinek. - To samo zrób z danymi, korzystając z metody
getMetrics()
. Drukuj przecinki oprócz ostatniego wskaźnika.
Oto jedna z implementacji metody drukowania nagłówków wierszy. Pamiętaj, że ten kod nie zwraca ciągu znaków reprezentującego cały wiersz. Jest drukowany do strumienia danych wyjściowych podczas przetwarzania wartości.
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(); }
Drukowanie „treści” pliku CSV (wszystkiego, co znajduje się pod wierszem nazw kolumn) jest bardzo podobne. Występują tylko 2 główne różnice. Po pierwsze, nie jest to
tylko pierwsza ocena poddana ocenie. Kod musi przejść przez wszystkie
wpisy w obiekcie pliku danych. Po drugie, zamiast metody getName()
do pobierania wartości przeznaczonej do oczyszczenia i wydrukowania użyj metody 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(); }
Ten kod dzieli plik danych na wpisy, a wpisy na wartości są wydrukowane na wyjściu. Jak jednak dostosować je do formatu CSV? Co zrobić, jeśli wartość w pliku z wartościami rozdzielonymi przecinkami zawiera przecinek? Wartości te muszą zostać oczyszczone.
Jak Sanityzacja danych w celu zapewnienia zgodności z CSV
Prostym formatem jest plik CSV. Plik CSV odpowiada tabeli danych, a każdy wiersz odpowiada jej wierszowi. Wartości w tym wierszu są rozdzielone przecinkami. Nowy wiersz oznacza nowy wiersz danych.
Ten prosty format sprawia, że łatwo pozbyć się niekorzystnych danych. Co zrobić, jeśli wartość zawiera przecinek? Co zrobić, jeśli jedna z wartości zawiera podziały wiersza? Co powinno się wydarzyć między przecinkami a wartościami? W każdym z tych przypadków można uwzględnić kilka prostych reguł.
- Jeśli ciąg zawiera znak cudzysłowu, zastąp go drugim znakiem cudzysłowu.
- Jeśli ciąg zawiera przecinek, umieść go w cudzysłowie prostym (chyba że już go masz).
- Jeśli w ciągu znaków jest podział wiersza, umieść cały ciąg w cudzysłowie prostym (chyba że już go masz).
- Jeśli ciąg znaków na początku lub na końcu jest spacją, umieść cały ciąg w cudzysłowie prostym (chyba że już go masz).
Wyobrażenie sobie, jak w tym momencie powinny wyglądać Twoje wartości, może być nieco trudne, dlatego podajemy kilka przykładów. Pamiętaj, że każdy przykład reprezentuje pojedynczą wartość, która jako taka ma znaczenie zmiany znaczenia. Aby uniknąć wątpliwości: spacje będą wyświetlane jako znak _.
Przed | Po |
---|---|
bez zmian | bez zmian |
losowy " podwójny cudzysłów | losowy cudzysłów podwójny "" |
oddzielone przecinkami | "rozdzielone przecinkami" |
Dwie wiersze |
„Dwie wiersze” |
_leading space i przecinek | "_najpierwsza spacja, przecinek" |
"cytat początkowy, przecinek | """cytat początkowy, przecinek" |
_space, przecinek drugi i cudzysłów podwójny" |
"_space, przecinek drugi i cudzysłów podwójny""" |
Najłatwiejszym sposobem radzenia sobie ze wszystkimi tymi warunkami jest napisanie metody oczyszczania. Wprowadzane są budzące wątpliwości dane i otrzymywane są prawidłowe, przejrzyste wartości w formacie CSV. Oto przykładowa implementacja takiej metody.
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(); }
Metoda rozpoczyna się od sprawdzenia, czy występują już podwójne cudzysłowy. Należy to zrobić przed wszystkimi innymi testami, ponieważ trzeba dodać ciąg znaków podwójnym cudzysłowem. Określanie różnic między cudzysłowami podwójnymi, które wchodzą w skład wartości, a cudzysłowami dodanymi wcześniej przy użyciu tej metody, byłoby uciążliwe. Łatwo uciekać od tych danych – wystarczy je podwoić. Każdy element " staje się "", każdy "" zmienia się w """" itd.
Gdy ten warunek zostanie spełniony, możesz sprawdzać wszystkie pozostałe warunki (nieusunięte odstępy, przecinki i znaki podziału wierszy). Jeśli występuje któraś z nich, po prostu umieść wartość w cudzysłowie.
Zwróć uwagę, że powyższe polecenie używa obiektu StringBuilder
i nigdy nie modyfikuje bezpośrednio nieprzetworzonego ciągu znaków. Dzieje się tak, ponieważ obiekt StringBuilder
umożliwia swobodną obsługę ciągu bez tworzenia tymczasowych kopii w pamięci. Ciągi w Javie są niezmienne, więc każda
drobna zmiana powoduje utworzenie zupełnie nowego ciągu. Gdy przeglądasz dane w arkuszu kalkulacyjnym, szybko sumuje się z nich.
Liczba wierszy | x wartości na wiersz | x Zmiany wartości | = Łączna liczba utworzonych nowych ciągów znaków |
---|---|---|---|
10 000 | 10 | 3 | 300 000 |
Co dalej?
Teraz, gdy dostajesz złoty młotek, poszukiwanie paznokci to zupełnie normalne. Oto kilka pomysłów na początek.
- Przyjrzyj się przykładowemu kodowi źródłowemu aplikacji, który korzysta z tej klasy do wydrukowania pliku CSV na podstawie przykładowego zapytania. Wykorzystuje on nazwę pliku wyjściowego jako parametr wiersza poleceń i domyślnie drukuje w standardzie. Potraktuj go jako punkt wyjścia i stwórz coś niesamowitego.
- CSV to tylko jeden z wielu popularnych formatów. Dostosuj klasę do innego formatu, np. TSV, YAML, JSON lub XML.
- Napisz aplikację, która będzie generować pliki CSV i wysyłać je e-mailem po ich zakończeniu. Łatwe automatyczne raporty miesięczne
- Napisz aplikację, która umożliwia interaktywne wprowadzanie zapytań, aby utworzyć zaawansowany interfejs do przeglądania danych.