2012-09-03 27 views
8

Próbuję napisać program python, który może przeszukać wikipedia dla dat narodzin i śmierci dla ludzi.Parse daty urodzenia i śmierci z Wikipedii?

Na przykład urodził się Albert Einstein: 14 marca 1879; zmarł: 18 kwietnia 1955.

Zacząłem Fetch a Wikipedia article with Python

import urllib2 
opener = urllib2.build_opener() 
opener.addheaders = [('User-agent', 'Mozilla/5.0')] 
infile = opener.open('http://en.wikipedia.org/w/api.php?action=query&prop=revisions&rvprop=content&rvsection=0&titles=Albert_Einstein&format=xml') 
page2 = infile.read() 

Działa to tak daleko, jak to idzie. page2 to reprezentacja xml sekcji ze strony wikipedii Alberta Einsteina.

I spojrzałem na ten samouczek, teraz, gdy mam stronę w formacie xml ... http://www.travisglines.com/web-coding/python-xml-parser-tutorial, ale nie rozumiem, jak uzyskać informacje, które chcę (daty urodzenia i śmierci) z xml. Czuję, że muszę być blisko, a jednak nie mam pojęcia, jak przejść dalej.

EDIT

Po kilku odpowiedzi, mam zainstalowane BeautifulSoup. Jestem teraz na etapie, na którym można drukować:

import BeautifulSoup as BS 
soup = BS.BeautifulSoup(page2) 
print soup.getText() 
{{Infobox scientist 
| name  = Albert Einstein 
| image  = Einstein 1921 portrait2.jpg 
| caption  = Albert Einstein in 1921 
| birth_date = {{Birth date|df=yes|1879|3|14}} 
| birth_place = [[Ulm]], [[Kingdom of Württemberg]], [[German Empire]] 
| death_date = {{Death date and age|df=yes|1955|4|18|1879|3|14}} 
| death_place = [[Princeton, New Jersey|Princeton]], New Jersey, United States 
| spouse  = [[Mileva Marić]] (1903–1919)<br>{{nowrap|[[Elsa Löwenthal]] (1919–1936)}} 
| residence = Germany, Italy, Switzerland, Austria, Belgium, United Kingdom, United States 
| citizenship = {{Plainlist| 
* [[Kingdom of Württemberg|Württemberg/Germany]] (1879–1896) 
* [[Statelessness|Stateless]] (1896–1901) 
* [[Switzerland]] (1901–1955) 
* [[Austria–Hungary|Austria]] (1911–1912) 
* [[German Empire|Germany]] (1914–1933) 
* United States (1940–1955) 
}} 

więc znacznie bliżej, ale wciąż nie wiem jak zwrócić death_date w tym formacie. O ile nie zacznę analizować danych za pomocą re? Mogę to zrobić, ale czuję, że używałbym niewłaściwego narzędzia do tej pracy.

+0

Parser XML nie pomoże ci dalej. Przeczytaj, co mówi JBernardo: pobierz dane w formacie json i użyj dedykowanego parsera MW. – georg

+0

Dołączyłem kompletny kod zarówno z/bez użycia 're' do parsowania. –

+0

Nie próbuj podszywać się pod przeglądarkę użytkownika. Zgodnie z [polityką użytkownika Wikimedia User-Agent] (http://meta.wikimedia.org/wiki/User-Agent_policy) powinieneś użyć "informacyjnego ciągu znaków użytkownika z danymi kontaktowymi". – svick

Odpowiedz

7

Można rozważyć użycie biblioteki, takiej jak BeautifulSoup lub lxml, aby przeanalizować odpowiedź html/xml.

Możesz również rzucić okiem na Requests, który ma znacznie czystszy API do wysyłania zapytań.


Oto kod roboczych za pomocą Requests, BeautifulSoup i re, prawdopodobnie nie jest najlepszym rozwiązaniem, ale to jest bardzo elastyczny i może być przedłużony o podobnych problemach:

import re 
import requests 
from bs4 import BeautifulSoup 

url = 'http://en.wikipedia.org/w/api.php?action=query&prop=revisions&rvprop=content&rvsection=0&titles=Albert_Einstein&format=xml' 

res = requests.get(url) 
soup = BeautifulSoup(res.text, "xml") 

birth_re = re.search(r'(Birth date(.*?)}})', soup.revisions.getText()) 
birth_data = birth_re.group(0).split('|') 
birth_year = birth_data[2] 
birth_month = birth_data[3] 
birth_day = birth_data[4] 

death_re = re.search(r'(Death date(.*?)}})', soup.revisions.getText()) 
death_data = death_re.group(0).split('|') 
death_year = death_data[2] 
death_month = death_data[3] 
death_day = death_data[4] 

Per Sugestia @ JBernardo korzystająca z danych JSON i mwparserfromhell, lepsza odpowiedź dla tego konkretnego przypadku użycia:

import requests 
import mwparserfromhell 

url = 'http://en.wikipedia.org/w/api.php?action=query&prop=revisions&rvprop=content&rvsection=0&titles=Albert_Einstein&format=json' 

res = requests.get(url) 
text = res.json["query"]["pages"].values()[0]["revisions"][0]["*"] 
wiki = mwparserfromhell.parse(text) 

birth_data = wiki.filter_templates(matches="Birth date")[0] 
birth_year = birth_data.get(1).value 
birth_month = birth_data.get(2).value 
birth_day = birth_data.get(3).value 

death_data = wiki.filter_templates(matches="Death date")[0] 
death_year = death_data.get(1).value 
death_month = death_data.get(2).value 
death_day = death_data.get(3).value 
+1

+1 dla BeautifulSoup. Właśnie tego potrzebuje OP. –

+1

Czy sprawdziłeś dane, aby sprawdzić, czy parser HTML/XML pomoże? Wskazówka: Nie będzie to – JBernardo

+0

@JBernardo Masz rację, zawartość jest w tym samym znaczniku XML. Chociaż wygląda na to, że format JSON ma ten sam problem. Sądzę, że jeden z analizowanych parserów przeanalizowałby dane w tagu? –

5

Po pierwsze: Interfejs API Wikipedii umożliwia korzystanie z formatu JSON zamiast XML, co znacznie ułatwia pracę.

Po drugie: Nie ma potrzeby korzystania w ogóle z parserów HTML/XML (zawartość nie jest HTML ani kontener musi być). To, co musisz parsować, to ten format Wiki wewnątrz znaczników "rewizji" JSON-a.

sprawdzić niektóre parser Wiki here


Co wydaje się być tu mylące jest to, że API pozwala wnioskować określonym formacie (XML lub JSON), ale to jest tylko pojemnik na tekst w rzeczywistym Format chcesz przeanalizować:

Ta jedna: {{Birth date|df=yes|1879|3|14}}

z jednym z analizatorów określonych w linku powyżej, będziesz w stanie to zrobić.

+0

OK, więc mogę go odczytać jako JSON: 'infile = opener.open ('http://en.wikipedia.org/w/api.php?action=query&prop=revisions&rvprop=content&rvsection=0&titles=Albert_Einstein&format=json') ' Patrząc na parsery Wiki, z którymi się łączyłeś, widzę mnóstwo, które są XML/HTML, ale nie wymieniono JSON. Czy masz zalecany? – JBWhitmore

+0

@JBPodobnie moduł 'json' jest dostarczany z Pythonem. Jest ** tylko ** pojemnikiem na prawdziwe dane, które chcesz przeanalizować. Te dane nie są w formacie XML, HTML ani JSON. Jest to w pewnym formacie Wiki. – JBernardo

+0

@JBWhitmore Chcesz przeanalizować dane tego rodzaju: '{{Data urodzenia | df = yes | 1879 | 3 | 14}}} i pomoże ci jeden z modułów w linku. – JBernardo

4

Najpierw użyj pywikipedia. Pozwala na wyszukiwanie tekstu artykułu, parametrów szablonu itp. Za pomocą interfejsu abstrakcyjnego wysokiego poziomu. Po drugie, chciałbym pójść z szablonem Persondata (spójrz na koniec artykułu). Ponadto, na dłuższą metę, być może zainteresuje Cię Wikidata, co zajmie kilka miesięcy, ale sprawi, że większość metadanych w artykułach Wikipedii będzie łatwo sprawdzana.

1

Szablon persondata jest obecnie uznany za przestarzały i należy zamiast niego uzyskać dostęp do Wikidata. Zobacz Wikidata:Data access. Moja wcześniejsza (teraz przestarzała) odpowiedź z 2012 roku wyglądała następująco:

Co należy zrobić, to przeanalizować szablon {{persondata}} znaleziony w większości artykułów biograficznych. Istnieje existing tools for easily extracting such data programmatically, z twoją obecną wiedzą i innymi przydatnymi odpowiedziami, które na pewno możesz wykonać.

+0

Za to, co warto, na wypadek, gdyby ktoś zapisał komuś innemu kliknięcie, Persondata wydaje się być przestarzała. Łącze mówi, że "... zostało usunięte. Od tej chwili takie dane powinny zostać dodane z cytatem do Wikidata". –

+0

Rzeczywiście. Będę edytować moją odpowiedź. –