美丽的汤Wikipidia嵌套表

时间:2017-08-01 17:41:14

标签: python web-scraping beautifulsoup html-parsing

我是Beautiful Soup和嵌套表的新手,因此我尝试获取一些刮擦维基百科表的经验。

我在网上搜索过任何好的例子,但遗憾的是我没有找到任何东西。

我的目标是通过大熊猫解析“美利坚合众国国家”这一表web page。从下面的代码中可以看出,我有以下问题:

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

2)我不知道如何处理 colspan =“2”,它出现在表格的某些行中。在我的pandas 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)

你有什么建议吗? 任何帮助,以了解更好的BeautifulSoup将不胜感激。 提前致谢。

2 个答案:

答案 0 :(得分: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']

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