Google oferuje Google Translation API ze strukturą kosztów opartą na użytkowaniu w ramach Google Cloud. Istnieje również nieudokumentowane API, którego można używać bez klucza , ale które odmawia działania po zaledwie kilku żądaniach. Korzystając z funkcji tłumaczenia stron internetowych w Google Chrome, można zauważyć, że strony mogą być tłumaczone w bardzo dobrej jakości bez zauważalnych ograniczeń.
Podobno zaawansowany model nmt jest już tutaj używany. Ale którego interfejsu API Google Chrome używa wewnętrznie do tłumaczenia treści i czy można również bezpośrednio adresować ten interfejs - nawet po stronie serwera? Do analizy ruchu sieciowego zalecane są narzędzia takie jak Wireshark lub Telerik Fiddler , które mogą również analizować ruch zaszyfrowany. Ale Chrome nawet bezpłatnie dostarcza żądania tłumaczenia strony, które wysyła: można je łatwo wyświetlić za pomocą narzędzi Chrome DevTools:
Jeśli wykonujesz tłumaczenie, następnie przechwyć kluczowe żądanie POST do https://translate.googleapis.com za pomocą „Kopiuj> Kopiuj jako cURL (bash)” i wykonaj je w narzędziu takim jak np. Postman , możesz bez problemu ponownie wysłać żądanie:
Znaczenie parametrów adresu URL jest również w dużej mierze oczywiste:
Klucz | Przykładowa wartość | Znaczenie |
anno | 3 | Tryb adnotacji (wpływa na format zwrotu) |
klient | te_lib | Informacje o kliencie (różne, wartość to „aplikacja internetowa” za pośrednictwem interfejsu internetowego Tłumacza Google; ma wpływ na format zwrotów i ograniczenie szybkości) |
format | html | Format ciągu (ważny przy tłumaczeniu tagów HTML) |
v | 1.0 | Numer wersji Tłumacza Google |
klucz | AIzaSyBOti4mM-6x9WDnZIjIeyEU21OpBXqWBgw | Klucz API (patrz poniżej) |
logld | vTE_20200210_00 | Wersja protokołu |
sl | de | Język źródłowy |
tl | en | Język docelowy |
sp | nmt | Model ML |
tc | 1 | nieznany |
sr | 1 | nieznany |
tk | 709408.812158 | Token (patrz poniżej) |
Moda | 1 | nieznany |
Niektóre nagłówki żądań również są ustawione - ale najczęściej można je zignorować. Po ręcznym odznaczeniu wszystkich nagłówków, w tym tych pochodzących z klienta użytkownika , podczas wprowadzania znaków specjalnych (tutaj podczas tłumaczenia „ Hello World ”) zostaje wykryty problem z kodowaniem:
Jeśli ponownie aktywujesz klienta użytkownika (to zazwyczaj nie powoduje żadnej szkody), API dostarcza zakodowane znaki UTF-8:
Czy już tam jesteśmy i czy mamy wszystkie informacje potrzebne do korzystania z tego interfejsu API poza Google Chrome? Jeśli zmienisz ciąg do przetłumaczenia (pole danych q żądania POST) z, na przykład „Hello world” na „Hello world ! „, Otrzymujemy komunikat o błędzie:
Teraz tłumaczymy ten zmodyfikowany ponownie w Google Chrome za pomocą funkcji tłumaczenia witryny i stwierdzamy, że oprócz parametru q zmienił się również parametr tk (wszystkie inne parametry pozostały takie same):
Oczywiście jest to token zależny od łańcucha, którego strukturę nie jest łatwo dostrzec. Po uruchomieniu tłumaczenia strony ładowane są następujące pliki:
- 1 plik CSS: translateelement.css
- 4 grafiki: translate_24dp.png (2x), gen204 (2x)
- 2 pliki JS: main_de.js, element_main.js
Te dwa pliki JavaScript są zaciemnione i zminimalizowane. Narzędzia takie jak JS Nice i de4js pomagają nam teraz uczynić te pliki bardziej czytelnymi. Aby zdebugować je na żywo, zalecamy rozszerzenie Chrome Requestly, które tuneluje zdalne pliki lokalnie w locie:
Teraz możemy debugować kod (najpierw CORS musi być aktywowany na serwerze lokalnym). Wydaje się, że odpowiednia sekcja kodu do generowania tokenu jest ukryta w pliku element_main.js w tej sekcji:
b7739bf50b2edcf636c43a8f8910def9
Tutaj tekst jest haszowany za pomocą kilku przesunięć . Ale niestety wciąż brakuje nam jednego elementu układanki: oprócz argumentu a (który jest tekstem do przetłumaczenia), do funkcji Bp () jest przekazywany kolejny argument b - rodzaj ziarna, które wydaje się zmieniać od czasu do czasu i obejmuje również wpada do haszowania. Ale skąd on pochodzi? Jeśli przejdziemy do wywołania funkcji Bp () , znajdziemy następującą sekcję kodu:
b7739bf50b2edcf636c43a8f8910def9
Funkcja Hq jest wcześniej zadeklarowana w następujący sposób:
b7739bf50b2edcf636c43a8f8910def9
Tutaj Deobfuscater zostawił trochę śmieci; Po zastąpieniu String.fromCharCode ('...') odpowiednimi ciągami znaków, usuń przestarzałe a () i złóż razem wywołania funkcji [c (), c ()] , wynikiem jest:
b7739bf50b2edcf636c43a8f8910def9
Albo jeszcze łatwiej:
b7739bf50b2edcf636c43a8f8910def9
Funkcja yq została wcześniej zdefiniowana jako:
b7739bf50b2edcf636c43a8f8910def9
Wydaje się, że ziarno znajduje się w globalnym obiekcie google.translate._const._ctkk , który jest dostępny w czasie wykonywania. Ale gdzie to jest ustawione? W drugim, wcześniej załadowanym pliku JS main_de.js, przynajmniej jest on również dostępny na początku. Na początku dodajemy następujący tekst:
b7739bf50b2edcf636c43a8f8910def9
W konsoli faktycznie otrzymujemy aktualne ziarno:
To pozostawia Google Chrome, który najwyraźniej zapewnia ziarno jako ostatnią opcję. Na szczęście jego kod źródłowy (Chromium, w tym komponent Tłumacz) jest open source i dlatego jest publicznie dostępny. Pobieramy repozytorium lokalnie i znajdujemy wywołanie funkcji TranslateScript :: GetTranslateScriptURL w pliku translate_script.cc w folderze Components / translate / core / browser:
b7739bf50b2edcf636c43a8f8910def9
Zmienna z adresem URL jest trwale zdefiniowana w tym samym pliku:
b7739bf50b2edcf636c43a8f8910def9
Jeśli teraz przyjrzymy się bliżej plikowi element.js (po ponownym rozogniskowaniu go), znajdziemy stały wpis c._ctkk - obiekt google.translate również jest odpowiednio ustawiony i uruchamiane jest ładowanie wszystkich odpowiednich zasobów (które już odkryliśmy wcześniej):
b7739bf50b2edcf636c43a8f8910def9
Teraz do rozważenia pozostaje klucz parametru (z wartością AIzaSyBOti4mM-6x9WDnZIjIeyEU21OpBXqWBgw). Wygląda na to, że jest to ogólny klucz API przeglądarki (który można również znaleźć w niektórych wynikach Google ). Jest ustawiony w Chromium w pliku translate_url_util.cc w folderze Components / translate / core / browser:
b7739bf50b2edcf636c43a8f8910def9
Klucz jest generowany w google_apis / google_api_keys.cc z fikcyjnej wartości:
b7739bf50b2edcf636c43a8f8910def9
Jednak test pokazuje, że wywołania API działają tak samo bez tego parametru klucza. Jeśli eksperymentujesz z API, otrzymasz z powrotem kod statusu 200, jeśli ci się powiedzie. Jeśli następnie napotkasz limit, otrzymasz z powrotem kod stanu 411 z komunikatem „ Żądania POST wymagają nagłówka o długości zawartości ”. Dlatego zaleca się dołączenie tego nagłówka (który jest automatycznie ustawiany jako tymczasowy nagłówek w programie Postman).
Format zwracanych przetłumaczonych ciągów jest nietypowy, gdy w jednym żądaniu jest kilka zdań. Poszczególne zdania są otoczone znacznikami i- / b-HTML:
Ponadto Google Chrome nie wysyła pełnego kodu HTML do interfejsu API, ale zapisuje w żądaniu wartości atrybutów, takie jak href (zamiast tego ustawia indeksy, aby tagi można było później przypisać po stronie klienta):
Jeśli zmienisz wartość klienta klucza POST z te_lib (Google Chrome) na webapp ( strony pomocną ), można uzyskać ostateczną tłumaczone ciąg:
Problem polega na tym, że istnieje większe prawdopodobieństwo, że napotkasz ograniczenie szybkości niż przez te_lib (dla porównania: w przypadku aplikacji webowej jest to osiągane po 40 000 znaków, w przypadku te_lib nie ma ograniczenia szybkości). Musimy więc przyjrzeć się bliżej, jak Chrome analizuje wynik. Znajdziemy go tutaj w element_main.js:
b7739bf50b2edcf636c43a8f8910def9
Jeśli wyślesz cały kod HTML do interfejsu API, atrybuty zostaną pozostawione w przetłumaczonej odpowiedzi. Dlatego nie musimy imitować całego zachowania parsowania, a jedynie wyodrębnić końcowy, przetłumaczony ciąg z odpowiedzi. Aby to zrobić, tworzymy mały parser tagów HTML, który odrzuca najbardziej zewnętrzne tagi <i> wraz z ich zawartością i usuwa najbardziej zewnętrzne tagi <b>. Dzięki tej wiedzy (po zainstalowaniu zależności z kompozytorem wymagają fzaninotto / faker vielhuber / stringhelper ) możemy teraz zbudować wersję API tłumaczenia po stronie serwera:
b7739bf50b2edcf636c43a8f8910def9
Poniżej przedstawiono wyniki wstępnego testu przeprowadzonego na pięciu różnych systemach o różnych przepustowościach i adresach IP:
Postać | Znaki na żądanie | Trwanie | Wskaźnik błędów | Koszt za pośrednictwem oficjalnego interfejsu API |
13.064.662 | ~250 | 03:36:17 | 0% | 237,78€ |
24.530.510 | ~250 | 11:09:13 | 0% | 446,46€ |
49.060.211 | ~250 | 20:39:10 | 0% | 892,90€ |
99.074.487 | ~1000 | 61:24:37 | 0% | 1803,16€ |
99.072.896 | ~1000 | 62:22:20 | 0% | 1803,13€ |
Σ284,802,766 | ~ Ø550 | Σ 159: 11: 37h | 0% | Σ 5183,41 € |
Uwaga: ten wpis na blogu zawierający wszystkie skrypty został napisany wyłącznie do celów testowych. Nie stosować skrypty do użytku produkcyjnego, zamiast pracować z oficjalnego API pomocna .