2009-09-08 14 views
7

Ich versuche, einen Web-Scraper, der eine Web-Seite von Publikationen analysieren und extrahieren die Autoren zu machen. Die Skelett-Struktur der Web-Seite ist die folgende:Python Web Scraping mit HTML-Tags mit Attributen

<html> 
<body> 
<div id="container"> 
<div id="contents"> 
<table> 
<tbody> 
<tr> 
<td class="author">####I want whatever is located here ###</td> 
</tr> 
</tbody> 
</table> 
</div> 
</div> 
</body> 
</html> 

Ich habe versucht, weit so BeautifulSoup und lxml zu verwenden, um diese Aufgabe zu erfüllen, aber ich bin nicht sicher, wie die beiden div-Tags zu handhaben und td-Tag, weil sie Attribute haben. Außerdem bin ich mir nicht sicher, ob ich mich mehr auf BeautifulSoup oder lxml oder eine Kombination von beiden verlassen sollte. Was soll ich machen?

Im Moment sieht mein Code wie das, was unten ist:

import re 
    import urllib2,sys 
    import lxml 
    from lxml import etree 
    from lxml.html.soupparser import fromstring 
    from lxml.etree import tostring 
    from lxml.cssselect import CSSSelector 
    from BeautifulSoup import BeautifulSoup, NavigableString 

    address='http://www.example.com/' 
    html = urllib2.urlopen(address).read() 
    soup = BeautifulSoup(html) 
    html=soup.prettify() 
    html=html.replace('&nbsp', '&#160') 
    html=html.replace('&iacute','&#237') 
    root=fromstring(html) 

Ich weiß, dass viele der Import-Anweisungen überflüssig sein können, aber ich nur kopiert, was ich zur Zeit in mehr Quelldatei hatte.

EDIT: Ich nehme an, dass ich dies nicht ganz klar gemacht habe, aber ich habe mehrere Tags in der Seite, die ich kratzen möchte.

Antwort

11

Es ist nicht mir aus Ihrer Frage klar, warum Sie über die div Tags kümmern müssen - was gerade zu tun:

soup = BeautifulSoup(html) 
thetd = soup.find('td', attrs={'class': 'author'}) 
print thetd.string 

Auf der HTML Sie geben, laufen diese emittiert genau:

####I want whatever is located here ### 

was scheint, was Sie wollen. Vielleicht können Sie genauer angeben, was Sie brauchen, und dieses super-einfache Snippet nicht tun - mehrere td Tags der gesamten Klasse author von denen Sie berücksichtigen müssen (alle? Nur einige? Welche?), Möglicherweise fehlen alle solche Tags (was möchten Sie in diesem Fall tun) und dergleichen. Es ist schwer zu sagen, was genau deine Spezifikationen sind, nur aus diesem einfachen Beispiel und überreichlichen Code ;-).

bearbeiten: wenn, nach dem neuesten Kommentar des OP gibt es mehr solche td-Tags, ein pro Autor:

thetds = soup.findAll('td', attrs={'class': 'author'}) 
for thetd in thetds: 
    print thetd.string 

... also nicht viel schwieriger überhaupt -)

+0

Danke, Alex. Ich habe mehrere Autoren auf der Seite, also werde ich mehrere td-Tags haben. Wie iteriere ich über jeden von ihnen? – GobiasKoffi

1

BeautifulSoup ist sicherlich der kanonische HTML-Parser/Prozessor. Aber wenn Sie nur diese Art von Snippet haben, müssen Sie, anstatt ein ganzes hierarchisches Objekt zu erstellen, das den HTML-Code darstellt, das Definieren von führenden und nachfolgenden HTML-Tags als Teil des Erstellens eines größeren Suchausdrucks:

from pyparsing import makeHTMLTags, withAttribute, SkipTo 

author_td, end_td = makeHTMLTags("td") 

# only interested in <td>'s where class="author" 
author_td.setParseAction(withAttribute(("class","author"))) 

search = author_td + SkipTo(end_td)("body") + end_td 

for match in search.searchString(html): 
    print match.body 

Die Funktion makeHTMLTags von Pyparsing kann viel mehr als nur die Ausdrücke "<tag>" und "</tag>" ausdrücken.Es behandelt auch:

  • hülsenlose Anpassung von Tags
  • "<tag/>" Syntax
  • null oder mehr Attribut in dem Starttag
  • Attribute definiert in beliebiger Reihenfolge
  • Attributnamen mit Namensräumen
  • Attributwerte in einfachen, doppelten oder keinen Anführungszeichen
  • Leerzeichen zwischen Tag und Symbolen oder Attributnamen '=', an d Wert
  • Attribute sind zugänglich nach wie Namen Ergebnisse Parsen

Dies sind die häufigen Fehler, wenn für HTML Schaben mit einem regex berücksichtigen.

6

oder Sie könnten pyquery verwenden, da BeautifulSoup ist nicht mehr aktiv gepflegt, siehe http://www.crummy.com/software/BeautifulSoup/3.1-problems.html

zuerst installieren pyquery mit

easy_install pyquery 

dann könnte Ihr Skript so einfach sein wie

from pyquery import PyQuery 
d = PyQuery('http://mywebpage/') 
allauthors = [ td.text() for td in d('td.author') ] 

pyquery verwendet die CSS-Selektor-Syntax, die von jQuery her bekannt ist und die ich intuitiver finde als die von BeautifulSoup. Es verwendet Lxml darunter und ist viel schneller als BeautifulSoup. Aber BeautifulSoup ist pure Python und funktioniert somit auch in der App-Engine von Google

5

Die lxml-Bibliothek ist jetzt der Standard für das Parsen von HTML in Python. Das Interface kann zunächst peinlich wirken, aber es ist sehr nützlich für das, was es tut.

Sie sollten die Bibliothek die XML-Spezialisierung behandeln lassen, wie diese masked & entities;

import lxml.html 

html = """<html><body><div id="container"><div id="contents"><table><tbody><tr> 
      <td class="author">####I want whatever is located here, eh? &iacute; ###</td> 
      </tr></tbody></table></div></div></body></html>""" 

root = lxml.html.fromstring(html) 
tds = root.cssselect("div#contents td.author") 

print tds   # gives [<Element td at 84ee2cc>] 
print tds[0].text # what you want, including the 'í'