我正试图从foreset.com上获取某些信息。我似乎能够获取主队、awayteam、位置,但无法获取预测分数、正确分数或天气。
有人能看看我的代码,告诉我家里的预测分数,正确的分数和天气吗。这是我迄今为止的代码:
from bs4 import BeautifulSoup
import requests
source = requests.get('https://www.forebet.com/en/predictions-world/world-cup').text
soup = BeautifulSoup(source, 'lxml')
teams= soup.find_all('a', class_= 'tnmscn')
for team in teams:
hometeam = team.find('span',class_= 'homeTeam').text
predictedscore = team.select_one('div', class_='ex_sc tabonly')
awayteam = team.find('span',class_ = 'awayTeam').text
date = team.find('span', class_='date_bah').text
location = team.find('name address', 'content').text
weather = team.find('span', class_="wnums")[0].text
print(hometeam,predictedscore ,awayteam,date,weather)
感谢的帮助
尝试抓取forest.com似乎无法抓取所有必要的数据。
您使用tnmscn
类在超链接中循环,但这只涵盖团队和日期信息;如果你还想要更多的数据,比如位置/天气/分数/赔率等。,你需要覆盖整排
# teams = soup.find_all('a', class_= 'tnmscn')
rows = soup.find_all('div', {'class': 'rcnt'})
# for team in teams:
for r in rows:
hometeam = r.find('span',class_= 'homeTeam').text
#### AND SO ON ####
(您也可以使用for team in soup.find_all('div', {'class': 'rcnt'})
进行循环,并在循环中继续使用team.find...
-这在结果方面不会有什么不同,但我认为for r in rows...
在整个行上循环[而不仅仅是主客场球队列]更有意义。)
关于使用此行获取位置:
location = team.find('name address', 'content').text
我在这行上得到AttributeError,因为.find('name address', 'content')
返回None
[而您无法从None
]获得.text
]。如果您没有收到这样的错误,我会感到非常惊讶,因为.find
的主要输入应该是一个标签名称,而试图查找name address
永远不会返回任何内容,因为html标签名称中没有空格。
关于用这条线获得预测分数:
predictedscore = team.select_one('div', class_='ex_sc tabonly')
class_
不是可以传递给.select
/.select_one
的参数,所以它只是选择team
中的第一个div
。您可以传递更精细的CSS选择器,因此它应该像.select_one('div.ex_sc.tabonly')
那样。
应该使用的是.find('span', {'itemprop': 'location'}).meta['content']
来获取meta
标签的content
属性,例如。
此外,请不要说这实际上会给你带来正确的分数,而不是预测的分数。
以获取预测分数、正确分数和天气
如果你在整行上循环,那么你可以使用
.find('span', class_='forepr').text
获得预测得分.find('div', class_='ex_sc tabonly').text
以获得正确的分数.find('div', class_="prwth tabonly")
来获取天气,但它可能会丢失,所以您应该- 在另一行中有
if weather: weather = weather.text
以避免获得AttributeError - [如果您想跳过这样的"行",请使用
else: continue
添加另一行。]
- 在另一行中有
建议的解决方案:
尽管这只是这里的天气数据的一个问题,但在尝试获取.text
之前,检查.find...
或.select...
返回了什么总是更安全的;由于您重复执行[.find....text
],因此将其作为一个函数更方便。
我已经有了一个函数,我在使用bs4进行刮擦时经常使用它,但它使用的是.select_one
(而不是.find
)。你所需要的只是一个选择器列表,如果你使用列表理解,你可以在一个语句中获得所有数据:
# def selectForList.... # PASTE FROM https://pastebin.com/ZnZ7xM6u
rData = [selectForList(r, [
'span.homeTeam', 'span.awayTeam', # home/away teams
'span.forepr', 'div.ex_sc.tabonly', # pred/correct scores
'span.date_bah', # date [location below]
('span[itemprop="location"]>meta[itemprop="name address"][content]', 'content'),
'div.prwth.tabonly>span.wnums', # temperature
]) for r in soup.select('div.rcnt')]
您可以通过使用printList=' '
设置selectForList
的打印选项进行打印,也可以循环使用rData
来更好地控制打印方式。
for r in rData:
print(f'# {r[0]} vs {r[1]}: {r[3] if r[3] else "score_unknown"}',
f'[pred: {r[2]}] on {r[4]} (at {r[5]})',
f'[{("temp: "+r[6]) if r[6] else "no_weather_data"}]')
### PRINTED OUTPUT BELOW ###
# Argentina vs France: 2 - 2 [pred: X] on 18/12/2022 16:00 (at Lusail Iconic Stadium) [temp: 21°]
# Croatia vs Morocco: 0 - 0 [pred: X] on 17/12/2022 16:00 (at Khalifa International Stadium) [temp: 22°]
# Argentina vs Croatia: 1 - 1 [pred: X] on 13/12/2022 20:00 (at Lusail Iconic Stadium) [temp: 22°]
# France vs Morocco: 3 - 1 [pred: 1] on 14/12/2022 20:00 (at Al Bayt Stadium) [temp: 22°]
# Juventus W vs Zurich (W): score_unknown [pred: 1] on 15/12/2022 18:45 (at Allianz Stadium) [no_weather_data]
# SL Benfica (W) vs Barcelona (W): score_unknown [pred: 2] on 15/12/2022 21:00 (at Caixa Futebol Campus) [no_weather_data]
对于稍微结构化的输出,您可以为选择器定义[而不是列表]一个参考字典(selRef
),然后获得与selRef
:具有相同键的字典列表中的数据
selRef = {'home_team': 'span.homeTeam', 'away_team': 'span.awayTeam', 'pred-y_n': ('div[class^="predict"]:has(>span.forepr)', 'class'), 'pred': 'span.forepr', 'correct_score': 'div.ex_sc.tabonly', 'date': 'span.date_bah', 'location': ('span[itemprop="location"]>meta[itemprop="name address"][content]', 'content'), 'temperature': 'div.prwth.tabonly>span.wnums', 'weather_icon': ('div.prwth.tabonly>img.wthc[src]', 'src')}
rdList = [dict(zip(
selRef.keys(), selectForList(r, selRef.values()) #, printList=' ')
)) for r in soup.select('div.rcnt')]
那么您可以使用panda将其转换为DataFrame,就像pandas.DataFrame(rdList)
一样。[查看数据帧]
您可能会注意到,除了拆分预测之外,我还添加了一个weather_icon
列。此列可用于添加天气的描述
wiRef = {'w-32': 'sunny', 'w-31': 'clear', 'w-30':'cloudy-day', 'w-29':'cloudy-night', 'w-20': 'fog', 'w-12': 'rainy-day', 'w-11': 'rainy-night'}
for ri, w in ([(i, r['weather_icon']) for i, r in enumerate(rdList) if r['weather_icon']]):
rdList[ri]['weather_icon'] = f'https://www.forebet.com{w}' # replace with full link
w = w.split('/')[-1].split('.png')[0].strip()
rdList[ri]['weather'] = wiRef[w] if w in wiRef else f'{w}.png'
# import pandas
pandas.DataFrame(rdList).to_csv('wcPreds.csv', index=False)
天气图标的完整列表以及输出"wcPreds.csv"的内容可以在该电子表格中找到。
您可以使用print(pandas.DataFrame(rdList).drop(['weather_icon'], axis=1).rename({'temperature':'temp'}, axis=1).to_markdown(index=False))
打印下表的标记:
home_team | 位置 | temp | 天气 |
---|---|---|---|
阿根廷 | 21° | 清除 | |
克罗地亚 | 清除 | ||
阿根廷 | 清除 | ||
法国 | 清除 | ||
尤文图斯W | nan | ||
SL Benfica(W) | nan |