Mal wieder Website Parsing

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Herr Lehmann
User
Beiträge: 81
Registriert: Samstag 14. August 2010, 22:20

Hallo, ich möchte in einem Script checken ob ein Film in Deutschland oder USA DVD Premiere hatte.

Diese Info bekommt man über IMDB:

z.b. http://www.imdb.com/title/tt0425210/releaseinfo

Der Quelltext sieht auszugsweise so aus:

Code: Alles auswählen

<tr><td><b><a href="/calendar/?region=ES">Spain</a></b></td>
    <td align="right"><a href="/date/04-07/">7 April</a> <a href="/year/2006/">2006</a></td>

    <td></td></tr>

<tr><td><b><a href="/calendar/?region=US">USA</a></b></td>
    <td align="right"><a href="/date/04-07/">7 April</a> <a href="/year/2006/">2006</a></td>
    <td></td></tr>


<tr><td><b><a href="/calendar/?region=DE">Germany</a></b></td>
    <td align="right"><a href="/date/01-11/">11 January</a> <a href="/year/2007/">2007</a></td>

    <td> (DVD premiere)</td></tr>

<tr><td><b><a href="/calendar/?region=JP">Japan</a></b></td>
    <td align="right"><a href="/date/01-13/">13 January</a> <a href="/year/2007/">2007</a></td>
    <td></td></tr>
Bei dem Beispiel wäre es jetzt so, dass der Film in Deutschland DVD Premiere hatte, aber nicht in den USA.
Das möchte ich jetzt automatisch für verschiedene Filme überprüfen lassen.

Mir ist nicht ganz klar wie ich das mit Regex oder BeutifulSoup anstellen sollte, da ich ja nicht z.b. nach <td> (DVD premiere)</td></tr> suchen kann weil das auch bei anderen Ländern stehen könnte. Gutes Beispiel Dafür ist:
http://www.imdb.com/title/tt0403407/releaseinfo

Ich freue mich auf eure Lösungsvorschläge :D

Gruß
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Es gibt direkt ein ImDB-Modul für Python, wozu parst du die Webseite?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Herr Lehmann
User
Beiträge: 81
Registriert: Samstag 14. August 2010, 22:20

Die info bekomme ich nicht mit dem IMDB Modul
BlackJack

@Herr Lehmann: Am besten schaut man sich HTML/XML auch immer mal als Baumstruktur an und überlegt, wie man von einem Zweig den man einfach finden kann, zu dem mit der gewünschten Information gelangt. Man kann von einer Fundstelle ja auch einfach wieder im Baum nach oben wandern. Und eine interaktive Python-Shell ist bei so etwas auch immer recht hilfreich um sich dem Ergebnis zu nähern:

Code: Alles auswählen

In [67]: a = soup.find(text=' (DVD premiere)')

In [68]: a
Out[68]: u' (DVD premiere)'

In [69]: a.parent
Out[69]: <td> (DVD premiere)</td>

In [70]: a.parent.parent
Out[70]: 
<tr><td><b><a href="/calendar/?region=DE">Germany</a></b></td>
<td align="right"><a href="/date/01-11/">11 January</a> <a href="/year/2007/">2007</a></td>
<td> (DVD premiere)</td></tr>

In [71]: a.parent.parent.td
Out[71]: <td><b><a href="/calendar/?region=DE">Germany</a></b></td>

In [72]: a.parent.parent.td.find(text=True)
Out[72]: u'Germany'
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Der HTML-Parser von lxml und XPath-Ausdrücke wären mein Lösungsansatz.

Stefan
BlackJack

Eine Übersetzung in XPath:

Code: Alles auswählen

In [118]: doc.xpath('//td[text()=" (DVD premiere)"]/../td[1]//text()')
Out[118]: ['Germany']
Herr Lehmann
User
Beiträge: 81
Registriert: Samstag 14. August 2010, 22:20

danke für die vielen tipps ich schaue mal ob ich damit zurechtkomme
Herr Lehmann
User
Beiträge: 81
Registriert: Samstag 14. August 2010, 22:20

Ich bin gerade dabei mein Script zu erweitern,

dabei Stoß ich auf folgendes Problem:

Ich nutze die xpath Variante von Blackjack also z.b.
doc.xpath('//td[text()=" (DVD premiere)"]/../td[1]//text()')

jetzt möchte ich aber genau die Länder herausfinden wo KEINE Zusatzinfos in Klammern stehen.

Geht das überhaupt mit Xpath?

Nochmal auszugsweise der Quelltext:

Code: Alles auswählen

<tr><td><b><a href="/calendar/?region=ES">Spain</a></b></td>
    <td align="right"><a href="/date/04-07/">7 April</a> <a href="/year/2006/">2006</a></td>

    <td></td></tr>

<tr><td><b><a href="/calendar/?region=US">USA</a></b></td>
    <td align="right"><a href="/date/04-07/">7 April</a> <a href="/year/2006/">2006</a></td>
    <td></td></tr>


<tr><td><b><a href="/calendar/?region=DE">Germany</a></b></td>
    <td align="right"><a href="/date/01-11/">11 January</a> <a href="/year/2007/">2007</a></td>

    <td> (DVD premiere)</td></tr>

<tr><td><b><a href="/calendar/?region=JP">Japan</a></b></td>
    <td align="right"><a href="/date/01-13/">13 January</a> <a href="/year/2007/">2007</a></td>
    <td></td></tr>

Es geht also um die leeren <td></td>.

Jemand eine Idee?

Gruß

Herr Lehmann

P.S. Wenn man alte Beiträge hier nicht recyceln sollte, bitte den Beitrag in ein neues Thema splitten
BlackJack

Herr Lehmann: Das offensichtliche -- ``doc.xpath('//td[text()=""]/../td[1]//text()')`` -- hast Du schon probiert!?
Herr Lehmann
User
Beiträge: 81
Registriert: Samstag 14. August 2010, 22:20

Ja, habe ich probiert. Da bekomme ich nie ein Ergebnis.
BlackJack

@Herr Lehmann: Ich hatte nicht bedacht, dass Textknoten immer einen Inhalt haben müssen. :oops: Also muss man auf ``td``-Elemente testen die keinen Textknoten als Kind haben (getestet mit http://www.imdb.com/title/tt0403407/releaseinfo):

Code: Alles auswählen

In [304]: doc.xpath('//td[not(text())]/../td[1]//text()')
Out[304]: 
['France',
 'Netherlands',
 'Netherlands',
 'Canada',
 'USA',
 'USA',
 'Germany',
 'New Zealand',
 'Germany',
 'Japan',
 'New Zealand',
 'UK',
 'Russia',
 'Argentina',
 'Finland',
 'Spain',
 'Philippines',
 'Hungary',
 'Italy']
Das ist aber wesentlich zerbrechlicher als nach dem doch recht spezifischen Text ' (DVD premiere)' zu suchen. Soll heissen hier würde die Gefahr für falsche Treffer deutlich steigen.

Wenn Du mehrere Informationen aus dieser Tabelle benötigst, wäre es wohl sauberer erst die Tabelle komplett in eine Datenstruktur zu überführen, auf die Du dann die Abfragen machen kannst.
Herr Lehmann
User
Beiträge: 81
Registriert: Samstag 14. August 2010, 22:20

Deine Lösung bringt leider nicht das gewünschte ergebnis. Es werden dabei einfach nur alle Länder ausgegeben in denen der Film erschienen ist.

Das Resultat müsste sein:

Germany
Russia
Spain
Philippines
Italy
BlackJack

@Herr Lehmann: Heute ist wohl nicht mein Tag. :oops: So geht's:

Code: Alles auswählen

In [305]: doc.xpath('//td[not(node())]/../td[1]//text()')
Out[305]: ['Germany', 'Russia', 'Spain', 'Philippines', 'Italy']
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Ein Test mittels `string-length()` scheint zu klappen:

Code: Alles auswählen

In [10]: root.xpath('//td[not(string-length())]/../td[1]//text()')
Out[10]: ['Germany', 'Russia', 'Spain', 'Philippines', 'Italy']
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Herr Lehmann
User
Beiträge: 81
Registriert: Samstag 14. August 2010, 22:20

Ich danke euch! Habt ihr vl eine gute Referenz zu XPath? Ich finde da leider immer noch sehr lückenhafte Docus wie z.b.

http://lxml.de/xpathxslt.html

Aber jetzt komm ich erstmal weiter.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Sehr genau kannst du es hier nachlesen.
Das Leben ist wie ein Tennisball.
Antworten