如何用BeautifulSoup提取HTML中Span及整行国际象棋赛事信息
优化BeautifulSoup提取国际象棋赛事数据的方案
一、初始需求的简化方案
你之前提取选手和评分的代码确实有点绕,还没搞定动态class的国家提取。其实可以利用BeautifulSoup的CSS选择器和元素定位来大幅简化:
目标HTML片段:
<div class="user-tagline "> <span class="username " data-avatar="aaaaaaa">player1</span> <span class="user-rating">(1357)</span> <span class="country-flag-small flag-113" tip="Portugal"></span> </div> <div class="user-tagline "> <span class="username " data-avatar="bbbbbbb">player2</span> <span class="user-rating">(1387)</span> <span class="country-flag-small flag-70" tip="Indonesia"></span> </div>
简化后的代码:
from bs4 import BeautifulSoup html = # 你的HTML字符串 soup = BeautifulSoup(html, 'html.parser') # 提取第一个选手的完整信息 first_player_div = soup.find('div', class_='user-tagline') player1 = first_player_div.find('span', class_='username').get_text(strip=True) pscore1 = first_player_div.find('span', class_='user-rating').get_text(strip=True).strip('()') # 直接通过tip属性拿国家,彻底绕开动态的flag-xxx class player1_country = first_player_div.find('span', class_='country-flag-small')['tip'] print(player1, pscore1, player1_country) # 输出:player1 1357 Portugal
优势说明:
- 用
find()替代findAll()[0]更直接,避免不必要的列表索引操作 get_text(strip=True)自动去除文本前后空白,不用手动拆分字符串- 直接读取元素属性获取国家,完全不受动态class影响
二、更新需求:完整提取整行赛事数据
对于包含多字段的赛事行,我们可以结构化地提取所有信息,代码逻辑更清晰易维护:
目标HTML片段:
<tr board-popover="" fen="r1bk2r1/1p2n3/pN6/1B1qQp2/P2Pp2p/1P6/2P2PPP/R3K1R1 b Q -" flip-board="1" highlight-squares="c4b6"> <td> <a class="clickable-link td-user" href="https://www.chess.com/live/game/2249663029?username=belemnarmada" target="_self"> <span class="time-control"> <i class="icon-rapid"> </i> </span> <div class="user-tagline "> <span class="username " data-avatar="https://betacssjs.chesscomfiles.com/bundles/web/images/noavatar_l.1c5172d5.gif" data-country="Portugal" data-enabled="true" data-flag="113" data-joined="Joined Jun 19, 2016" data-logged="Online 6 hrs ago" data-membership="basic" data-name="Atikinounette" data-popup="hover" data-title="" data-username="Atikinounette"> Atikinounette </span> <span class="user-rating"> (1357) </span> <span class="country-flag-small flag-113" tip="Portugal"> </span> </div> <div class="user-tagline "> <span class="username " data-avatar="https://images.chesscomfiles.com/uploads/v1/user/28196414.83e31ff1.50x50o.3a6f77e4aa44.jpeg" data-country="Indonesia" data-enabled="true" data-flag="70" data-joined="Joined May 15, 2016" data-logged="Online Nov 7, 2017" data-membership="basic" data-name="belemnarmada" data-popup="hover" data-title="" data-username="belemnarmada"> belemnarmada </span> <span class="user-rating"> (1387) </span> <span class="country-flag-small flag-70" tip="Indonesia"> </span> </div> </a> </td> <td> <a class="clickable-link text-middle" href="https://www.chess.com/live/game/2249663029?username=belemnarmada" target="_self"> <div class="pull-left"> <span class="game-result"> 1 </span> <span class="game-result"> 0 </span> </div> <div class="result"> <i class="icon-square-minus loss" tip="Lost"> </i> </div> </a> </td> <td class="text-center"> <a class="clickable-link" href="https://www.chess.com/live/game/2249663029?username=belemnarmada" target="_self"> 30 min </a> </td> <td class="text-right"> <a class="clickable-link text-middle moves" href="https://www.chess.com/live/game/2249663029?username=belemnarmada" target="_self"> 25 </a> </td> <td class="text-right miniboard"> <a class="clickable-link archive-date" href="https://www.chess.com/live/game/2249663029?username=belemnarmada" target="_self"> Aug 9, 2017 </a> </td> <td class="text-center miniboard"> <input class="checkbox" game-checkbox="" game-id="2249663029" game-is-live="true" ng-model="model.gameIds[2249663029].checked" type="checkbox"/> </td> </tr>
完整提取代码:
from bs4 import BeautifulSoup html = # 你的HTML字符串 soup = BeautifulSoup(html, 'html.parser') # 定位目标赛事行 game_row = soup.find('tr', {'board-popover': ''}) # 提取两位选手的信息 player_divs = game_row.find_all('div', class_='user-tagline') players = [] for div in player_divs: player_info = { 'name': div.find('span', class_='username').get_text(strip=True), 'rating': div.find('span', class_='user-rating').get_text(strip=True).strip('()'), 'country': div.find('span', class_='country-flag-small')['tip'] } players.append(player_info) # 提取比赛结果 result_spans = game_row.find('div', class_='pull-left').find_all('span', class_='game-result') game_result = [span.get_text(strip=True) for span in result_spans] # 提取其他赛事字段 game_duration = game_row.find('td', class_='text-center').get_text(strip=True) total_moves = game_row.find('td', class_='text-right').find('a', class_='moves').get_text(strip=True) game_date = game_row.find('a', class_='archive-date').get_text(strip=True) # 整理成结构化数据 game_data = { 'players': players, 'result': game_result, 'duration': game_duration, 'total_moves': total_moves, 'date': game_date } print(game_data)
输出示例:
{ 'players': [ {'name': 'Atikinounette', 'rating': '1357', 'country': 'Portugal'}, {'name': 'belemnarmada', 'rating': '1387', 'country': 'Indonesia'} ], 'result': ['1', '0'], 'duration': '30 min', 'total_moves': '25', 'date': 'Aug 9, 2017' }
方案亮点:
- 用字典结构化存储数据,可读性和扩展性拉满
- 精准定位元素,避免冗余的文本拆分操作
- 统一用
get_text(strip=True)处理文本,自动清理空白字符 - 完全兼容动态class的元素提取(比如国家flag)
内容的提问来源于stack exchange,提问作者mdivk
相关产品推荐
相关产品推荐

