2011. május 23.

Wikipedia API – sok szöveg, gyorsan, tisztán

Már volt szó korábban az API-k használatáról a New York Times és a Guardian adatai kapcsán. Az API (alkalmazásprogramozási interfész) egy olyan szabványosított felület, amin keresztül hozzá lehet férni egy másik program funkcióihoz – anélkül, hogy részletesen ismernünk kéne azok működését. Minket ez elsősorban a webes alkalmazások miatt érdekel : sok oldal lehetővé teszi, hogy megkerülve a webes felületet férjünk hozzá az adatokhoz, vagy akár interakcióba lépjünk velük (közismert példa a facebook-os alkalmazás).
A Wikipedia is szabadon hozzáférhető a web megkerülésével, és ez valójában mindenkinek jó: a fejlesztők pontosan olyan adatokat kapnak, amilyet kívánnak, a Wikipedia szervereinek pedig nem kell azon erőlködniük, hogy emberi fogyasztásra alkalmassá tegyék az adathalmazt (ezzel csökken a terhelés). 


A Wikipedia MediaWiki szoftveren fut, így az ő API-ját lehet használni (dokumentáció itt és itt ) Ez egy elég okos rendszer, mi csak a legegyszerűbb dolgot fogjuk megcsinálni: kiolvasunk egy oldalt, nyers szöveg formátumban (emlékezzünk, hogy a Wikipedia alapból formázott HTML-t ad).

Ez egy egyszerű HTTP híváson keresztül történik:

Az összes Wikipedián (így a magyaron is) az API-motor a fenti címen található (mutatis mutandis). A bűvös szó itt az action=raw paraméter, ami HTML helyett “nyers” szöveget szolgáltat. Csakhogy, a kapott nyers szöveg nem igazán nyers:


'''Elephants''' are large land [[mammal]]s in two [[Genus|genera]] of the [[family (biology)|family]]


Így ezt is tisztítani kell, azonban ez formátum sokkal egyszerűbb, mint egy HTML. Lássuk, hogyan valósítjuk meg python-ban a tisztítást:


# -*- coding: utf-8 -*-
from __future__ import division
import re
import urllib2
from urllib2 import HTTPError
import sys
def url_olvas(url):
opener = urllib2.build_opener()
opener.addheaders = [('User-agent', 'Mozilla/5.0')]
try:
infile = opener.open(url)
except HTTPError, e:
print e.code
exit()
page = infile.read()
sorok=re.split("\n",page)
page="<ujsor>".join(sorok)
return page
def wiki_olvas_main(args):
page=url_olvas("http://en.wikipedia.org/w/index.php?title="+args[1]+"&action=raw")
while True:
m=re.match("(.*?)\{\{.*?(\{\{.*?\}\}.*?){0,}\}\}(.*)",page)
if (m): page=m.group(1)+""+m.group(3)
else: break
page=re.sub("{.*?}","",page)
page=re.sub("<ref.*?>.*?</ref>","",page)
page=re.sub("\[\[File:(.*?)(\[\[.*?\]\].*?){0,}\]\]","",page)
page=re.sub("\[\[Image:(.*?)(\[\[.*?\]\].*?){0,}\]\]","",page)
while True:
m=re.match("(.*?)'''(.*?)'''(.*)",page)
if (m): page=m.group(1)+"<b>"+m.group(2)+"</b>"+m.group(3)
else: break
while True:
m=re.match("(.*?)''(.*?)''(.*)",page)
if (m): page=m.group(1)+"<i>"+m.group(2)+"</i>"+m.group(3)
else: break
while True:
m=re.match("(.*?)====(.*?)====(.*)",page)
if (m): page=m.group(1)+"<h4>"+m.group(2)+"</h4>"+m.group(3)
else: break
while True:
m=re.match("(.*?)===(.*?)===(.*)",page)
if (m): page=m.group(1)+"<h3>"+m.group(2)+"</h3>"+m.group(3)
else: break
while True:
m=re.match("(.*?)==(.*?)==(.*)",page)
if (m): page=m.group(1)+"<br><h2>"+m.group(2)+"</h2><br>"+m.group(3)
else: break
while True:
m=re.match("(.*)\[\[(.*?)\|(.*?)\]\](.*)",page)
if (m): page=m.group(1)+"<a href=\"http://en.wikipedia.org/wiki/"+m.group(2)+"\">"+m.group(3)+"</a>"+m.group(4)
else: break
while True:
m=re.match("(.*)\[\[(.*?)\]\](.*)",page)
if (m): page=m.group(1)+"<a href=\"http://en.wikipedia.org/wiki/"+m.group(2)+"\">"+m.group(2)+"</a>"+m.group(3)
else: break
page=re.sub("<ujsor>","\n",page)
print "<html><body><h1>"
print args[1]
print "</h1><br>"
print page
print "</body></html>"
wiki_olvas_main(sys.argv)
view raw wikiOlvas.py hosted with ❤ by GitHub


A program HTML formátumban adja vissza a megtisztított szöveget (így jobban áttekinthetők a linkek, címek, stb). Ez természetesen a megfelelő részek egyszerű átírásával/törlésével pillanatok alatt átalakítható. A jelenlegi változat parancsorból, paraméterként olvassa be a kívánt oldalt, vagyis elindítani így tudjuk (linux parancssorból):

python wikiOlvas.py Humanities > eredmeny.html

Az url_olvas() funkció kizárólag a HTML kérést bonyolítja, míg a wiki_olvas_main() végzi a tisztítást. A fő program funkcióba szervezésének az oka csupán annyi, hogy így a kódot modulként is használhatjuk ( from wikiOlvas import * ).


A program tehát csak annyit csinál, hogy eltávolít a HTML kérésből beérkező adatokból minden “nem szöveg”-nek értékelt adatot (képeket, hivatkozásokat, stb.) Ezek jellemzően kapcsos vagy szögletes zárójelek közé vannak zárva. Az ilyen munkához a legjobb ötlet – szerintem – a reguláris kifejezések (regular expression) használata. Ezek legfőbb erőssége abban rejlik, hogy a “mit-cserélj-mire” jellegű kifejezések nagyon tág keretek között írhatók le (ezt használom például a linkek feldolgozásánál, ahol úgy kell kivenni egy részt a szövegfolyamból, hogy annak egy része mégis megmaradjon). Egyébként, reguláris kifejezések írása külön művészet, aminek az alapjaival mindenképpen érdemes megismerkedni, ha szövegekkel dolgozunk.

Kis programunk tehát megtisztítja az API-tól lekért “nyers” szöveget (és azt sem tökéletesen, mert a Wikipedia belső formázási szabályai is elég bonyolultak). Ennél az API persze sokkal többre képes: lekérhetünk egyszerre több oldalt is, számos formátumban (mondjuk, XML-ben), vagy akár API-n át bele is írhatunk a Wikipédiába. A mi programunk egyik érdekes, és elég könnyen megvalósítható fejlesztése lehet a linkeket összegyűjtő, majd azokon (rekurzívan) tovább haladó változat. Így gyűjthetünk sok-sok szöveget, számolhatunk hivatkozásokat, vagy akár rajzolhatunk hálókat az egymáshoz kapcsolódó témákról – amit csak nem szégyenlünk.

Az API csak örül, hisz éppen erre való.


Nincsenek megjegyzések: