2016-08-11 11 views
5

Here is the Website I am trying to scrape http://livingwage.mit.edu/Python-> Beautifulsoup-> Webscraping-> Looping über URL (1 bis 53) und Speichern Ergebnisse

Die spezifischen URLs sind von

http://livingwage.mit.edu/states/01 

http://livingwage.mit.edu/states/02 

http://livingwage.mit.edu/states/04 (For some reason they skipped 03) 

...all the way to... 

http://livingwage.mit.edu/states/56 

Und auf jeder dieser URLs, ich brauche die letzte Zeile der zweiten Tabelle:

Beispiel für http://livingwage.mit.edu/states/01

Erforderliche Jahreseinkommen vor Steuern $ 20.260 $ 42.786 $ 51.642 $ 64.767 $ 34.325 $ 42.305 $ 47.345 $ 53.206 $ 34.325 $ 47.691 56.934 $ $ 66.997

Wunsch Ausgang: 60.933

Alabama $ 20.260 $ 42.786 $ 51.642 $ 64.767 $ 34.325 $ 42.305 $ 47.345 $ 53.206 $ 34.325 $ 47.691 $ 56.934 $ 66.997

Alaska $ 24.070 $ 49.295 $ $ 79,871 $ 38,561 $ 47,136 $ 52,233 $ 61,531 $ 38,561 $ 54,433 $ 66,316 $ 82,403

...

...

Wyoming $ 20.867 42.689 $ $ 52.007 $ 65.892 $ 34.988 $ 41.887 $ 46.983 $ 53.549 $ 34.988 $ 47.826 $ 57.391 $ 68.424

Nach 2 Stunden um von Messing, ist das, was ich bisher habe (ich bin ein Anfänger):

import requests, bs4 

res = requests.get('http://livingwage.mit.edu/states/01') 

res.raise_for_status() 
states = bs4.BeautifulSoup(res.text) 


state_name=states.select('h1') 

table = states.find_all('table')[1] 
rows = table.find_all('tr', 'odd')[4:] 


result=[] 

result.append(state_name) 
result.append(rows) 

Wenn ich die STATE_NAME und Zeilen in Python Konsole betrachtet es gibt mir die hTML-Elemente

[<h1>Living Wag...Alabama</h1>] 

und

[<tr class = "odd... </td> </tr>] 

Problem 1: Das sind die Dinge, die ich in der gewünschten Ausgabe wollen, aber wie kann ich Python es mir in einem String-Format zu geben, anstatt HTML wie oben?

Problem 2: Wie durchlaufe ich request.get (url01 bis url56)?

Vielen Dank für Ihre Hilfe.

Und wenn Sie einen effizienteren Weg bieten können, um die Zeilenvariable in meinem Code zu bekommen, würde ich es sehr schätzen, weil die Art, wie ich dorthin komme, nicht sehr Pythonic ist.

Antwort

5

einfach alle Staaten von der Startseite bekommen, dann können Sie die zweite Tabelle auswählen und die CSS-Klassenungerade Ergebnisse verwenden die tr zu bekommen Sie brauchen, gibt es keine Notwendigkeit, wie die Klasse zu schneiden ist Namen sind einzigartig:

import requests 
from bs4 import BeautifulSoup 
from urllib.parse import urljoin # python2 -> from urlparse import urljoin 


base = "http://livingwage.mit.edu" 
res = requests.get(base) 

res.raise_for_status() 
states = [] 
# Get all state urls and state name from the anchor tags on the base page. 
# td + td skips the first td which is *Required annual income before taxes* 
# get all the anchors inside each li that are children of the 
# ul with the css class "states list". 
for a in BeautifulSoup(res.text, "html.parser").select("ul.states.list-unstyled li a"): 
    # The hrefs look like "/states/51/locations". 
    # We want everything before /locations so we split on/from the right -> /states/51/ 
    # and join to the base url. The anchor text also holds the state name, 
    # so we return the full url and the state, i.e "http://livingwage.mit.edu/states/01 "Alabama". 
    states.append((urljoin(base, a["href"].rsplit("/", 1)[0]), a.text)) 


def parse(soup): 
    # Get the second table, indexing in css starts at 1, so table:nth-of-type(2)" gets the second table. 
    table = soup.select_one("table:nth-of-type(2)") 
    # To get the text, we just need find all the tds and call .text on each. 
    # Each td we want has the css class "odd results", td + td starts from the second as we don't want the first. 
    return [td.text.strip() for td in table.select_one("tr.odd.results").select("td + td")] 


# Unpack the url and state from each tuple in our states list. 
for url, state in states: 
    soup = BeautifulSoup(requests.get(url).content, "html.parser") 
    print(state, parse(soup)) 

Wenn Sie den Code ausführen, werden Sie sehen eine Ausgabe wie:

Alabama ['$21,144', '$43,213', '$53,468', '$67,788', '$34,783', '$41,847', '$46,876', '$52,531', '$34,783', '$48,108', '$58,748', '$70,014'] 
Alaska ['$24,070', '$49,295', '$60,933', '$79,871', '$38,561', '$47,136', '$52,233', '$61,531', '$38,561', '$54,433', '$66,316', '$82,403'] 
Arizona ['$21,587', '$47,153', '$59,462', '$78,112', '$36,332', '$44,913', '$50,200', '$58,615', '$36,332', '$52,483', '$65,047', '$80,739'] 
Arkansas ['$19,765', '$41,000', '$50,887', '$65,091', '$33,351', '$40,337', '$45,445', '$51,377', '$33,351', '$45,976', '$56,257', '$67,354'] 
California ['$26,249', '$55,810', '$64,262', '$81,451', '$42,433', '$52,529', '$57,986', '$68,826', '$42,433', '$61,328', '$70,088', '$84,192'] 
Colorado ['$23,573', '$51,936', '$61,989', '$79,343', '$38,805', '$47,627', '$52,932', '$62,313', '$38,805', '$57,283', '$67,593', '$81,978'] 
Connecticut ['$25,215', '$54,932', '$64,882', '$80,020', '$39,636', '$48,787', '$53,857', '$61,074', '$39,636', '$60,074', '$70,267', '$82,606'] 

Sie Schleife ar in konnte Ange von 1-53, aber das Extrahieren des Ankers von der Basisseite gibt uns den Staatsnamen in einem einzelnen Schritt, das Verwenden der h1 von dieser Seite würde Ihnen auch Ausgang Lebende Lohnberechnung für Alabama geben, die Sie dann versuchen sollten parse, um nur den Namen zu erhalten, der nicht trivial wäre, wenn man bedenkt, dass einige Staaten mehr als einen Wortnamen haben.

+1

Vielen Dank, das ist genau das, was ich brauche. Nun, wie kann ich dies als die akzeptierte Antwort für meine Frage markieren? –

+0

@OmiSlash. Keine Sorge, ich sehe, du hast es herausgefunden. –

+0

Ich habe die letzten paar Tage damit verbracht, deine Codes zu studieren, und ich muss sagen, dass es so pythonisch ist, dass es direkt über meinen Kopf ging. Also gibt es das Sprichwort, einem Kerl einen Fisch zu geben, füttern Sie ihn für einen Tag, lehren Sie ihn zu fischen und Sie füttern ihn für ein Leben lang. Ich lese die Anfrage-Dokumentation und verstehe einige grundlegende HTML. Ich habe einen Fisch von dir erhalten und es sei denn, du willst, dass ich immer wieder zurückkomme, um deine Hilfe beim Webscraping zu erbitten (und du würdest dir auch einige rechtschaffene Punkte verdienen), kannst du deinen Gedanken- und Workflowprozess durchgehen wie Sie diesen Code erstellen? –

2

Problem 1: Das sind die Dinge, die ich in der gewünschten Ausgabe will, aber wie kann ich Python es mir in einem String-Format anstelle von HTML wie oben geben?

Sie können den Text, indem Sie einfach erhalten, indem etwas auf den Linien zu tun:

state_name=states.find('h1').text 

Das gleiche gilt auch für jede der Zeilen angewendet werden.

Problem 2: Wie durchlaufe ich request.get (url01 bis url56)?

for i in range(1,57): 
    res = requests.get('http://livingwage.mit.edu/states/'+str(i).zfill(2)) 
    ...rest of the code... 

zfill fügt diese führenden Nullen:

Der gleiche Code-Block kann in einer Schleife von 1 bis 56 wie so gesetzt werden. Außerdem wäre es besser, wenn requests.get in einem try-except Block eingeschlossen ist, so dass die Schleife selbst dann fehlerfrei weiterläuft, wenn die URL falsch ist.

+1

Vielen Dank für Ihre Antwort, und es hilft mir sehr, da es meiner Art der Codierung folgen. Aber ich habe Padraic Cunninghams Antwort akzeptiert, weil es viel mehr Pythonic ist als die Art, wie ich codiert habe (ich schäme mich !!). Und von Padraic Cunninghams Antwort habe ich ein paar neue Techniken für das Web-Scraping gelernt. Das Erlernen neuer Fähigkeiten ist immer das Ziel, richtig? –

+0

Völlig wahr! – dunder