You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python BeautifulSoup批量爬取多URL p标签数据报错求助

爬虫批量提取球员资料问题

核心需求

提取每个球员链接对应的资料框数据,经浏览器开发者工具检查元素,初步判断可通过提取页面p标签获取对应数据。
球员资料框示例截图
作为Python网络爬虫新手,目前已完成两段独立功能的代码:

  • 单链接信息爬取代码:可部分成功运行,用于提取单个球员页面main-container容器下的p标签内容
import requests
from bs4 import BeautifulSoup


# getting html

url = 'https://basketball.realgm.com/player/Darius-Adams/Summary/28720'
req = requests.get(url)

soup = BeautifulSoup(req.text, 'html.parser')

container = soup.find('div', attrs={'class', 'main-container'})
playerinfo = container.find_all('p')


print(playerinfo)
  • 多页面href链接提取代码:可爬取2020-2022年发展联盟球员列表页的所有a标签href属性
from bs4 import BeautifulSoup
import requests


def get_links(url):

    links = []

    website = requests.get(url)
    website_text = website.text
    soup = BeautifulSoup(website_text)

    for link in soup.find_all('a'):

        links.append(link.get('href'))

    for link in links:
        print(link)

        print(len(links))


get_links('https://basketball.realgm.com/dleague/players/2022')
get_links('https://basketball.realgm.com/dleague/players/2021')
get_links('https://basketball.realgm.com/dleague/players/2020')

现存问题

目标是合并上述两段代码,实现批量提取多个URL下所有p标签内容的功能,但自行编写的合并代码无法正常运行,不清楚错误原因,合并代码如下:

from bs4 import BeautifulSoup
import requests


def get_profile(url):

    profiles = []

    req = requests.get(url)
    soup = BeautifulSoup(req.text, 'html.parser')
    container = soup.find('div', attrs={'class', 'main-container'})

    for profile in container.find_all('a'):

        profiles.append(profile.get('p'))

    for profile in profiles:
        print(profile)


get_profile('https://basketball.realgm.com/player/Darius-Adams/Summary/28720')
get_profile('https://basketball.realgm.com/player/Marial-Shayok/Summary/26697')

需要实现的最终效果:工具可一次性干净爬取球员姓名、当前效力球队、出生日期、出生地等结构化资料,若现有实现思路存在问题可直接指正。


问题解答

合并代码的核心错误

  1. 标签查找逻辑完全错误:代码中查找的是容器下所有a标签,还调用get('p')方法取属性——get()是BeautifulSoup中获取标签属性的方法,p根本不是a标签的属性,自然拿不到任何有效内容,实际需要查找的是p标签而非a标签。
  2. 链接提取逻辑无过滤:现有爬列表页所有a标签的逻辑会拿到大量无关链接(导航栏、页脚、其他板块跳转链接),并非所有a标签都指向球员详情页,会导致后续请求大量无效地址报错。
  3. 提取范围过大:直接提取main-container下所有p标签会拿到新闻、数据统计、广告等大量冗余内容,无法直接得到结构化的球员资料。

正确实现方案

直接定位最小范围的球员资料容器(页面中球员基础信息存放在class="profile-box"的div容器内,精准度远高于main-container),先过滤出有效的球员详情页链接,再逐页解析结构化字段即可,完整可运行代码如下:

import requests
from bs4 import BeautifulSoup
import time

# 模拟浏览器请求头,避免被反爬拦截
HEADERS = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
}
BASE_DOMAIN = "https://basketball.realgm.com"

def get_player_links(list_page_url):
    """从球员列表页提取去重后的有效球员详情页链接"""
    valid_links = []
    resp = requests.get(list_page_url, headers=HEADERS)
    soup = BeautifulSoup(resp.text, "html.parser")
    for a_tag in soup.find_all("a"):
        href = a_tag.get("href", "")
        # 按路径规则过滤球员详情页链接
        if "/player/" in href and "/Summary/" in href:
            full_link = BASE_DOMAIN + href
            if full_link not in valid_links:
                valid_links.append(full_link)
    return valid_links

def parse_single_player(player_url):
    """解析单个球员详情页,返回结构化基础资料"""
    player_info = {}
    resp = requests.get(player_url, headers=HEADERS)
    soup = BeautifulSoup(resp.text, "html.parser")
    # 精准定位球员资料框
    profile_box = soup.find("div", class_="profile-box")
    if not profile_box:
        return player_info
    # 提取球员姓名
    player_info["full_name"] = profile_box.find("h2").get_text(strip=True)
    # 遍历资料框内p标签,按冒号拆分键值对
    for p_tag in profile_box.find_all("p"):
        line = p_tag.get_text(strip=True)
        if ":" in line:
            field, value = line.split(":", 1)
            player_info[field.strip()] = value.strip()
    return player_info

if __name__ == "__main__":
    all_player_data = []
    # 遍历三个年份的球员列表页
    for year in [2020, 2021, 2022]:
        list_url = f"{BASE_DOMAIN}/dleague/players/{year}"
        print(f"正在抓取{year}年球员列表...")
        player_links = get_player_links(list_url)
        print(f"当前年份共获取到{len(player_links)}个有效球员链接")
        for link in player_links:
            try:
                data = parse_single_player(link)
                if data:
                    all_player_data.append(data)
                    print(f"已完成抓取:{data.get('full_name')}")
                # 加1秒延时,避免请求过频被封IP
                time.sleep(1)
            except Exception as e:
                print(f"抓取链接{link}出错,错误信息:{str(e)}")
                continue
    print(f"\n全部抓取完成,共获取{len(all_player_data)}条球员结构化数据")

注意事项

  • 批量爬取必须添加合理延时,不要短时间内向目标网站发送大量请求,否则极易被封禁IP
  • 提取页面内容时尽量定位到最小范围的目标父容器,可大幅减少后续数据清洗的工作量
  • 所有提取到的链接必须做规则过滤和去重,避免无效请求

内容的提问来源于stack exchange,提问作者Anthony Madle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 08:39:19