Nettsider kan vera ein stor kjelde til informasjon, og er som oftast enkle å lesa
for det blotte auge. Diverre er ikkje dette tilfellet om ein vil lesa
sidene maskinelt.
Når eg vanligvis skal henta ut informasjon av tekstfilar, kan ein
nytta små, nyttige programmer som sed, grep osb til å henta ut den
informasjonen ein vil ha tak i. Prøver ein dette på ymse nettsider, ser
ein fort at kjeldekoda ikkje vart laga for å lesast direkte, den er
dårleg organisert med enten sinnsjukt lange linjer, eller overdreven
bruk av linjeskift. Då kjem dei tekstbaserte programma til kort. Ein må
kunne tolka html-koden som det hierarkiet av informasjon ho er, ikkje
som rein tekst. Men som ein ofte finn ut når ein nyttar fri
programvare; har du eit problem, er det ofte at nokon andre har løyst
det før deg. Når eg skulle spore ei pakke i posten, fann eg derfor fram
ein python-modul Odin hadde tipsa meg om tidlegare, nemleg Beautiful Soup
Beautiful Soup gjer oss eit syntakstre som gjer at me kan henta ut all informasjonen me vil frå eit nettsted, med særs få linjer kode. Det har ein god dokumentasjon,
men samtidig er det så enkelt å nytta at ein får ut det ein vil med
berre et par metodekall. Med nokre linjer python fekk eg skreve
programmet eg ønska. Det gjer ikkje noko anna enn å skriva ut den, og
berre den, informasjonen eg ville ha ut. Kan ein derimot
grunnprinsippa, er det ikkje stort meir som kreves for å skriva til
døme ein fullblods innsamlar av kva enn informasjon som fins på nettet.
Postens sporingssystem ser heilt greit ut, mens koden bak ser slik ut (utdrag):
<tr> <td> 26.04.08 </td> <td> 10.43 </td> <td> UTLEVERT </td> <td> 0515 OSLO <a href="http://kart.posten.no/default.aspx?visible=bedrift;pib;post;kasser&id=" target="_blank"> </a> </td> </TR>
Etter å ha leika litt med Beautiful Soup, får eg derimot eit kort og konsist svar i terminalen:
Slik gjer du det
For å komme igang med Beautiful Soup, lastar du berre ned pythonmodulen herifrå,
og du er klar. For å tolka ein nettside, lager du eit objekt av
BeautifulSoup-klassen, og gjer den nettsiden som argument. Dette kan
til døme vera ein streng med html-koden du vil tolka, eller ein side
henta via urllib2, slik eg gjer:
from BeautifulSoup import BeautifulSoup
import urllib2
posten = “http://sporing.posten.no/sporing/KMSporingslink.aspx?PackageNumber=<DITTPAKKENR>”
page = urllib2.urlopen(posten)
parser = BeautifulSoup(page)
Når objektet er laga, kan du nytta ein rekke metodar til å henta ut informasjon frå siden, sjå dokumentasjonen.
Eg fann ut at findAll() gjorde det eg ville; den gjev deg ein liste med
dei delene av treet som passer med dei argumentene du gjev han. Til
døme gjev findAll(’table’) ein liste over alle tabellane på siden. Ein
kan óg begrensa søket på atributter som findAll(”foo”, align=”center”),
css-klasser med findAll(”foo”, { “class” : “foo” }), evt berre
findAll(”foo”, “foo”) og tekstinnhald med findAll(”foo”, text=”bar”).
Merk berre at teksten er eksakt, så om ein vil ha eit lausare søk må
ein nytta ein regex.
Om du får feilmeldinga «’ascii’ codec can’t encode character ‘x’ in position y: ordinal not in range(128)», sjå feilsøking i dokumentasjonen.
Ettersom eg berre vil vita om pakken kan hentast, hentar eg ut alle
tabellane med findAll(), men tek berre vare på den siste, som har
informasjonen eg treng.
Det som er veldig kjekt, er at objektene findAll() gjev deg, har dei
samme metodane som BeautifulSoup-objektet. Dermed er det veldig enkelt
å iterera over tabellar, rader og kolonner, slik eg gjev i
posten-skriptet:
# we only care about the last section
table = parser.findAll(‘table’)[-1]
for tr in table.findAll(‘tr’):
# get table cells and strip whitespace
td = [td.contents[0].strip() for td in tr.findAll(‘td’)]
#finally, print
print “%-9s %-6s %-25s %-15s” % (td[0], td[1], td[2], td[3])
Det som er verdt å merka seg, er at eg nyttar td.contents[0] til å
henta ut innhaldet i html-taggene. Sålenge taggane berre inneheld
tekst, kan ein nytta td.string, men siden den fjerde kolonnen (sjå
skjermskuddet) inneheld ein lenke (og dermed ein <a> tag), nyttar
eg contents[0] til å henta ut teksten, som ligg først.
Posten-skriptet finn du her.

