Python posiada bibliotekę urllib2 do wykonywania zapytań HTTP, HTTPS, FTP. Dzięki niej łatwo możemy pobrać zawartość strony www czy plik z jakiegoś serwera. W poprzednim poście (“Simple.Data.SqlServer na hostingu Webio“) stworzyłem proste Web Api, które zwraca listę obiektów klasy Event z serwera. W celu jej pobrania wystarczy wywołać metodę urlopen():
|
import urllib2 response = urllib2.urlopen('http://smartlodowka.creyn.pl/api/events/') print response.read() # [{"Id":2,"Name":"First test event"},{"Id":3,"Name":"And second event"},{"Id":4,"Name":"Test multi 1"},{"Id":5,"Name":"Test multi 2"},{"Id":6,"Name":"New one"},{"Id":7,"Name":"pTest1"}] |
Możemy użyć bezpośrednio URLa lub stworzyć obiekt Request, który umożliwi także ustawianie nagłówków żądania. W tym przykładzie chcę dostać od serwera odpowiedź w formacie XML a nie JSON.
|
import urllib2 request = urllib2.Request('http://smartlodowka.creyn.pl/api/events/') request.add_header('Accept', 'application/xml') response = urllib2.urlopen(request) print response.read() # <ArrayOfEvent xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/SmartLodowkaAPI.DTO"><Event><Id>2</Id><Name>First test event</Name></Event><Event><Id>3</Id><Name>And second event</Name></Event><Event><Id>4</Id><Name>Test multi 1</Name></Event><Event><Id>5</Id><Name>Test multi 2</Name></Event><Event><Id>6</Id><Name>New one</Name></Event><Event><Id>7</Id><Name>pTest1</Name></Event></ArrayOfEvent> |
Pobrana odpowiedź z serwera jest stringiem, przydałoby się zamienić ją na jakiś bardziej przydatny typ danych. Zacznijmy od stworzenia klasy Event. Konstruktor klasy w Pythonie nazywa sie “__init__” i przyjmuje parametr “self“, dzięki któremu możemy stworzyć property klasy i zainicjować je na odpowiednie dane przekazane przy tworzeniu obiektu.
|
class Event: def __init__(self, id, name): self.Id = id self.Name = name ev = Event(1, 'First event') print 'Name of first event: ' + ev.Name + ' of id: ' + str(ev.Id) # Name of first event: First event of id: 1 |
Nie można łączyć ze sobą stringów i intów. Należy najpierw zamienić int na string. Stąd: str(ev.Id)
Następnie należy zrobić deserializację stringa do obiektów naszej nowej klasy. Wiemy, że z serwera dostaniemy listę obiektów typu Event w jednym stringu w formacie JSON. Niestety nie udało mi się znaleźć biblioteki pokroju Json.NET od Newtonsoft. Także napiszemy własnego, skrojonego na miarę “Json to Event” parsera opartego na wyrażeniach regularnych:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
import json import re # regular expresion module # class representing Event class Event: def __init__(self, id, name): self.Id = int(id) # make sure id is integer self.Name = name # response that cames from api response = '[{"Id":2,"Name":"First test event"},{"Id":3,"Name":"And second event"},{"Id":4,"Name":"Test multi 1"},{"Id":5,"Name":"Test multi 2"},{"Id":6,"Name":"New one"},{"Id":7,"Name":"pTest1"}]' print response # [{"Id":2,"Name":"First test event"},{"Id":3,"Name":"And second event"},{"Id":4,"Name":"Test multi 1"},{"Id":5,"Name":"Test multi 2"},{"Id":6,"Name":"New one"},{"Id":7,"Name":"pTest1"}] # split response and get all objects: between { and } jsonObjects = re.findall("{.*?}",response) # foreach of found object, get values between: " and " and between: : and , events = [] for o in jsonObjects: values = re.findall("\".*?\"|:.*?,", o) id = values[1][1:-1] # remove first and last character name = values[3][1:-1] ev = Event(id, name) events.append(ev) print len(events) # 6 print 'Id is: ' + str(events[3].Id) # Id is: 5 print 'Name is: ' + events[3].Name # Name is: Test multi 2 |
Trochę nie podoba mi się zabawa ze stringami i wyrażeniami regularnymi. Jeżeli ktoś z czytelników zna fajną bibliotekę Pythona deserializującą JSONa do obiektów danej klasy, proszę o komentarz :)
Powyższy kod pozostawia wiele do życzenia, co z kolei daje miejsce do poprawy w kolejnych wpisach :)
Skoro już potrafimy pobrać listę zdarzeń z Web Api należałoby teraz wysłać nowe i dodać do kolekcji na serwerze. W tym celu również posłużymy się biblioteką urllib2 i metodą urlopen. Metoda ta, jako pierwszy parametr przyjmuje URL lub obiekt Request określający docelowy endpoint, do którego się łączy. Jako drugi parametr może przyjąć dane. Jeżeli przekażemy do tej metody dane, to automatycznie zostanie wysłane zapytanie POST (zamiast GET jak w poprzednich przypadkach). Dane muszą być w formacie ‘application/x-www-form-urlencoded‘.
|
import urllib2 # has to be list of Events data = 'Events[0].Name=TestURLLIB2' response = urllib2.urlopen('http://smartlodowka.creyn.pl/api/events/', data) print response.read() # [{"Id":8,"Name":"TestURLLIB2"}] |
Ten dziwny format danych wysłanych w requeście spowodowany jest sposobem w jaki budowane są obiekty C# w Web Api. Kontroler spodziewa się listy obiektów typu Event, nazwa tego property to właśnie “Events“, czyli przesyłamy tablicę i pierwszy element (stąd indeks 0) bindujemy do obiektu Event a jego property “Name” ustawiamy na “TestURLLIB2″.
|
public IHttpActionResult Post(CreateEventsRequest request) { ... } public class CreateEventsRequest { public List<Event> Events { get; set; } } public class Event { ... public string Name { get; set; } } |
A chcąc przekazać dwa zdarzenia ustawiamy dwa pierwsze elementy tablicy
|
import urllib2 url = 'http://smartlodowka.creyn.pl/api/events/' # has to be list of Events data = 'Events[0].Name=List1&Events[1].Name=List2' response = urllib2.urlopen(url, data) print response.read() # [{"Id":9,"Name":"List1"},{"Id":10,"Name":"List2"}] allEvents = urllib2.urlopen(url).read() print allEvents # [{"Id":2,"Name":"First test event"},{"Id":3,"Name":"And second event"},{"Id":4,"Name":"Test multi 1"},{"Id":5,"Name":"Test multi 2"},{"Id":6,"Name":"New one"},{"Id":7,"Name":"pTest1"},{"Id":8,"Name":"TestURLLIB2"},{"Id":9,"Name":"List1"},{"Id":10,"Name":"List2"}] |
Dzięki tym kilku ćwiczeniom znamy już proste zapytania HTTP: pobieranie danych za pomocą GET i wysyłanie za pomocą POST. W tym momencie to w zupełności wystarczy aby przejść dalej w ramach projektu Smart Lodówka i przymierzyć się do wysyłania zdarzeń ze świata rzeczywistego. Zacznę od dwóch podstawowych typów zdarzeń: Otwarcie i Zamknięcie drzwi lodówki.
C.
Like this:
Like Loading...
Leave a Reply