2017-08-01 85 views
0

我是新来美丽的汤和嵌套表,因此我尝试获得一些经验刮维基百科表。美丽的汤维基百科嵌套表

我在网上搜索了很好的例子,但不幸的是我还没有找到任何东西。

我的目标是通过这张web page,通过熊猫解析“美利坚合众国的国家”表格。正如你从我的代码下面可以看到我有以下问题:

1)我不能提取所有的列。显然,我的代码不允许在pandas DataFrame中正确导入所有列,并将第一列下方的html表格的第三列条目写入。

2)我不知道如何处理colspan =“2”它出现在表格的某些行中。在我的熊猫DataFrame中,我想在资本和最大城市相同的情况下拥有相同的条目。

这是我的代码。请注意,我试图克服我的第一个问题。

代码:

from urllib.request import urlopen 
import pandas as pd 

wiki='https://en.wikipedia.org/wiki/List_of_states_and_territories_of_the_United_States' 
page = urlopen(wiki) 

from bs4 import BeautifulSoup 

soup = BeautifulSoup(page) 

right_table=soup.find_all('table')[0] # First table 

rows = right_table.find_all('tr')[2:] 

A=[] 
B=[] 
C=[] 
D=[] 
F=[] 

for row in rows: 
    cells = row.findAll('td') 
# print(len(cells)) 
    if len(cells)>=11: #Only extract table body not heading 
     A.append(cells[0].find(text=True)) 
     B.append(cells[1].find(text=True)) 
     C.append(cells[2].find(text=True)) 
     D.append(cells[3].find(text=True)) 
     F.append(cells[4].find(text=True)) 

df=pd.DataFrame(A,columns=['State']) 
df['Capital']=B 
df['Largest']=C 
df['Statehood']=D 
df['Population']=F 
df 
print(df) 

你有任何suggestings? 任何帮助理解更好的BeautifulSoup将不胜感激。 在此先感谢。

+0

的清洁版维基百科的那些表是人类FYI编辑。这意味着他们往往是一团糟。 – pguardiario

回答

1

以下是我将使用的策略。

我注意到表格中的每一行都是完整的,但如您所说,某些行在“城市”列中有两个城市,有些行只有一个。这意味着我们可以使用一行中的项目数量来确定是否需要将该行中提到的城市名称“加倍”。

我以你的方式开始。

>>> import requests 
>>> import bs4 
>>> page = requests.get('https://en.wikipedia.org/wiki/List_of_states_and_territories_of_the_United_States').content 
>>> soup = bs4.BeautifulSoup(page, 'lxml') 
>>> right_table=soup.find_all('table')[0] 

然后我找到表中的所有行并验证它至少近似正确。

>>> trs = right_table('tr') 
>>> len(trs) 
52 

我闲逛,直到我找到阿拉巴马州和怀俄明州,第一个和最后一个行线,并显示其文本。他们是两种类型的行的例子!

>>> trs[2].text 
'\n\xa0Alabama\nAL\nMontgomery\nBirmingham\n\nDec 14, 1819\n\n\n4,863,300\n\n52,420\n135,767\n50,645\n131,171\n1,775\n4,597\n\n7\n\n' 
>>> trs[51].text 
'\n\xa0Wyoming\nWY\nCheyenne\n\nJul 10, 1890\n\n\n585,501\n\n97,813\n253,335\n97,093\n251,470\n720\n1,864\n\n1\n\n' 

我发现我可以\n\xa0拆分这些字符串。这可以用正则表达式来完成。

>>> [_ for _ in re.split(r'[\n\xa0]', trs[51].text) if _] 
['Wyoming', 'WY', 'Cheyenne', 'Jul 10, 1890', '585,501', '97,813', '253,335', '97,093', '251,470', '720', '1,864', '1'] 
>>> [_ for _ in re.split(r'[\n\xa0]', trs[2].text) if _] 
['Alabama', 'AL', 'Montgomery', 'Birmingham', 'Dec 14, 1819', '4,863,300', '52,420', '135,767', '50,645', '131,171', '1,775', '4,597', '7'] 

if _条件在这些列表解析是放弃空字符串。

怀俄明州字符串的长度为12,阿拉巴马州的是13.我会离开阿拉巴马州的字符串,因为它是熊猫。我会延长怀俄明州(和所有其他长度12)使用:

>>> row = [_ for _ in re.split(r'[\n\xa0]', trs[51].text) if _] 
>>> row[:3]+row[2:] 
['Wyoming', 'WY', 'Cheyenne', 'Cheyenne', 'Jul 10, 1890', '585,501', '97,813', '253,335', '97,093', '251,470', '720', '1,864', '1'] 
0

下面的解决方案应该解决您提到的两个问题。

from urllib.request import urlopen 
import pandas as pd 
from bs4 import BeautifulSoup 

wiki='https://en.wikipedia.org/wiki/List_of_states_and_territories_of_the_United_States?action=render' 
page = urlopen(wiki) 
soup = BeautifulSoup(page, 'html.parser') 
right_table=soup.find_all('table')[0] # First table 
rows = right_table.find_all('tr')[2:] 

A=[] 
B=[] 
C=[] 
D=[] 
F=[] 

for row in rows: 
    cells = row.findAll('td') 
    combine_cells = cells[1].get('colspan') # Tells us whether columns for Capital and Established are the same 
    cells = [cell.text.strip() for cell in cells] # Extracts text and removes whitespace for each cell 
    index = 0 # allows us to modify columns below 

    A.append(cells[index]) # State Code 
    B.append(cells[index + 1]) # Capital 
    if combine_cells: # Shift columns over by one if columns 2 and 3 are combined 
     index -= 1 

    C.append(cells[index + 2]) # Largest 
    D.append(cells[index + 3]) # Established 
    F.append(cells[index + 4]) # Population 

df=pd.DataFrame(A,columns=['State']) 
df['Capital']=B 
df['Largest']=C 
df['Statehood']=D 
df['Population']=F 
df 
print(df) 

编辑:这里是上面的代码

import pandas as pd 
from bs4 import BeautifulSoup 
from urllib.request import urlopen 

wiki = 'https://en.wikipedia.org/wiki/List_of_states_and_territories_of_the_United_States' 
page = urlopen(wiki) 
soup = BeautifulSoup(page, 'html.parser') 
table_rows = soup.find('table')('tr')[2:] # Get all table rows 
cells = [row('td') for row in table_rows] # Get all cells from rows 


def get(cell): # Get stripped string from tag 
    return cell.text.strip() 


def is_span(cell): # Check if cell has the 'colspan' attribute <td colspan="2"></td> 
    return cell.get('colspan') 


df = pd.DataFrame() 
df['State'] = [get(cell[0]) for cell in cells] 
df['Capital'] = [get(cell[1]) for cell in cells] 
df['Largest'] = [get(cell[2]) if not is_span(cell[1]) else get(cell[1]) for cell in cells] 
df['Statehood'] = [get(cell[3]) if not is_span(cell[1]) else get(cell[2]) for cell in cells] 
df['Population'] = [get(cell[4]) if not is_span(cell[1]) else get(cell[3]) for cell in cells] 
print(df) 
+0

谢谢你们两位!非常有用的评论! – fdrigo