使用Python+BeautifulSoup爬取Transfermarkt球员数据分页问题
问题原因分析
- 索引越界报错:当前页面仅返回25条球员数据,你通过
find_all查询得到的Players、Values等列表长度最大为25,当循环索引超过24(列表从0开始计数)时自然会触发越界错误。 - 点击翻页URL不变:Transfermarkt的翻页参数为URL末尾附加的
page参数,肉眼看到URL无变化是浏览器前端渲染隐藏了参数,实际第二页请求地址就是原URL末尾拼接&page=2,第三页拼接&page=3,以此类推即可。
实现全量爬取的方案
1. 先修复单页提取逻辑的问题
你现有代码存在两个隐藏问题:
- 硬编码
range(0,25),部分页面可能数据不足25条,容易触发越界 - 缺少
Values_pre的提取逻辑,需要对应补上对应节点的查询代码
2. 增加翻页循环控制
外层加页码循环,直到某一页查询不到球员数据时自动停止即可,完整可运行代码参考如下:
import requests from bs4 import BeautifulSoup import pandas as pd import time import random headers = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'} base_url = "https://www.transfermarkt.co.uk/transfers/transferrekorde/statistik?saison_id=alle&land_id=0&ausrichtung=&spielerposition_id=&altersklasse=&leihe=&w_s=&plus=1" # 存储全量数据的列表 all_data = [] page_num = 1 while True: # 拼接翻页地址 current_url = f"{base_url}&page={page_num}" response = requests.get(current_url, headers=headers) # 请求失败就重试2次,还是失败就终止 if response.status_code != 200: for _ in range(2): time.sleep(2) response = requests.get(current_url, headers=headers) if response.status_code == 200: break else: print(f"第{page_num}页请求失败,终止爬取") break soup = BeautifulSoup(response.content, 'html.parser') Players = soup.find_all("a", {"class": "spielprofil_tooltip"}) # 没有球员数据说明爬完所有页了,终止循环 if not Players: print(f"所有页面爬取完成,共爬取{page_num-1}页") break Values = soup.find_all("td", {"class": "rechts hauptlink"}) # 注意这里补你自己的Values_pre提取逻辑,替换成对应节点的选择器 Values_pre = soup.find_all("替换为你对应节点的class或标签规则") Age = soup.find_all("td", {"class": "zentriert"}) # 单页循环用列表最小长度作为上限,避免越界 max_idx = min(len(Players), len(Values), len(Values_pre)//2, len(Age)//5) for i in range(max_idx): try: item = { "Players": Players[i].text, "Value_post": Values[i].text, "value_pre": Values_pre[2*i].text, "rank": Age[(5*i)].text, "age": Age[1 + (5*i)].text, "season": Age[2 + (5*i)].text, "missing": Age[3 + (5*i)].text, "team": Age[4 + (5*i)].text } all_data.append(item) except Exception as e: print(f"第{page_num}页第{i}条数据提取失败:{e}") continue print(f"第{page_num}页爬取完成,累计{len(all_data)}条数据") page_num += 1 # 加1-3秒随机延时,避免被封IP time.sleep(random.uniform(1, 3)) # 转成DataFrame df = pd.DataFrame(all_data) print(df.head())
注意事项
- 不要爬取频率过高,必须加延时,Transfermarkt反爬策略比较严格,高频请求容易被封IP
- 如果需要爬取大量数据,建议搭配代理IP池使用
- 部分特殊球员的字段可能存在缺失,可以根据自己的需求调整异常捕获的处理逻辑
内容的提问来源于stack exchange,提问作者Parsifal
相关产品推荐
相关产品推荐

