这是我想要刮掉的东西(缩短了一吨以便于阅读):
<table class="sortable row_summable stats_table" id="per_game">
<colgroup><col><col><col><col><col><col><col><col><col><col><col><col><col><col><col><col><col><col><col><col><col><col><col><col><col><col><col><col><col></colgroup>
<thead>
<tr class="">
<th data-stat="season" align="center" class="tooltip sort_default_asc" tip="If listed as single number, the year the season ended.<br>★ - Indicates All-Star for league.<br>Only on regular season tables.">Season</th>
<th data-stat="age" align="center" class="tooltip sort_default_asc" tip="Age of Player at the start of February 1st of that season.">Age</th>
</tr>
</thead>
<tbody>
<tr class="full_table" id="per_game.2009">
<td align="left" ><a href="/players/r/rondora01/gamelog/2009/">2008-09</a></td>
<td align="right" >22</td>
</tr>
<tr class="full_table" id="per_game.2010">
<td align="left" ><a href="/players/r/rondora01/gamelog/2010/">2009-10</a><span class="bold_text" style="color:#c0c0c0"> ★</span></td>
<td align="right" >23</td>
</tr>
</tfoot>
</table>
这是我正在使用的代码:
from bs4 import BeautifulSoup
import requests
import mechanize
from mechanize import Browser
import csv
mech = Browser()
url = "http://www.basketball-reference.com/players/r/rondora01.html"
# url = "http://www.basketball-reference.com/players/r/rosede01.html"
RR = mech.open(url)
html = RR.read()
soup = BeautifulSoup(html)
table = soup.find(id="per_game")
for row in table.findAll('tr')[1:]:
col = row.findAll('td')
season = col[0].string
age = col[1].string
team = col[2].string
pos = col[3].string
games_played = col[4].string
record = (season, age, team, pos, games_played)
print "|".join(record)
但是,如果您在HTML中注意到第二行中与第一行相比,则该季节还有一个span
。它创造了一个小星星。我的代码运行直到任何具有该附加参数的行,然后崩溃。关于使代码足够灵活以忽略额外span
块的想法?
答案 0 :(得分:1)
我建议做一些改变:
由于您对与<a>
元素相关联的文本感兴趣,请更改您的行:
col[0].string
到col[0].a.string
。这将解决问题。
修复第一个问题后,您将在该表的最后一行遇到错误(因为它的结构不同)。要解决此问题,请将此行for row in table.findAll('tr')[1:]:
更改为for row in table.findAll('tr')[1:-1]:
。这将负责跳过最后一行。
进行以上更改:
for row in table.findAll('tr')[1:-1]:
col = row.findAll('td')
season = col[0].a.string
age = col[1].string
team = col[2].string
pos = col[3].string
games_played = col[4].string
record = (season, age, team, pos, games_played)
print "|".join(record)
打印:
2006-07|20|BOS|NBA|PG
2007-08|21|BOS|NBA|PG
2008-09|22|BOS|NBA|PG
2009-10|23|BOS|NBA|PG
2010-11|24|BOS|NBA|PG
2011-12|25|BOS|NBA|PG
2012-13|26|BOS|NBA|PG
2013-14|27|BOS|NBA|PG
答案 1 :(得分:1)
您可以通过以下方式改进代码:首先,将所有标题读入列表,然后逐行读取所有参数,使用zip()
将每个标题与值匹配并制作字典:
headers = [item.text for item in table('th')]
for row in table('tr')[1:]:
params = [item.text.strip() for item in row('td')]
print dict(zip(headers, params))
打印:
{u'Lg': u'NBA', u'FT': u'1.5', u'3P': u'0.1', u'TOV': u'1.8', u'2PA': u'5.4', u'Tm': u'BOS', u'FG': u'2.4', u'3PA': u'0.4', u'DRB': u'2.8', u'2P': u'2.3', u'AST': u'3.8', u'Season': u'2006-07', u'FT%': u'.647', u'PF': u'2.3', u'PTS': u'6.4', u'FGA': u'5.8', u'GS': u'25', u'G': u'78', u'STL': u'1.6', u'Age': u'20', u'TRB': u'3.7', u'FTA': u'2.4', u'BLK': u'0.1', u'FG%': u'.418', u'Pos': u'PG', u'2P%': u'.432', u'MP': u'23.5', u'ORB': u'0.9', u'3P%': u'.207'}
{u'Lg': u'NBA', u'FT': u'1.4', u'3P': u'0.1', u'TOV': u'1.9', u'2PA': u'9.0', u'Tm': u'BOS', u'FG': u'4.6', u'3PA': u'0.2', u'DRB': u'3.2', u'2P': u'4.5', u'AST': u'5.1', u'Season': u'2007-08', u'FT%': u'.611', u'PF': u'2.4', u'PTS': u'10.6', u'FGA': u'9.3', u'GS': u'77', u'G': u'77', u'STL': u'1.7', u'Age': u'21', u'TRB': u'4.2', u'FTA': u'2.3', u'BLK': u'0.2', u'FG%': u'.492', u'Pos': u'PG', u'2P%': u'.499', u'MP': u'29.9', u'ORB': u'1.0', u'3P%': u'.263'}
{u'Lg': u'NBA', u'FT': u'2.2', u'3P': u'0.2', u'TOV': u'2.6', u'2PA': u'8.9', u'Tm': u'BOS', u'FG': u'4.8', u'3PA': u'0.6', u'DRB': u'4.0', u'2P': u'4.6', u'AST': u'8.2', u'Season': u'2008-09', u'FT%': u'.642', u'PF': u'2.4', u'PTS': u'11.9', u'FGA': u'9.5', u'GS': u'80', u'G': u'80', u'STL': u'1.9', u'Age': u'22', u'TRB': u'5.2', u'FTA': u'3.4', u'BLK': u'0.1', u'FG%': u'.505', u'Pos': u'PG', u'2P%': u'.518', u'MP': u'33.0', u'ORB': u'1.3', u'3P%': u'.313'}
{u'Lg': u'NBA', u'FT': u'2.2', u'3P': u'0.2', u'TOV': u'3.0', u'2PA': u'10.2', u'Tm': u'BOS', u'FG': u'5.7', u'3PA': u'1.0', u'DRB': u'3.2', u'2P': u'5.5', u'AST': u'9.8', u'Season': u'2009-10\xa0\u2605', u'FT%': u'.621', u'PF': u'2.4', u'PTS': u'13.7', u'FGA': u'11.2', u'GS': u'81', u'G': u'81', u'STL': u'2.3', u'Age': u'23', u'TRB': u'4.4', u'FTA': u'3.5', u'BLK': u'0.1', u'FG%': u'.508', u'Pos': u'PG', u'2P%': u'.536', u'MP': u'36.6', u'ORB': u'1.2', u'3P%': u'.213'}
{u'Lg': u'NBA', u'FT': u'1.1', u'3P': u'0.1', u'TOV': u'3.4', u'2PA': u'9.2', u'Tm': u'BOS', u'FG': u'4.7', u'3PA': u'0.6', u'DRB': u'3.1', u'2P': u'4.5', u'AST': u'11.2', u'Season': u'2010-11\xa0\u2605', u'FT%': u'.568', u'PF': u'1.8', u'PTS': u'10.6', u'FGA': u'9.9', u'GS': u'68', u'G': u'68', u'STL': u'2.3', u'Age': u'24', u'TRB': u'4.4', u'FTA': u'1.9', u'BLK': u'0.2', u'FG%': u'.475', u'Pos': u'PG', u'2P%': u'.491', u'MP': u'37.2', u'ORB': u'1.3', u'3P%': u'.233'}
...
如果要从参数值中删除不可打印的字符,可以依赖string.printable
:
import string
params = [filter(lambda x: x in string.printable, item.text)
for item in row.find_all('td')]
另请参阅:Stripping non printable characters from a string in python
输出到csv的完整代码(带有播放器名称):
import csv
import string
from bs4 import BeautifulSoup
from mechanize import Browser
mech = Browser()
url = "http://www.basketball-reference.com/players/r/rondora01.html"
RR = mech.open(url)
html = RR.read()
soup = BeautifulSoup(html)
table = soup.find(id="per_game")
player_name = soup.select('div#info_box h1')[0].text.strip()
with open('result.csv', 'w') as f:
writer = csv.writer(f)
writer.writerow(['Name'] + [item.text for item in table('th')])
for row in table('tr')[1:]:
writer.writerow([player_name] + [filter(lambda x: x in string.printable, item.text)
for item in row('td')])