Jedną z niezwykle ciekawych funkcjonalności dostępnych w Power BI jest możliwość pobierania danych znajdujących się na stronach internetowych bez konieczności pisania dodatkowego kodu. Konektor Web który jest kluczowym elementem opisywanej funkcjonalności, pozwala w prosty sposób pobrać dane tego typu. W ramach niniejszego artykułu chciałbym napisać parę słów na ten temat i pokazać jak w prosty sposób rozwiązać napotkane problemy.
Dane do naszego testu pobierzemy z największego serwisu filmowego na świecie czyli IMDB. Nasz scenariusz zakłada pobranie listy najwyżej ocenianych filmów komediowych do Power BI w celu ich późniejszej wizualizacji. Lista interesujących nas ekranizacji dostępna jest pod następującym linkiem: https://www.imdb.com/list/ls072723591/?sort=list_order,asc&st_dt=&mode=detail&page=1. Zamieściłem tutaj pełny link ponieważ to właśnie w jego konstrukcji możemy zauważyć, że składa się on z kilku członów i jest parametryzowany gdzie parametrem, któremu w szczególności będziemy chcieli się przyjrzeć jest page. Parametr ten wskazuje na którą stronę zestawienia chcemy zajrzeć. Powyższy link wskazuje oczywiście na pierwszą stronę zawierającą pierwszą setkę filmów. W ramach naszego testu będziemy chcieli pobrać 500 filmów, które są widoczne po 100 tytułów na stronie. Na ten moment się tym nie przejmujemy się wszystkimi stronami i spróbujemy pobrać dane z pierwszej z nich. Do tego celu wykorzystamy konektor Web dostępny oczywiście ze wstążki Get data -> Web:
Jego konfiguracja na ten moment sprowadza się do podania odpowiedniego adresu URL z którego chcemy pobierać dane. Wklejamy zatem adres URL ze wskazaniem pierwszej strony:
Po zatwierdzeniu przyciskiem OK naszym oczom powinien ukazać się podgląd tego co na danej stronie znalazł Power BI:
Jeżeli strona, którą podaliśmy nie jest prostą strukturą HTML to domyślnie rzecz biorąc Power BI niewiele nam tutaj podpowie. Jednakże pod ręką mamy bardzo fajną funkcjonalność jaką jest zaznaczona na powyższym zrzucie ekranowym opcja Add table using examples. Opcja ta pozwala wskazać jakie elementy na stronie nas interesują, a Power BI na tej podstawie postara się znaleźć odpowiedni wzorzec i stworzyć selektor wybierający odpowiednie elementy z kodu strony.
Konfiguracja Add table using examples sprowadza się do zlokalizowania interesujących nas danych na podglądzie i wpisania odpowiednich danych w pierwszy wiersz tabeli znajdującej się w dolnej części ekranu. Jak widać pierwszym filmem na liście jest Deadpool i dlatego też wpisałem do tabeli opisujące go atrybuty takie jak:
- pozycja (Rank),
- tytuł (Title),
- rok (Year),
- ocena (Rate),
- długość (Duration),
- typ (Type).
W kolejnym kroku do wiersza numer dwa wpisałem kolejne miejsce w rankingu tak aby Power BI mógł znaleźć interesujący nas wzorzec i resztę miejsc uzupełnił automatycznie. Jeżeli wszystko wypełniliśmy poprawnie to powinniśmy zobaczyć propozycje pozostałych miejsc na stronie, tak jak zostało to przedstawione na poniższym zrzucie ekranowym:
Jak możecie zauważyć, powyższy rezultat jest jak najbardziej tym czego oczekiwaliśmy. Warto tutaj zaznaczyć, że jeżeli Power BI nie będzie w stanie znaleźć wzorca to oczywiście dostaniemy odpowiedni komunikat błędu. Dla przykładu aby zilustrować to zachowanie nie zapisałem poprawnie pełnej nazwy tytułu filmu i selektor nie mógł zostać znaleziony (musimy być pod tym względem uważni i wpisywać pełne informacje znajdujące się na stronie):
Nawet jeśli na pierwszy rzut oka wszystko się zgadza to warto przewinąć nieco okno sugerowanych wartości i uzupełnić brakujące jeśli takowe się znajdą. Jeżeli luki w danych występują to może to być spowodowane po prostu innym lub niejednoznacznym zapisem w kodzie strony). Jeśli wygenerowany rezultat zaspokaja nasze potrzeby to zostanie wygenerowany odpowiedni kod który dokona web scrapingu czyli pobrania danych ze strony. Warto również rozważyć to żeby nie ładować danych w surowej postaci tylko je nieco oczyścić przy pomocy Power Query. Dokonamy tego poprzez kliknięcie Transform Data:
Na samym początku nasz zbiór danych wygląda następująco:
Pierwsze co powinno nam się rzucić w oczy to fakt, że wszystkie kolumny mają typ tekst. Zmieńmy domyślne zachowanie i zmodyfikujemy typ kolumny “Rank” z tekstowego na całkowitoliczbowy, analogicznie dla kolumny “Rate” z tekstowego na zmiennoprzecinkowy. Takiej konwersji możemy oczywiście dokonać na wiele różnych sposobów, ja użyłem konwersji dostępnej z poziomu nagłówka tak jak możecie zobaczyć poniżej:
Gdy typy danych się zgadzają to w kolejnym kroku wyodrębnimy długość trwania filmu (Duration) tak byśmy mogli operować tą daną pod postacią liczbową, a nie tekstową. Oprócz tego pozbędziemy się nawiasów w nazwie roku, które na stronie pełniły rolę estetyczną, a w analizie tych danych są dla nas całkowicie zbędne. Obu tych transformacji dokonamy przy pomocy funkcjonalności Column From Examples, która działa analogicznie do opisywanego wyżej pobierania danych ze strony internetowej (oznacza to, że wpisujemy co chcemy osiągnąć, a Power BI postara się znaleźć wzorzec i użyć odpowiedniej funkcji języka M). Cały proces wyodrębniania możecie zobaczyć na poniższej animacji:
Podobną operację wykonałem dla kolumny “Duration” gdzie usunąłem ciąg tekstowy ” min” i zmieniłem typ danych na całkowitoliczbowy. Po ostatecznych zmianach całość prezentuje się w następujący sposób:
Jeśli byłaby taka potrzeba to dodatkowo moglibyśmy wyodrębnić dane wylistowane po przecinku w kolumnie “Type”, jednakże ja je na ten moment traktuje jako dane opisowe i pozostawiłem je w obecnej formie. Powstałą tabelę nazwałem “TopMovies” i w obecnej formie załadowałem do modelu. Jeśli interesowałoby nas 100 najwyżej ocenianych filmów to właściwie nasza praca mogłaby na tym się skończyć, my jednak przejdziemy nieco dalej i będziemy chcieli przejść przez pozostałe strony zestawienia. Ogólnie rzecz biorąc to czy pobieramy dane filmów od 1 do 100 czy od 101 do 200 nie powinno mieć znaczenia pod kątem struktury strony z której pobieramy dane. Dlatego też dobrym pomysłem będzie zamiana naszego zapytania na funkcję, która jako parametr przyjmie numer strony z której będziemy pobierać dane.
Aby stworzyć funkcję klikamy prawym przyciskiem myszy na wybrane zapytanie i z menu kontekstowego wybieramy Create funciton:
Na początku dostaniemy komunikat, że nasza funkcja w momencie tworzenia nie zawiera żadnego parametru. Akceptujemy ten fakt i klikamy Create:
Dalej podajemy nazwę funkcji, ja zwyczajowo dodaję zawsze przedrostek udf_ i tak też zrobiłem w tym wypadku:
W kolejnym kroku należy przejść do powstałej funkcji i włączyć Advanced Editor gdzie dodamy parametr, a następnie go podstawimy do URL zamiast numeru strony:
Mamy gotową funkcję, dlatego warto usunąć zapytanie, które posłużyło nam do wygenerowania poszczególnych transformacji wchodzących w jej skład. Przechodząc dalej musimy wywołać stworzoną funkcję z odpowiednimi parametrami. Jak to zrobić? Już tłumaczę! Najpierw stwórzmy sobie puste zapytanie wybierając New Source -> Blank Query:
Następnie przechodzimy do Advanced Editora i tam wpisujemy następujący kod M który najpierw stworzy listę z liczbami od 1 do 5, a następnie zamieni ją na tabelę:
let Source = {1..5}, #"Converted to Table" = Table.FromList(Source, Splitter.SplitByNothing(), null, null, ExtraValues.Error), #"Renamed Columns" = Table.RenameColumns(#"Converted to Table",{{"Column1", "PageNumber"}}) in #"Renamed Columns"
Po wykonaniu powyższego kodu rezultat powinien przedstawiać się w następujący sposób:
Powstała kolumna jest typu Any, można więc powiedzieć, że nie ma typu więc możemy to zmienić przypisując jej typ tekstowy w przedstawiony wcześniej sposób. Teraz nie pozostaje nic innego jak wywołać funkcję dla każdego z wierszy przekazując kolumnę “PageNumber” jako jej parametr. Wybieramy zatem ze wstążki Add Column -> Invoke Custom Function:
Sama konfiguracja wywołania funkcji wygląda następująco:
Po wywołaniu funkcji jeśli wszystko wykonaliśmy poprawnie to powinniśmy otrzymać następujący widok:
Kolejnym krokiem będzie pobranie danych znajdujących się pod każdym z wierszy, a zrobimy to np. poprzez kliknięcie przycisku Expand zaznaczonego na powyższym zrzucie ekranowym. Po wykonaniu tej operacji powinniśmy otrzymać interesujący nas zbiór danych:
Przed ostatecznym załadowaniem danych polecam sprawdzić jakość pobranych danych oraz wykonać dwie dodatkowe transformacje. Pierwszą z nich będzie odfiltrowanie wierszy, które nie posiadają rankingu:
Musimy tak zrobić ze względu na fakt, iż na sztywno ustawiliśmy nasze ładowanie aby pobierało 5 kolejnych stron, a jeżeli takowej ilości stron nie ma to mogą nam wpaść po prostu puste wiersze więc warto je wyeliminować. Drugą transformacją wartą wykonania jest nadanie typów dla wszystkich kolumn. Najłatwiej jest to osiągnąć zaznaczając je wszystkie i wybierając transformację Transform -> Detect Data Types:
Kiedy mamy już wszystko gotowe możemy załadować dane do modelu, wszystko powinno odbyć się bez większego problemu. Dla pewności, że wszystko działa odświeżmy cały zbiór danych korzystając z opcji dostępnej na wstążce. Pierwszy problem prawdopodobnie pojawi się zaraz po opublikowaniu na portalu powerbi.com i próbie odświeżenia danych. W moim przypadku powstały błąd wygląda następująco:
Co się dzieje? Wygląda na to, że wszystko działa w Power BI Desktop ale niestety nie działa w serwisie. Na szczęście istnieje sposób na poradzenie sobie z tym problemem, o tym i jeszcze kilku dodatkowych rzeczach postaram się napisać kilka słów już w następnym artykule – aby go nie przegapić zapraszam do subskrypcji. Pozdrawiam!
- Avoiding Issues: Monitoring Query Pushdowns in Databricks Federated Queries - October 27, 2024
- Microsoft Fabric: Using Workspace Identity for Authentication - September 25, 2024
- Executing SQL queries from Azure DevOps using Service Connection credentials - August 28, 2024
Super artykuł, sporo się nauczyłem 🙂 Pozdrawiam!
Dzięki i pozdrawiam!