Moi! Suht aloitteleva koodari täällä ja tarvisin apua. Koitan rakentaa Alkon API:n pohjalle toimivaa hyvin yksinkertaista pikku python-ohjelmaa, jossa pyydetään tietoa halutun tuotteen saatavuudesta halutussa kaupungissa. Itse apista datan hakeminen oli helppoa, mutta ongelmia aiheuttaa Alkon sivuillaan ylläpitämä tekstitiedosto tuotehinnastosta, jota en saa parsittua millään tavalla järkevään muotoon: http://www.alko.fi/tuotteet/tallennahinnasto/
Saan tuon parsittua vain massiiviseksi stringiksi enkä saa millään tavalla siihen mitään struktuuria. Olen kokeillut ties mitä splittejä sun muita, mutta tuo string ei tahdo muuntua edes listaksi vaikka mitä yritän.
Regular expressioneilla onnistuin parsimaan tuoteID:n, mitä tarvitaan API:n käyttöön, mutta haluaisin ensiksi tarjota käyttäjällä listan eri tuotekategerioista ja tämän alta listan tuotteista, jotta käyttäjä voi valita haluamansa tuotteen, jota hakea.
Tässä toistaiseksi tekemäni koodi, jossa tietyn tuotteen valinnan sijaan valitaan täysin satunnainen tuote Alkon listalta ja haetaan sen tiedot annetun kaupungin Alkoista:
import requests
from urllib.request import urlopen
import re
import random
import pandas
tuotteet= urlopen('http://www.alko.fi/contentassets/df76c4146bb74ac08089e5bf610e6d67/fi/alkon-hinnasto-tekstitiedostona.txt').read().decode('utf_8')
tuotenro = re.findall('[0-9][0-9][0-9][0-9][0-9][0-9]', tuotteet)
tuote = random.choice(tuotenro)
print("Anna kaupunki, jonka Alkoista haetaan")
kaupunki=input()
haku=requests.get('http://www.alko.fi/api/product/Availability?productId=' tuote '&cityId=' kaupunki '&language=fi')
data = haku.json()
maara=[]
kauppa=[]
for list in data:
maara.append(list['Amount'])
kauppa.append(list['StoreName'])
DataSet= pandas.DataFrame(maara,kauppa)
print(DataSet)
Saako tuohon Alkon tuotelista-tekstitiedostoon mitään struktuuria kun sen hakee Pythoniin? Haluaisin parsia sieltä tuoteID:n lisäksi ainakin tuotteen nimen sekä tyypin.
Käytössä Python 3.5 Windowsilla.
Saan tuon parsittua vain massiiviseksi stringiksi enkä saa millään tavalla siihen mitään struktuuria. Olen kokeillut ties mitä splittejä sun muita, mutta tuo string ei tahdo muuntua edes listaksi vaikka mitä yritän.
Regular expressioneilla onnistuin parsimaan tuoteID:n, mitä tarvitaan API:n käyttöön, mutta haluaisin ensiksi tarjota käyttäjällä listan eri tuotekategerioista ja tämän alta listan tuotteista, jotta käyttäjä voi valita haluamansa tuotteen, jota hakea.
Tässä toistaiseksi tekemäni koodi, jossa tietyn tuotteen valinnan sijaan valitaan täysin satunnainen tuote Alkon listalta ja haetaan sen tiedot annetun kaupungin Alkoista:
import requests
from urllib.request import urlopen
import re
import random
import pandas
tuotteet= urlopen('http://www.alko.fi/contentassets/df76c4146bb74ac08089e5bf610e6d67/fi/alkon-hinnasto-tekstitiedostona.txt').read().decode('utf_8')
tuotenro = re.findall('[0-9][0-9][0-9][0-9][0-9][0-9]', tuotteet)
tuote = random.choice(tuotenro)
print("Anna kaupunki, jonka Alkoista haetaan")
kaupunki=input()
haku=requests.get('http://www.alko.fi/api/product/Availability?productId=' tuote '&cityId=' kaupunki '&language=fi')
data = haku.json()
maara=[]
kauppa=[]
for list in data:
maara.append(list['Amount'])
kauppa.append(list['StoreName'])
DataSet= pandas.DataFrame(maara,kauppa)
print(DataSet)
Saako tuohon Alkon tuotelista-tekstitiedostoon mitään struktuuria kun sen hakee Pythoniin? Haluaisin parsia sieltä tuoteID:n lisäksi ainakin tuotteen nimen sekä tyypin.
Käytössä Python 3.5 Windowsilla.
Vastaukset 13
Vanhimmat
Tabulaattori erottimena teksti menee soluihin nätisti Calcissa.
Eikö sen näe siellä kaupassa paikanpäällä onko juuri sitä haluamaansa laatua olevaa pulloa vai ei.
Jos ei ole niin ostaa vähän toista laatua sitten.
Kokeilin hakea kossupulloa Varkauden viinakaupasta, syöttämällä selaimen osoiteriville (katsoin tuoteid:n Alkon sivuilta):
http://www.alko.fi/api/product/Availability?productId=000132&cityId=Varkaus&language=fi
Selain palautti:
[{"StoreName":"Varkaus","StoreLink":"/myymalat-palvelut/2736/","Amount":"18","LastUpdated":"17.11."}]
Tuloksesta sain irroitetuksi myymälän ja määrän esim näin:
#koodi alkaa
tiedot = [{"StoreName":"Varkaus","StoreLink":"/myymalat-palvelut/2736/","Amount":"18","LastUpdated":"17.11."}]
for rivi in tiedot:
print("Alko:", rivi["StoreName"])
print("Määrä: ", rivi["Amount"])
#koodi loppuu
Joka tulosti:
Alko: Varkaus
Määrä: 18
Nuo aaltosulkeet oli itselleni uusi tuttavuus, niiden käyttöä selitetty:
http://stackoverflow.com/questions/9197324/curly-braces-in-python
CSV-tiedostojen käsittelystä on juttua:
https://docs.python.org/2/library/csv.html
En näköjään vastannut varsinaiseen kysymykseesi, pitänee tutkia tuota CSV-osastoa tarkemmin.
Ei tarvinnut käyttää CSV:tä. Tässä esimerkissä kysytään hakuarvo, jota haetaan taulukon "Nimi"-sarakkeesta ja palautetaan "Numero"-sarakkeen arvo, jos hakuarvo löytyy.
#koodi alkaa
import requests
from urllib.request import urlopen
tuotteet=urlopen('http://www.alko.fi/contentassets/df76c4146bb74ac08089e5bf610e6d67/fi/alkon-hinnasto-tekstitiedostona.txt').read().decode('utf_8')
pos=tuotteet.find("Numero"); # etsitään vars. taulukon alku
if pos>0: # jos taulukon alku löytyi, niin
tuotteet=tuotteet[pos:].splitlines() # pilkotaan taulukko riveihin
otsikot=tuotteet[0].split("\t") # otsikkorivin sarakkeet listaksi
nimisarake=otsikot.index("Nimi") # tuotenimen sarakeindeksi
palautussarake=otsikot.index("Numero") # paluuarvosarake
hakunimi=input("Hakuarvo: ")
rivit=len(tuotteet) # rivien määrä
for r in range(rivit):
rivi=tuotteet[r].split("\t")
if rivi[nimisarake].find(hakunimi) >= 0:
print(rivi[palautussarake])
#koodi päättyy
Sehän on jsonia
import json
alko='{"StoreName":"Varkaus","StoreLink":"/myymalat-palvelut/2736/","Amount":"18","LastUpdated":"17.11."}'
parsed = json.loads(alko)
print(parsed['StoreName'])
Suuntaa antavaa taulukointia
http://pastebin.com/vSXuR7D4
Affiliate-Julkaisia
Linux Mint 18 Sarah
Xfce 64-bit
Tietysti sinne tuli virhe, rivi 41 näin
Numerot = line.split('\t')
Eli rivi puretaan sarakketiedoksi tabulointi merkillä. Lisäksi huomaa että käsittelen ohjelmassa "HINNASTOA" paikallisena tiedostona, verkkoa kuormittamatta.
Ja vielä kannattaa huomioida että hinaston tallenus teksti-tiedostoksi ei ole onnistunut alunalkaen oikein, kettien määrä eri tuotteilla on erillainen. Eli kun alunperin hinnastoa on luotu, kokaisen kentän pitäisi sisältää vaikka välilyönti, ei näytä muuten tieksitiedostoksi viedessä säilyvän kenttäjako, tai ne katoaa Windows <--> Linux syystä.
Affiliate-Julkaisia
Linux Mint 18 Sarah
Xfce 64-bit
Vielkäin+on+jokin+TYPO+mukana.
Kun+yrität+noutaa+kakki+ne+tuotteet+jotka+sisältävät+"Koskenkorva"+joutuu+jättämään+ensimmäisen+kirjaimen+pois,+eli+näin:
for+x+in+tuotteet[Nimi]:
if+x.find('oskenkorv')+>+0:
print(x)
Vain+näin+löytyy+kaikki:
Koskenkorva+Viina
Koskenkorva+Viina
Koskenkorva+Viina++muovipullo
Koskenkorva+Viina++muovipullo
Koskenkorva+Viina++muovipullo
Koskenkorva+Viina++muovipullo
Koskenkorva+Viina++muovipullo
Koskenkorva+Vodka+40+%
Koskenkorva+Vodka+40+%++muovipullo
Koskenkorva+Vodka+40+%++muovipullo
Koskenkorva+Vodka+60+%++muovipullo
Koskenkorva+Vodka+Sauna+Barrel
Koskenkorva+Vodka+Vanilla++muovipullo
Koskenkorva+Viina+30+%++muovipullo
Koskenkorva+Viina+30%++muovipullo
Koskenkorva+Viina+30%++muovipullo
Koskenkorva+Viina+32+%
Koskenkorva+Viina+Omena++muovipullo
Koskenkorva+Pure+Apple++tölkki
Koskenkorva+Pure+Cranberry++tölkki
Koskenkorva+Pure+Strawberry+Lime++tölkki
Koskenkorva+The+Original+Strawberry++muovipullo
Koskenkorva+The+Original+Peach++muovipullo
Koskenkorva+Minttu++muovipullo
Koskenkorva+Lakritsi
Koskenkorva+Salmiakki
Koskenkorva+Salmiakki++muovipullo
Koskenkorva+Salmiakki++muovipullo
Koskenkorva+Salmiakki++muovipullo
Koitan+löytää+ratkaisun+tuonnempana+mikäli+mennään+oikeaan+suuntaa+tään+ohjelman+kanssa.
Affiliate-Julkaisia
Linux+Mint+18+Sarah
Xfce+64-bit
Lähdemateriaaliin+voi+tosiaan+jäädä+virheitä.+Muokkasin+nyt+omaa+koodiani+siten,+että+tehdään+ilmoitus,+mikäli+rivin+sarakkeiden+määrä+poikkeaa+otsikkosarakkeiden+määrästä.+Yritetään+silti+hakea+tuotetta+siltä+riviltä,+mutta+ympäröidään+mahdollinen+tulos+huutomerkkiriveillä,+koska+tulos+ei+ole+välttämättä+oikein.+Lisäksi+näytetään+tuotenro:n+lisäksi+tuotteen+nimi+(sama+siis+mihin+hakuarvoa+verrataan+joka+rivillä)
Linkki+oli+näköjään+muuttunut+myös.
import+requests
from+urllib.request+import+urlopen
#koodi+alkaa
tuotteet=urlopen('https://www.alko.fi/INTERSHOP/static/WFS/Alko-OnlineShop-Site/-/Alko-OnlineShop/fi_FI/Muut+ladattavat+tiedostot/Hinnastot/alkon-hinnasto-tekstitiedostona-21-11.txt').read().decode('utf_8')
pos=tuotteet.find("Numero");+#+etsitään+vars.+taulukon+alku
if+pos>0:+#+jos+taulukon+alku+löytyi,+niin
++++tuotteet=tuotteet[pos:].splitlines()+#+pilkotaan+taulukko+riveihin
++++otsikot=tuotteet[0].split("\t")+#+otsikkorivin+sarakkeet+listaksi
++++nimisarake=otsikot.index("Nimi")+#+tuotenimen+sarakeindeksi
++++palautussarake=otsikot.index("Numero")+#+paluuarvosarake
++++hakunimi=input("Hakuarvo:+")
++++rivit=len(tuotteet)+#+rivien+määrä
++++for+r+in+range(rivit):
++++++++rivi=tuotteet[r].split("\t")
++++++++if+len(rivi)+!=+len(otsikot):
++++++++++++print("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
++++++++++++print("Rivillä+nro",str(r+1),"virheellinen+määrä+("+\
+++++++++++++++++++str(len(rivi))+")+sarakkeita")
++++++++++++if+rivi[nimisarake].find(hakunimi)+>=+0:
++++++++++++++++print(rivi[palautussarake]+":+",end="")
++++++++++++++++print(rivi[nimisarake])
++++++++++++print("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
++++++++++++continue
++++++++if+rivi[nimisarake].find(hakunimi)+>=+0:
++++++++++++print(rivi[palautussarake]+":+",end="")
++++++++++++print(rivi[nimisarake])
#koodi+loppuu
Esimerkiksi+haettassa+sanalla+"Koskenkorva"+saadaan+tulokseksi:
Hakuarvo:+Koskenkorva
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Rivillä+nro+1329+virheellinen+määrä+(31)+sarakkeita
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
000132:+Koskenkorva+Viina
101328:+Koskenkorva+Viina
101316:+Koskenkorva+Viina++muovipullo
101327:+Koskenkorva+Viina++muovipullo
101334:+Koskenkorva+Viina++muovipullo
101333:+Koskenkorva+Viina++muovipullo
101338:+Koskenkorva+Viina++muovipullo
100147:+Koskenkorva+Vodka+40+%
100154:+Koskenkorva+Vodka+40+%++muovipullo
100153:+Koskenkorva+Vodka+40+%++muovipullo
148013:+Koskenkorva+Vodka+60+%++muovipullo
188477:+Koskenkorva+Vodka+Sauna+Barrel
100696:+Koskenkorva+Vodka+Vanilla++muovipullo
930498:+Koskenkorva+Viina+30+%++muovipullo
112646:+Koskenkorva+Viina+30%++muovipullo
112647:+Koskenkorva+Viina+30%++muovipullo
000102:+Koskenkorva+Viina+32+%
174956:+Koskenkorva+Viina+Omena++muovipullo
746804:+Koskenkorva+Pure+Apple++tölkki
772364:+Koskenkorva+Pure+Cranberry++tölkki
778134:+Koskenkorva+Pure+Strawberry+Lime++tölkki
200507:+Koskenkorva+The+Original+Strawberry++muovipullo
287437:+Koskenkorva+The+Original+Peach++muovipullo
197456:+Koskenkorva+Minttu++muovipullo
906276:+Koskenkorva+Lakritsi
003129:+Koskenkorva+Salmiakki
154656:+Koskenkorva+Salmiakki++muovipullo
154654:+Koskenkorva+Salmiakki++muovipullo
154653:+Koskenkorva+Salmiakki++muovipullo
>>>
Alko on uudistanut sivujaan ja taisi tuo API mennä samalla rikki.
Kiitos näistä. Toisaalla sain vinkin seuraavasta pätkästä, jolla saadaan Alkon txt-tiedosto käteväksi pandas-dataframeksi:
with urlopen('http://www.alko.fi/contentassets/df76c4146bb74ac08089e5bf610e6d67/fi/alkon-hinnasto-tekstitiedostona.txt') as f:
hinnasto = pd.read_table(io.BytesIO(f.read()), header=1, error_bad_lines=False)
Tuon avulla saa datan helposti käytettävään muotoon. Tuo error_bad_lines=False-optio korvaa tuon yllä nähdyn kikkailun txt-tiedoston puutteiden korjaamiseksi.
Toivottavasti Alko saisi jotain järkeä apiinsa, jotta samasta paikasta saisi ladattua hinnaston kuin myös haettua tuotteen saatavuuden eikä tätä kikkailua tarvitsisi tehdä. Mutta hyvää treeniä tämä on toki ja näitäkin vastauksia lukemalla olen oppinut.
Kiitos vaan itsellesi, tämä oli hyvä ja opettavainen avaus. Minäkin löysin vian ja nyt hakee Numeron, Hinnan, Nimen ja Tyypin.
Affiliate-Julkaisia
Linux Mint 18 Sarah
Xfce 64-bit