Hämta data från webbsidor

Gold

Vi brukar ofta säga att det är fantasin som sätter gränserna till vad man kan använda en Vera till, och det här är ett rätt bra exempel för det. Jag är intresserad av aktier och trading, vilket i sin tur leder till att jag vill ha koll på t.ex. olika index, olja eller guldpris för att använda dessa som indikatorer.

Jag tänker visa hur jag använder Veran för att hämta data från en webbsida och sedan använder dataMine för att skapa grafer över data som jag hämtar in. Och på samma sätt kan du hämta in data från en webbsida som du är intresserad av.

Jag började med att skapa en enhet för Veran som tar emot decimaltal 0-99999 och använder Money som enhet eftersom det är olika valuta på sakerna jag vill hämta data för.

Du kan ladda ner samma enhet här.

Ladda upp dessa 2 filer som finns i zip filen under APPS \ Develop apps \ Luup files. Gå sedan till APPS \ Develop apps \ Create device och ange D_Currency1.xml som Upnp Device Filename och en passande Description som blir enhetens namn.

d_curren

Efter du skapat enheten kan du starta om Veran om du inte får upp enheten under Devices. Du kan även testa att ladda om webbsidan i din webbläsare om den ändå inte dyker upp.

Gold

Då får jag en enhet som ser ut som bilden ovan. Klar för att matas med data.

Guldpriset hämtar jag från Kitco. Och data ligger i en tabell som ser ut så här:

tabell

För att hämta själva data använder jag mig av Powershell. Jag har tidigare använt vbscript för att parsa fram data från andra sidor, men det är betydligt smidigare att använda Powershell tycker jag. Så här ser hela skriptet ut som bara hämtar data jag vill ha och skriver ut det på skärmen.

$url = "http://www.kitco.com/market/"
$content = (new-object System.Net.WebClient).DownloadString($url) 
$content -match '<td id="AU-ask">[0-9].*<\/td>'

$GoldPrice = $Matches[0] -replace '<td id="AU-ask">'
$GoldPrice = $GoldPrice -replace '</td>'
Write-host $GoldPrice

Nu ska vi bryta ner skriptet för att förklara vad som egentligen händer.

$url = "http://www.kitco.com/market/"

$url är alltså den webbsida som innehåller data jag är ute efter.

$content = (new-object System.Net.WebClient).DownloadString($url)

Raden ovan populerar variabeln $content med data som den hämtar från $url. Vi har alltså hämtat data från hemsidan.

$content -match '<td id="AU-ask">[0-9].*<\/td>'

På raden ovan ser ni att jag använder mig av regular expression för att identifiera rätt rad bland all html kod. Mönster matchning skulle man kunna kalla det. Så här beskriver wikipedia regular expression som även förkortas regex.

In theoretical computer science and formal language theory, a regular expression (sometimes called a rational expression)[1][2] is a sequence of characters that define a search pattern, mainly for use in pattern matching with strings, or string matching, i.e. ”find and replace”-like operations.

Och för att veta vilken rad jag är ute efter när jag ska matcha, så använder jag mig av inspektera funktionen som finns i Chrome och som även finns för andra webbläsare. Den får jag fram genom att högerklicka på webbsidan jag är ute efter och välja valet inspektera i menyn som kommer fram.

inspektera2

När jag fått fram det nya fönstret som ni ser på bilden till höger, så håller jag in CTRL + F som ger mig sökrutan. Jag söker efter 1295 eftersom jag ser att det är guldpriset just nu enligt bilden ovan. Då hittar jag rätt rad i fönstret till höger som ni ser.

För att skapa min söksträng med regular expression så använder jag mig av en sajt som heter https://regex101.com. Den förenklar det hela genom att jag kan se i realtid vad min söksträng kommer att matcha.

Först måste jag ha html koden som den ska söka i. Jag öppnar powershell och kör dessa rader nedan.

$url = "http://www.kitco.com/market/"
$content = (new-object System.Net.WebClient).DownloadString($url)

Powershell1

Och i powershell kan du enkelt se vad t.ex. variabeln $content innehåller genom att bara skriva $content. Men här blir det enklare att pipa ut det till en text fil som vi kan öppna i notepad och klippa ut innehållet så vi kan klistra in det på regex101 sidan.

Powershell2

Nu när du klistrat in innehållet på sidan under TEST STRING så kan du börja göra din matchning.

regex

För dig som vill lära dig lite om regular expression så finns det många hjälpsamma sidor till ditt förfogade. T.ex. denna. http://regexone.com/ Kortfattat så handlar det om att du ska matcha delen av din sträng som du vet är konsekvent, medans den delen av strängen som ändras så använder du olika jokertecken (wildcard). Och i mitt fall resulterade detta i denna söksträng.

regex1

Du som är skarpsynt ser att taggen för att avsluta html tabellen inte ser rätt ut, och det är för att det finns vissa olagliga tecken för regex  och / är ett av dessa, så för att tagget </td> blir då <\/td> som på bilden ovan.

Nu fortsätter vi med powershell skriptet, och nästa uppgift blir att städa svaret. Och svaret döljer sig i variabeln $Matches.

Hade vi fått fler än ett svar så kommer $Matches innehålla dessa, men även fast jag bara fick en träff kommer jag specificera att jag endast vill använda den första raden som då blir $Matches[0].

Powershell4

Så nu går vi genom allt steg för steg enligt bilden ovan.

  1. Jag sätter min adress till webbsidan som innehåller data jag är intresserad av.
  2. Jag hämtar htmlkoden från webbsidan till varabeln $content.
  3. Jag använder min regex sträng för att hitta rätt rad i htmlkoden.
  4. True kommer jag få som svar om den hittat en match på min söksträng.
  5. Här frågar jag vad det första svaret är i $Matches variabeln som blir svaret på min regex söksträng.
  6. Svaret i html på min regex söksträng visas på denna rad.
  7. Här säger jag att variabeln $Goldprice ska innehålla html raden från min regex söksträng och samtidigt ersätta <td id=”AU-ask”> med inget, vilket gör att jag får ett renare svar.
  8. Här kollar jag vad variabeln $GoldPrice nu innehåller
  9. Här ser ni att svaret ser nu mer läsligt ut, men fortfarande lite html kod kvar att rensa.
  10. Här rensar jag det som är kvar av html koden så att bara värdet blir kvar i variabeln.
  11. Jag kollar nu igen vad som är kvar i min variabel $GoldPrice.
  12. Och som ni ser är nu svaret i rätt format som jag vill ha det.

Så vad har vi kvar nu? Jo nu ska vi ladda upp data till Veran!

#Send to Vera Kitco Gold
$VeraUrl = "http://192.168.69.1:3480/data_request?id=variableset&DeviceNum=119&serviceId=urn:micasaverde-com:serviceId:LightSensor1&Variable=CurrentLevel&Value=$GoldPrice"
Invoke-WebRequest -uri $VeraUrl

Här ovan ser ni ett exempel på hur ni matar eran nya enhet med data. 192.168.69.1 är IP-adressen till Veran, byt ut denna till din aktuella IP-adress för din Vera. Och DeviceNum=119 är enhets-id på den enheten i Veran som du vill mata med data. Längst bak ser ni variabeln $GoldPrice som blir värdet som skjuts över till enheten.

Och så här ser hela det skriptet ut.

$url = "http://www.kitco.com/market/"
$content = (new-object System.Net.WebClient).DownloadString($url) 
$content -match '<td id="AU-ask">[0-9].*<\/td>'

$GoldPrice = $Matches[0] -replace '<td id="AU-ask">'
$GoldPrice = $GoldPrice -replace '</td>'
Write-host $GoldPrice

#Send to Vera Kitco Gold
$VeraUrl = "http://192.168.69.1:3480/data_request?id=variableset&DeviceNum=119&serviceId=urn:micasaverde-com:serviceId:LightSensor1&Variable=CurrentLevel&Value=$GoldPrice"
Invoke-WebRequest -uri $VeraUrl

Väldigt användbart och tar inte så lång tid att få till när man väl gjort det några gånger.

Så finns det några nackdelar med detta? Ja det gör det tyvärr. Den största risken är att hemsidan görs om så att htmlkoden ändras i den utsträckning att din hämtning slutar att fungera. Och det finns även vissa webbsidor som blockerar skript som dessa eftersom de belastar deras webbserver.

Ett tips till dig som vill göra detta. Fundera hur ofta du behöver ha data. Kör inte skriptet 1 gång i minuten bara för att du kan, du belastar webbservern för den som är snäll att tillhandahålla detta data som du är intresserad av. Du kanske klarar dig med att hämta var 10:e eller 15:e minut istället, vilket ger 10 eller 15 gånger mindre belastning.

En annan bra grej som jag nu får på köpet, är att jag enkelt kan använda t.ex. Vera Alerts för att få ett meddelande om guldpriset går över eller under en viss gräns. Inte så tokigt med en Vera i hemmet 🙂

2 reaktioner på ”Hämta data från webbsidor”

  1. Pingback: PowerShell – Trigga system med bilder från webbkameror |

  2. Hej! Jag har helt nyligen blivit tipsad om denna sida, som verkar kunna hjälpa mig med det jag vill. Men jag skriver också för att lämna min uppskattning till denna textrad: ”…för den som är snäll att tillhandahålla detta data som du är intresserad av.”

    Det behöver man förhålla sig till hela tiden, att ”andra inte är till bara för mig”.

    Tack för ordet och på återhörande!
    /LarsN

Lämna en kommentar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *