Así que estoy interesado en this theory que si vas a un artículo al azar de Wikipedia, haz clic en el primer enlace no dentro de paréntesis repetidamente, en el 95% de los casos terminarás en el artículo sobre Philosophy.Obtener el primer enlace en un artículo de Wikipedia no entre paréntesis
que quería escribir un script en Python que hace el enlace de ir a buscar para mí y, al final, imprimir una lista agradable de los cuales fueron visitados artículos (linkA -> linkB -> linkC
), etc.
He conseguido el DOM HTML de las páginas web, y logró eliminar algunos enlaces innecesarios y la barra de descripción superior que lleva páginas de desambiguación. Hasta ahora, he llegado a la conclusión de que:
- El DOM comienza con la tabla que se ve a la derecha en algunas páginas, por ejemplo en Human. Queremos ignorar estos enlaces.
- Los elementos de enlace válidos todos tienen un elemento
<p>
algún lugar como su antepasado (más a menudo sus padres o abuelos si es dentro de una etiqueta<b>
o similar. No parece que la barra superior que conduce a páginas de desambiguación, para contener cualquier<p>
elementos. - enlaces no válidos contienen algunas palabras especiales seguido de dos puntos, por ejemplo
Wikipedia:
Hasta ahora, tan bueno, pero. que es el paréntesis que me reciben. En el artículo sobre Human por ejemplo, el primer eslabón paréntesis, no en el interior es "/ wiki/Species", pero el script encuentra "/ wiki/Taxonomy" que está dentro de ellos.
No tengo ni idea de cómo hacerlo desde el punto de vista programático, ya que tengo que buscar texto en una combinación de nodos principales/secundarios que puede no ser siempre el mismo. ¿Algunas ideas?
Mi código se puede ver a continuación, pero es algo que inventé muy rápido y no muy orgulloso. Sin embargo, se comenta, para que puedas ver mi línea de pensamiento (espero :)).
"""Wikipedia fun"""
import urllib2
from xml.dom.minidom import parseString
import time
def validWikiArticleLinkString(href):
""" Takes a string and returns True if it contains the substring
'/wiki/' in the beginning and does not contain any of the
"special" wiki pages.
"""
return (href.find("/wiki/") == 0
and href.find("(disambiguation)") == -1
and href.find("File:") == -1
and href.find("Wikipedia:") == -1
and href.find("Portal:") == -1
and href.find("Special:") == -1
and href.find("Help:") == -1
and href.find("Template_talk:") == -1
and href.find("Template:") == -1
and href.find("Talk:") == -1
and href.find("Category:") == -1
and href.find("Bibcode") == -1
and href.find("Main_Page") == -1)
if __name__ == "__main__":
visited = [] # a list of visited links. used to avoid getting into loops
opener = urllib2.build_opener()
opener.addheaders = [('User-agent', 'Mozilla/5.0')] # need headers for the api
currentPage = "Human" # the page to start with
while True:
infile = opener.open('http://en.wikipedia.org/w/index.php?title=%s&printable=yes' % currentPage)
html = infile.read() # retrieve the contents of the wiki page we are at
htmlDOM = parseString(html) # get the DOM of the parsed HTML
aTags = htmlDOM.getElementsByTagName("a") # find all <a> tags
for tag in aTags:
if "href" in tag.attributes.keys(): # see if we have the href attribute in the tag
href = tag.attributes["href"].value # get the value of the href attribute
if validWikiArticleLinkString(href): # if we have one of the link types we are looking for
# Now come the tricky parts. We want to look for links in the main content area only,
# and we want the first link not in parentheses.
# assume the link is valid.
invalid = False
# tables which appear to the right on the site appear first in the DOM, so we need to make sure
# we are not looking at a <a> tag somewhere inside a <table>.
pn = tag.parentNode
while pn is not None:
if str(pn).find("table at") >= 0:
invalid = True
break
else:
pn = pn.parentNode
if invalid: # go to next link
continue
# Next we look at the descriptive texts above the article, if any; e.g
# This article is about .... or For other uses, see ... (disambiguation).
# These kinds of links will lead into loops so we classify them as invalid.
# We notice that this text does not appear to be inside a <p> block, so
# we dismiss <a> tags which aren't inside any <p>.
pnode = tag.parentNode
while pnode is not None:
if str(pnode).find("p at") >= 0:
break
pnode = pnode.parentNode
# If we have reached the root node, which has parentNode None, we classify the
# link as invalid.
if pnode is None:
invalid = True
if invalid:
continue
###### this is where I got stuck:
# now we need to look if the link is inside parentheses. below is some junk
# for elem in tag.parentNode.childNodes:
# while elem.firstChild is not None:
# elem = elem.firstChid
# print elem.nodeValue
print href # this will be the next link
newLink = href[6:] # except for the /wiki/ part
break
# if we have been to this link before, break the loop
if newLink in visited:
print "Stuck in loop."
break
# or if we have reached Philosophy
elif newLink == "Philosophy":
print "Ended up in Philosophy."
break
else:
visited.append(currentPage) # mark this currentPage as visited
currentPage = newLink # make the the currentPage we found the new page to fetch
time.sleep(5) # sleep some to see results as debug
Puede probar la interfaz más rica proporcionada por lxml. Eso le permite usar xpath y un montón de otras cosas. – Marcin
Mientras estamos en las recomendaciones, me gustaría dejar beautifulsoup como un nombre probablemente útil aquí. – marue
@marue Dos grandes sabores que saben muy bien juntos: ¡lxml tiene un backend precioso! – Marcin