python beutifulsoup extract numbers, hvordan?

Dette forum bruges på EGET ANSVAR til at lege med scripts og andre ting med risiko for at beskadige sit eget og andres systemer.
gtr

python beutifulsoup extract numbers, hvordan?

Indlæg af gtr »

coursera
geany
python 2

I en kursusrække er jeg kommet til en opgave, som jeg ikke kan finde svaret på. Jeg har spurgt på kursets forum. Forummet virker efter min mening ikke hensigtsmæssigt. Når jeg paster den kode, jeg har skrevet og som ikke virker, bliver den slettet. En anden kursusdeltager svarede på et spørgsmål fra mig. Det blev også delvis slettet. Derfor spørger jeg her. Man skal hente data fra en url. Når man har hentet data'ene, skal man extract numbers og summere dem. Jeg kan hente data'ene, men ikke extract dem og summere dem. Man underviser med videoer og denne bog. http://do1.dr-chuck.com/py4inf/EN-us/book.pdf. Opgaven hører til kap 12. Der er blevet undervist op til kap 12.

Den her kode har jeg skrevet.

Kode: Vælg alt

import re
import urllib
from BeautifulSoup import *
url = 'http://python-data.dr-chuck.net/comments_42.html'
html = urllib.urlopen(url).read()
soup = BeautifulSoup(html)
tags = soup('tr')
print tags


Når koden startes i geany, fremkommer dette i command line.

Kode: Vælg alt

[<tr>
<td>Name</td><td>Comments</td>
</tr>, <tr><td>Leven</td><td><span class="comments">100</span></td></tr>, <tr><td>Mahdiya</td><td><span class="comments">97</span></td></tr>, <tr><td>Ajayraj</td><td><span class="comments">87</span></td></tr>, <tr><td>Lillian</td><td><span class="comments">86</span></td></tr>, <tr><td>Aon</td><td><span class="comments">86</span></td></tr>, <tr><td>Ruaraidh</td><td><span class="comments">78</span></td></tr>, <tr><td>Gursees</td><td><span class="comments">75</span></td></tr>, <tr><td>Emmanuel</td><td><span class="comments">74</span></td></tr>, <tr><td>Christy</td><td><span class="comments">72</span></td></tr>, <tr><td>Annoushka</td><td><span class="comments">72</span></td></tr>, <tr><td>Inara</td><td><span class="comments">72</span></td></tr>, <tr><td>Caite</td><td><span class="comments">70</span></td></tr>, <tr><td>Rosangel</td><td><span class="comments">70</span></td></tr>, <tr><td>Iana</td><td><span class="comments">66</span></td></tr>, <tr><td>Anise</td><td><span class="comments">66</span></td></tr>, <tr><td>Jaosha</td><td><span class="comments">65</span></td></tr>, <tr><td>Cadyn</td><td><span class="comments">65</span></td></tr>, <tr><td>Edward</td><td><span class="comments">63</span></td></tr>, <tr><td>Charlotte</td><td><span class="comments">61</span></td></tr>, <tr><td>Sammy</td><td><span class="comments">60</span></td></tr>, <tr><td>Zarran</td><td><span class="comments">60</span></td></tr>, <tr><td>Rowen</td><td><span class="comments">59</span></td></tr>, <tr><td>Stanislaw</td><td><span class="comments">59</span></td></tr>, <tr><td>Maighdlin</td><td><span class="comments">57</span></td></tr>, <tr><td>Connan</td><td><span class="comments">56</span></td></tr>, <tr><td>Warrick</td><td><span class="comments">54</span></td></tr>, <tr><td>Diya</td><td><span class="comments">52</span></td></tr>, <tr><td>Lawson</td><td><span class="comments">52</span></td></tr>, <tr><td>Wu</td><td><span class="comments">51</span></td></tr>, <tr><td>Irmak</td><td><span class="comments">47</span></td></tr>, <tr><td>Emilija</td><td><span class="comments">47</span></td></tr>, <tr><td>Kayda</td><td><span class="comments">41</span></td></tr>, <tr><td>Ellenor</td><td><span class="comments">41</span></td></tr>, <tr><td>Kyra</td><td><span class="comments">41</span></td></tr>, <tr><td>Nikita</td><td><span class="comments">38</span></td></tr>, <tr><td>Kaelah</td><td><span class="comments">35</span></td></tr>, <tr><td>Meko</td><td><span class="comments">32</span></td></tr>, <tr><td>Marissa</td><td><span class="comments">31</span></td></tr>, <tr><td>Ayat</td><td><span class="comments">24</span></td></tr>, <tr><td>Sali</td><td><span class="comments">19</span></td></tr>, <tr><td>Hashem</td><td><span class="comments">19</span></td></tr>, <tr><td>Tygan</td><td><span class="comments">18</span></td></tr>, <tr><td>Rioden</td><td><span class="comments">17</span></td></tr>, <tr><td>Cruiz</td><td><span class="comments">16</span></td></tr>, <tr><td>Caoilfinn</td><td><span class="comments">13</span></td></tr>, <tr><td>Ewen</td><td><span class="comments">8</span></td></tr>, <tr><td>Baighley</td><td><span class="comments">7</span></td></tr>, <tr><td>Ramone</td><td><span class="comments">1</span></td></tr>, <tr><td>Kyran</td><td><span class="comments">1</span></td></tr>, <tr><td>Noelani</td><td><span class="comments">1</span></td></tr>]


Hvordan extract jeg numbers? Er det ikke en string?
zob
Redaktør
Indlæg: 4430
Tilmeldt: 6. jan 2009, 22:01
Geografisk sted: København

Re: python beutifulsoup extract numbers, hvordan?

Indlæg af zob »

Kode: Vælg alt

import urllib
from bs4 import BeautifulSoup

url = 'http://python-data.dr-chuck.net/comments_42.html'
html = urllib.urlopen(url).read()
soup = BeautifulSoup(html)
spans = soup.find_all('span', attrs={'class':'comments'})

result = 0
for span in spans:
    result += int(span.string)
print '{}{}'.format ("Summen af tallene er: ", result)

Resultatet bliver:

Kode: Vælg alt

Summen af tallene er: 2482


Du kan finde noget dokumentation her: http://www.crummy.com/software/Beautifu ... uick-start

Bemærk jeg her bruger BeautifulSoup4 (jeg kunne ligeså godt læse op på den seneste nu jeg var ved det), og det virker vist ikke med ældre versioner, så bemærk ændringen i import statements også.

Du extracter ved at køre find_all() på den soup du allerede selv havde lavet. Bemærk du kan trække alt af en bestemt klasse ud. Et enkelt span indeholder og tags, derfor nøjes vi med at addere .string feltet i loopet (et enkelt span.string felt indeholder et enkelt tal f.eks. 100, men det er en string, derfor caster vi til int ved at sætte span.string i int(span.string))
gtr

Re: python beutifulsoup extract numbers, hvordan?

Indlæg af gtr »

Tak for svar. I bogens kap 12 står følgende

Kode: Vælg alt

import urllib
import re

url = raw_input('Enter - ')
html = urllib.urlopen(url).read()
links = re.findall('href="(http://.*?)"', html)
for link in links:
    print link


Kan det være, man skal bruge den kode, hvor den ændres til at finde tal?

I bogen står også

Kode: Vælg alt

import urllib
from BeautifulSoup import *

url = raw_input('Enter - ')
html = urllib.urlopen(url).read()
soup = BeautifulSoup(html)

# Retrieve all of the anchor tags
tags = soup('a')
for tag in tags:
   # Look at the parts of a tag
   print 'TAG:',tag
   print 'URL:',tag.get('href', None)
   print 'Content:',tag.contents[0]
   print 'Attrs:',tag.attrs


Hvad er attrs?
Det svar, du skriver, er ikke beskrevet i bogens kap 12. Jeg mener ikke , at bogen viser, hvordan man extracter fra beautifulsoup data.
AJenbo
Admin
Indlæg: 20878
Tilmeldt: 15. nov 2009, 15:04
IRC nickname: AJenbo
Geografisk sted: Vanløse, København

Re: python beutifulsoup extract numbers, hvordan?

Indlæg af AJenbo »

Attrs er kort for attributter, det referer til de felter man kan sætte i et html tag.
zob
Redaktør
Indlæg: 4430
Tilmeldt: 6. jan 2009, 22:01
Geografisk sted: København

Re: python beutifulsoup extract numbers, hvordan?

Indlæg af zob »

gtr skrev:Det svar, du skriver, er ikke beskrevet i bogens kap 12. Jeg mener ikke , at bogen viser, hvordan man extracter fra beautifulsoup data.


Nu har jeg ikke nærstuderet din bog. Men mon ikke det er sådan at de giver en opgave som du ikke har hele svaret på i bogen på forhånd. På den måde lærer du at læse dokumentation (som jeg linkede til) og/eller hacke dig lidt frem (jeg indrømmer jeg brugte en kombination af disse metoder).
(hacke skal, i denne sammenhæng, bare forstås som at prøve sig lidt frem og se hvad der sker).

De to eksempler du giver fra bogen "extracter" da også data, bare ikke lige præcis data af den type som du har brug for til øvelsen, men du kan vel ikke regne med at øvelserne bliver ved med at være copy-paste fra bogen når du er nået til kapitel 12.
lath
Indlæg: 5095
Tilmeldt: 27. apr 2008, 02:16
IRC nickname: lars_t_h
Geografisk sted: Fyn

Re: python beutifulsoup extract numbers, hvordan?

Indlæg af lath »

gtr skrev:coursera
geany
python 2

I en kursusrække er jeg kommet til en opgave, som jeg ikke kan finde svaret på. Jeg har spurgt på kursets forum. Forummet virker efter min mening ikke hensigtsmæssigt. Når jeg paster den kode, jeg har skrevet og som ikke virker, bliver den slettet. En anden kursusdeltager svarede på et spørgsmål fra mig. Det blev også delvis slettet. Derfor spørger jeg her. Man skal hente data fra en url. Når man har hentet data'ene, skal man extract numbers og summere dem. Jeg kan hente data'ene, men ikke extract dem og summere dem. Man underviser med videoer og denne bog. http://do1.dr-chuck.com/py4inf/EN-us/book.pdf. Opgaven hører til kap 12. Der er blevet undervist op til kap 12.

Den her kode har jeg skrevet.

Kode: Vælg alt

import re
import urllib
from BeautifulSoup import *
url = 'http://python-data.dr-chuck.net/comments_42.html'
html = urllib.urlopen(url).read()
soup = BeautifulSoup(html)
tags = soup('tr')
print tags


Når koden startes i geany, fremkommer dette i command line.

Kode: Vælg alt

[<tr>
<td>Name</td><td>Comments</td>
</tr>, <tr><td>Leven</td><td><span class="comments">100</span></td></tr>, <tr><td>Mahdiya</td><td><span class="comments">97</span></td></tr>, <tr><td>Ajayraj</td><td><span class="comments">87</span></td></tr>, <tr><td>Lillian</td><td><span class="comments">86</span></td></tr>, <tr><td>Aon</td><td><span class="comments">86</span></td></tr>, <tr><td>Ruaraidh</td><td><span class="comments">78</span></td></tr>, <tr><td>Gursees</td><td><span class="comments">75</span></td></tr>, <tr><td>Emmanuel</td><td><span class="comments">74</span></td></tr>, <tr><td>Christy</td><td><span class="comments">72</span></td></tr>, <tr><td>Annoushka</td><td><span class="comments">72</span></td></tr>, <tr><td>Inara</td><td><span class="comments">72</span></td></tr>, <tr><td>Caite</td><td><span class="comments">70</span></td></tr>, <tr><td>Rosangel</td><td><span class="comments">70</span></td></tr>, <tr><td>Iana</td><td><span class="comments">66</span></td></tr>, <tr><td>Anise</td><td><span class="comments">66</span></td></tr>, <tr><td>Jaosha</td><td><span class="comments">65</span></td></tr>, <tr><td>Cadyn</td><td><span class="comments">65</span></td></tr>, <tr><td>Edward</td><td><span class="comments">63</span></td></tr>, <tr><td>Charlotte</td><td><span class="comments">61</span></td></tr>, <tr><td>Sammy</td><td><span class="comments">60</span></td></tr>, <tr><td>Zarran</td><td><span class="comments">60</span></td></tr>, <tr><td>Rowen</td><td><span class="comments">59</span></td></tr>, <tr><td>Stanislaw</td><td><span class="comments">59</span></td></tr>, <tr><td>Maighdlin</td><td><span class="comments">57</span></td></tr>, <tr><td>Connan</td><td><span class="comments">56</span></td></tr>, <tr><td>Warrick</td><td><span class="comments">54</span></td></tr>, <tr><td>Diya</td><td><span class="comments">52</span></td></tr>, <tr><td>Lawson</td><td><span class="comments">52</span></td></tr>, <tr><td>Wu</td><td><span class="comments">51</span></td></tr>, <tr><td>Irmak</td><td><span class="comments">47</span></td></tr>, <tr><td>Emilija</td><td><span class="comments">47</span></td></tr>, <tr><td>Kayda</td><td><span class="comments">41</span></td></tr>, <tr><td>Ellenor</td><td><span class="comments">41</span></td></tr>, <tr><td>Kyra</td><td><span class="comments">41</span></td></tr>, <tr><td>Nikita</td><td><span class="comments">38</span></td></tr>, <tr><td>Kaelah</td><td><span class="comments">35</span></td></tr>, <tr><td>Meko</td><td><span class="comments">32</span></td></tr>, <tr><td>Marissa</td><td><span class="comments">31</span></td></tr>, <tr><td>Ayat</td><td><span class="comments">24</span></td></tr>, <tr><td>Sali</td><td><span class="comments">19</span></td></tr>, <tr><td>Hashem</td><td><span class="comments">19</span></td></tr>, <tr><td>Tygan</td><td><span class="comments">18</span></td></tr>, <tr><td>Rioden</td><td><span class="comments">17</span></td></tr>, <tr><td>Cruiz</td><td><span class="comments">16</span></td></tr>, <tr><td>Caoilfinn</td><td><span class="comments">13</span></td></tr>, <tr><td>Ewen</td><td><span class="comments">8</span></td></tr>, <tr><td>Baighley</td><td><span class="comments">7</span></td></tr>, <tr><td>Ramone</td><td><span class="comments">1</span></td></tr>, <tr><td>Kyran</td><td><span class="comments">1</span></td></tr>, <tr><td>Noelani</td><td><span class="comments">1</span></td></tr>]


Hvordan extract jeg numbers? Er det ikke en string?

Når du pudser en HTML parser på et HTML dokument - der jo kun er tekst - så får du som output et DOM træ.

Et DOM træ består af knudepunkter der kaldes en Node.

Du er kort fortalt ude efter alle Nodes der af typen TextNode, der bor inde i en span Node.
En span Node skal have en class attribut, der indeholder værdien comment før TextNoden der bor inde i span Noden må bruges.

Opgaven er meget pæn, da alle tal er en TextNode der bor inde i span.comment Node, og kun indeholder et tal og uden at der er noget rundt omkring tallet.
Hvis der befandt sig mere end et tal i hver tekst fra en TextNode, og en TextNode var inde i mange forskellige HTML tags, så ville opgaven blive betydeligt meget sværere.

zob har leveret koden til dig på et virtuelt sølvfad.

/Lars

En gang ude i fremtiden så kan måske bruge den her algoritme - der er skrevet i psudo kode.

Algoritmen er en LL(1) lexical analyzer - også kaldet en lexer - der kan finde mange tal i en tekst streng.
F.eks. så vil teksten "1abg567b f5 4 694nn " få algoritmen til at producere det her array af heltal: [1, 567, 5, 4, 694].
Den er en LL(1) lexer, fordi den søger fra venstre mod højre (det første L), og konstruerer et token/en brik (her er et token et tal), ved kun at kigge på 1 tegn af gangen
Det andet L i LL(1) betyder at algoritmen arbejder venstre rekursivt. Det begreb er ret svært at forklare, hvis man ikke kender til BNF (Backus-Naur Form) - der en måde at beskrive et programmeringssprog på.

For sprog med latinske bogstaver, f.eks. dansk, så bryder mennesker tekst op i ord med en LL(k) algoritme, hvor k betyder uendeligt mange tegn, og i praksis er k selvfølgelig kun så stort som det antal tegn et menneske kan håndtere på samme tid.

---
Her er LL(1) lexer algoritmen for tal:

Opret en funktion, du kan kalde den 'numberLexer', der modtager en tekst (string, Python: str) som input og leverer et array af heltal retur:

Inde i funktionen gør dette:
Opret et tomt array af tal - lad os kalde den for 'numbers' der er typen 'et heltal'
Opret et andet array af tegn, som vi kalder 'txtNumber' - txtNumber er vores buffer af tegn vi bruger til at finde et helt tal, f.eks tegnene der kommer i følgende rækkefølge: "1", "2", "3", der jo er tallet 123.
Start en løkke der gennemgår tekststrengen fra første tegn til det sidste tegn i arrayet:
Er første tegn et tal? (if1)
Hvis ja (then1):
tilføj tegnet til txtNumber arrayet (tegn bufferen) - vi er nu i gang med at konstruere et heltal ved at læse flere tegn fra teksten.
Hvis nej (else1):
Har bufferen (txtNumbers) mere end nul tegn? (if2):
Hvis ja: (else1 -> then2):
Vi har fundet et tal, som består af et eller flere tegn!
Lad en Python funktion producere et tal ud fra teksten (str) i bufferen 'txtNumbers'.
Tilføj tallet til 'numbers' arrayet.
Slet indholdet i 'txtNumbers' (længden af det array bliver nul).
Der er ikke nogen (else1 -> else2)
Læg en til variablen der peger på et index i teksten, sådan at algoritmen hopper hen til næste tegn.
Loop igen for at behandle det næste tegn fra teksten.

Efter løkken returnerer du 'numbers' arrayet.

Hvis længden af det returnerede array ('numbers') er 0 (nul), så var der ingen tal i teksten.

---
Bemærkninger til algoritmen:

Jeg bruger if1, if2, til at fortælle hvor en if sætning starter.
Then1, og else1 er henholdsvis sandt-delen for if sætning if1, og falskt-delen for if sætning if1.
if2 er inde i scopet for else1.
Then2 er sandt-delen for if sætning if2, som er inde i else1 blokken (inde i else1 scopet).
Der er ikke nogen else2 - altså falskt del - for if2 if sætningen.
Jeg er Software ingeniør (Diplomingeniør) i Informationsteknologi og indlejede systemer, hvor indlejrede systemer er computer (microcontroller) + elektronik i for eksempel et TV, en router, en vaskemaskine og den slags
gtr

Re: python beutifulsoup extract numbers, hvordan?

Indlæg af gtr »

I videoen fortæller kort om tags. I bogen står der meget lidt om at hente specifik beautifulsoup data. Jeg ved ikke, hvad jeg skal bruge.

Kode: Vælg alt

spans = soup.find_all('span', attrs={'class':'comments'})

Jeg kan ikke se noget sted i bogen, hvor denne opbygning beskrives. Jeg ved ikke, hvordan man skal være i stand til at ræsonere sig frem til, hvordan forskriften skal være. Selv når jeg ser coden, kan jeg ikke forstå den efterfølgende, fordi jeg ikke kender baggrunden for opbygningen.

I den næste opgave skal man gøre det samme med xml data. Her kan jeg også hente data. Jeg kan ikke extract specifik data fra xml, som opgaven lyder.
AJenbo
Admin
Indlæg: 20878
Tilmeldt: 15. nov 2009, 15:04
IRC nickname: AJenbo
Geografisk sted: Vanløse, København

Re: python beutifulsoup extract numbers, hvordan?

Indlæg af AJenbo »

Det er sikkert meningen du selv skal så noget af det op i dokumentationen for beutifulsoup.
thj01
Indlæg: 2667
Tilmeldt: 21. nov 2006, 10:06
Geografisk sted: Fredericia

Re: python beutifulsoup extract numbers, hvordan?

Indlæg af thj01 »

Blev lige så glad da jeg så bogen ... og så opdagede jeg at den var skrevet til python2 :(
Forfatter til Ubuntuguiden: http://www.vidas.dk/guides/ubuntuguiden.html

Kører LTS udgaverne.

"It's always easy if you know how to do it."
zob
Redaktør
Indlæg: 4430
Tilmeldt: 6. jan 2009, 22:01
Geografisk sted: København

Re: python beutifulsoup extract numbers, hvordan?

Indlæg af zob »

Hvis det "bare" er for at få en gratis python 3 bog, så er dette vel en klassiker (du kan også downloade som pdf og endda clone den med git).
http://www.diveintopython3.net/

I bogen er der i øvrigt også et kapitel 12 om XML parsing som gtr måske kan bruge til det seneste problem.
thj01
Indlæg: 2667
Tilmeldt: 21. nov 2006, 10:06
Geografisk sted: Fredericia

Re: python beutifulsoup extract numbers, hvordan?

Indlæg af thj01 »

@zob

Tak... det er sådan noget viden der er kræs for os ikke programmeringsfolk ... :) ... Tak
Forfatter til Ubuntuguiden: http://www.vidas.dk/guides/ubuntuguiden.html

Kører LTS udgaverne.

"It's always easy if you know how to do it."
gtr

Re: python beutifulsoup extract numbers, hvordan?

Indlæg af gtr »

Jeg har testet

Kode: Vælg alt

import urllib
from BeautifulSoup import *
url = 'http://python-data.dr-chuck.net/comments_42.html'
html = urllib.urlopen(url).read()
soup = BeautifulSoup(html)
tags = soup('span')


Det giver linier som

Kode: Vælg alt

<span class="comments">41</span>


Er det strings? Hvorfor kan jeg ikke skrive

Kode: Vælg alt

for tag in tags:
    print tag[22:1]


Kode: Vælg alt

spans = soup.find_all('span', attrs={'class':'comments'})


virker ikke på min computer. Måske fordi jeg har version beautifulsoup 3 installeret.

Der har været kommentarer om, at der bruges python 2. Det er python 2 man bruger i undervisningen, fordi det er det mest anvendte. Der skiftes først til python 3, når det bliver standard. Selvom det synes, at man her mener, at man bruger python 3.
AJenbo
Admin
Indlæg: 20878
Tilmeldt: 15. nov 2009, 15:04
IRC nickname: AJenbo
Geografisk sted: Vanløse, København

Re: python beutifulsoup extract numbers, hvordan?

Indlæg af AJenbo »

En string er blot en serie af tegn, så ja det er en string, men der er kun en så det er ikke strings (flertal).

Stortset alt ny kode der skrives er python3 og det er kun eksisterende projekter der stadig er i python2 og de fleste er igang med at omskrive til python3.