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')
需要实现的最终效果:工具可一次性干净爬取球员姓名、当前效力球队、出生日期、出生地等结构化资料,若现有实现思路存在问题可直接指正。
问题解答
合并代码的核心错误
- 标签查找逻辑完全错误:代码中查找的是容器下所有
a标签,还调用get('p')方法取属性——get()是BeautifulSoup中获取标签属性的方法,p根本不是a标签的属性,自然拿不到任何有效内容,实际需要查找的是p标签而非a标签。 - 链接提取逻辑无过滤:现有爬列表页所有a标签的逻辑会拿到大量无关链接(导航栏、页脚、其他板块跳转链接),并非所有a标签都指向球员详情页,会导致后续请求大量无效地址报错。
- 提取范围过大:直接提取
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
相关产品推荐
相关产品推荐

