2016-08-11 1 views
5

Here is the Website I am trying to scrape http://livingwage.mit.edu/Python-> Beautifulsoup-> Webscraping-> URL (1 ~ 53)에 걸쳐 반복 및 저장 결과

특정 URL은

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 

에서 그리고 이러한 URL 각각에, 내가 필요하다 두 번째 테이블의 마지막 행 :

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

에 대한 연간 소득 필수 세전 $ 20,260 $ 4만2천7백86 $ 51,642 $ 64,767 $ 34,325 $ 4만2천3백5 $ 4만7천3백45 $ 53,206 $ 34,325 $ 47,691 $ 5만6천9백34 $ 66,997

욕망 출력 :

알라바마 $ 20,260 $ 4만2천7백86 $ 51,642 $ 64,767 $ 34,325 $ 4만2천3백5 $ 4만7천3백45 $ 53,206 $ 34,325 $ 47,691 $ 5만6천9백34 $ 66,997

알래스카에게 $ 24,070 $ 4만9천2백95 $ 6만9백33 $ 79,871 $ 38,561 $ 47,136 $ 52,233 $ 61,531 $ 38,561 $ 54,433 $ 66,316 $ 82,403

...

...

와이오밍 $ 2만8백67 $ 42,689 $ 52,007 $ 65,892 $ 34,988 $ 41,887 $ 4만6천9백83 $ 5만3천5백49 $ 34,988 $ 47,826 $ 5만7천3백91 장난 2 시간 후 $ 6만8천4백24

, 이것은 내가 (나는 초보자입니다) 지금까지 무엇을 가지고 :

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) 

내가 파이썬 콘솔에서 STATE_NAME 행을 볼 때 그것은 HTML 요소를 줘

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

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

문제 1 :이 내가 원하는 출력에서 ​​원하는 일을하지만, 어떻게 오히려 위와 같이 HTML보다 문자열 형식으로 파이썬이 나에게주고받을 수 있나요?

문제점 2 : request.get (url01 - url56)을 어떻게 반복합니까?

도움 주셔서 감사합니다.

내 코드에서 행 변수를 얻는보다 효율적인 방법을 제공 할 수 있다면, 내가 얻은 방법이 매우 Pythonic이 아니기 때문에, 크게 감사하겠습니다.

답변

5

그냥 초기 페이지에서 모든 상태를 얻을, 당신은 클래스로 슬라이스 할 필요가 없습니다 두 번째 테이블을 선택하고는 당신이 필요로하는 TR을 얻을 수있는 CSS 클래스를이상한 결과을 사용할 수 있습니다 이름은 고유 :

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)) 

코드를 실행하면 당신은 볼 것 같은 출력 :

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'] 

당신은 루프 아칸소 수 1-53에서 ange하지만 기본 페이지에서 앵커를 추출하면 한 페이지에서 h1을 사용하여 상태 이름도 제공합니다. Alabama의 생활 임금 계산 다음에 시도해야 할 생활 임금 계산 어떤 주에서는 한 단어 이름이 더 많다고 생각하면 사소한 것이 아닌 이름을 얻으려고 파싱하십시오.

+1

대단히 고마워,이게 내가 원하는거야. 자, 어떻게 이것을 내 질문에 대한 대답으로 받아 들일 수 있습니까? –

+0

@OmiSlash. 걱정 마라, 네가 알아 냈어. –

+0

지난 2 일 동안 코드를 연구하는 데 시간을 썼으며, 그 코드가 내 머리 위로 바로 향이났다. 남자에게 물고기를주는 말은 하루 먹이를주고, 물고기를 가르치며, 평생 동안 먹이를줍니다. 요청 문서를 읽고 기본 HTML을 이해합니다. 나는 물고기를 받았으며, 항상 웹 스크랩으로 도움을 청하기 위해 다시 돌아 오기를 원하지 않는다면 (그리고 당신은 의로운 점을 얻었을 것입니다.) 생각과 워크 플로우 과정을 진행할 수 있습니까? 이 코드를 만들 때? –

2

문제 1 : 이것들은 내가 원하는 출력물에서 원하는 것들이지만, 파이썬이 위와 같이 HTML이 아닌 문자열 형식으로 나에게 줄 수있는 방법은 무엇입니까?

당신의 라인에 뭔가를 수행하여 간단하여 텍스트를 얻을 수 있습니다 :

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

같은 너무 각 행에 적용 할 수 있습니다.

문제점 2 : request.get (url01 - url56)을 어떻게 반복합니까?

동일한 코드 블록

은 56과 같이 1 내지 루프 안에 넣을 수 :

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

zfill 그 앞에 0을 추가 할 것이다. 또한 requests.gettry-except 블록으로 묶여 있으면 URL이 잘못되어도 루프가 정상적으로 계속 진행되는 것이 좋습니다.

+1

답장을 보내 주셔서 감사합니다. 코드 작성 방식을 따르므로 많은 도움이됩니다. 그러나 나는 Padraic Cunningham의 대답을 받아 들였다. 왜냐하면 내가 코딩 한 것보다 훨씬 더 Pythonic이기 때문이다 (나는 부끄럽다 !!). 그리고 Padraic Cunningham의 답변에서 웹 스크 레이 핑을위한 몇 가지 새로운 기술을 배웠습니다. 새로운 기술을 배우는 것이 항상 목표입니다. 맞습니까? –

+0

완전히 사실입니다! – dunder