我正试图在一个网站上搜索板球俱乐部的成绩,但某一日期的比赛次数并没有固定。例如:2022年9月17日星期六有1场比赛,2022年9月下星期六有3场比赛。如果网站将日期分为不同的类别或表格,这会很简单,但事实并非如此。
import requests
import urllib3
import pandas as pd
from html.parser import HTMLParser
from bs4 import BeautifulSoup
网站的URL如下所示:-
#Url = Page 1 of results
url = 'https://halstead.play-cricket.com/Matches?fixture_month=13&home_or_away=both&page=1&q%5Bcategory_id%5D=all&q%5Bgender_id%5D=all&search_in=&season_id=255&seasonchange=f&selected_season_id=255&tab=Result&team_id=&utf8=%E2%9C%93&view_by=year'
data = requests.get(url).text
soup = BeautifulSoup(data, 'lxml')
主代码
#Creating the table
main_lists = {'Team A':[], '':[],'Team B':[]}
entries = soup.findAll('p', class_='txt1')
list = []
for entries in entries:
#Everything in one list
list.append(entries.text.strip('/n'))
#Separating entries by odd and even index
l = range(len(list))
list_even = list[::2]
list_odd = list [1::2]
for list_even in list_even:
main_lists['Team A'] += [list_even]
main_lists[''] += ['vs']
for list_odd in list_odd:
main_lists['Team B'] += [list_odd]
#Turn lists into dataframe
df_main = pd.DataFrame(main_lists)
#Getting result
res_list = []
x = 0
while x < df_main.shape[0]:
res = soup.select('.fonts-gt')[x];x += 1
res_list.append(res.text)
res_list = [sub.replace(' ',' ') for sub in res_list]
df_main['Result'] = res_list
df_main = df_main.reindex(columns=['Result', 'Team A', 'Team B'])
#Getting the Date
date = soup.findAll('div', class_='col-sm-12 text-center text-md-left title2 padding_top_for_mobile')
date_table = []
for date in date:
date_table.append(date.text.strip('n'))
date_table2 = [sub.replace('2022n', '2022') for sub in date_table]
df_date = pd.DataFrame(date_table2)
print(f'The length of df_main is {len(df_main)}, and the length of df_date is {len(df_date)}')
在这里,我们可以看到两个数据帧的行数的差异。
df_main的长度为25,df_date的长度为12
我确实尝试过使用类似的东西:-
items = soup.find_all(class_=['row ml-large-0 mr-large-0','col-sm-12 d-md-none match-status-mobile'])
for item in items:
print(item.text)
它给出了类似于:但我仍然不知道如何按日期来区分这些。
尝试更改选择策略并一次性提取信息。对匹配项进行迭代,并使用find_previous()
提取列出匹配项的相应日期。
在较新的代码中,避免使用旧的语法findAll()
,而使用find_all()
或select()
和css selectors
-要了解更多信息,请花一分钟时间检查文档
示例
import requests
from bs4 import BeautifulSoup
url='https://halstead.play-cricket.com/Matches?fixture_month=13&home_or_away=both&page=1&q%5Bcategory_id%5D=all&q%5Bgender_id%5D=all&search_in=&season_id=255&seasonchange=f&selected_season_id=255&tab=Result&team_id=&utf8=%E2%9C%93&view_by=year'
soup = BeautifulSoup(requests.get(url).text)
data = []
for e in soup.select('table'):
d = dict(zip(['Team A','Team B'],[t.text for t in e.select('.txt1')]))
d.update({
'Result':e.div.text,
'Date':e.find_previous('div',class_='title2').get_text(strip=True)
})
data.append(d)
pd.DataFrame(data)
输出
团队A | 团队B | |||
---|---|---|---|---|
0 | 埃塞克斯郡哈尔斯特德CC-第一届XI | Fakenham CC-第一个XI | Fakenham CC被8次WICKETS击败 | 022年9月17日星期六|
1 | Battisford&CC区-XI第一日星期六 | Halstead CC,埃塞克斯郡-XI第二日 | 取消 | 2022年9月10日星期六 |
2 | Maldon CC-第四届XI | 埃塞克斯郡哈尔斯特德CC-第三届XI | >取消2022年9月10日星期六 | |
3 | 埃塞克斯郡哈尔斯特德CC-第一届XI | Worlington CC-第一任XI | 哈斯特德CC,Essex WON BY 23 RUNS | 2022年9月10日星期六 |
21 | Halstead CC,埃塞克斯郡-NECL第一届XI | Wickham St Pauls CC-第一届XI | Wickham St Pauls CC被两个WICKETS击败 | 2022年7月31日星期日 |
22 | 埃塞克斯郡哈尔斯特德CC-XI第二郡 | West Bergholt CC-XI第一郡两个郡 | 埃塞克斯郡霍尔斯特德CC 3次跑步 | >2022年7月30日星期六 |
23 | Halstead CC,埃塞克斯郡-第三届XI | 艾伯顿&CC区-第三届XI | ABBERTON&2022年7月30日星期六,地区CC被6个WICKE | |
24 | Coggeshall镇CC-第一届XI | 埃塞克斯郡哈尔斯特德CC-第一任XI | Halstead CC,Essex WON BY 117 RUNS | 2022年7月30日星期六 |
这很困难,但是,一旦我改变了获取数据的方法,我就可以获得您想要的结果。
变化是:
- 获取
table
HTML元素内部的数据,该元素具有匹配项(,即团队A、团队B和结果) - 对于日期,当所述
div
没有table
HTML元素时,获取div
内部的文本
这是修改后的代码:
import requests
import urllib3
import pandas as pd
from html.parser import HTMLParser
import bs4
from bs4 import BeautifulSoup
#Url = Page 1 of results
url = 'https://halstead.play-cricket.com/Matches?fixture_month=13&home_or_away=both&page=1&q%5Bcategory_id%5D=all&q%5Bgender_id%5D=all&search_in=&season_id=255&seasonchange=f&selected_season_id=255&tab=Result&team_id=&utf8=%E2%9C%93&view_by=year'
data = requests.get(url).text
soup = BeautifulSoup(data, 'lxml')
# Variables:
result_array = [] # It will contain the list of dictionaries with the desired data.
team_a = "" # Value for "Team A" column.
team_b = "" # Value for "Team B" column.
result = "" # Value for "Result" column.
temp_date = "" # Stores the date.
# Get the main div that contains the data to extract:
div_principal = soup.find("div", class_="tab-pane fade active in")
# Loop the divs "i.e. the data of the matches and the date" found in the main container div:
for indx, div in enumerate(div_principal):
# Loop only the valid elements with the data to get:
if (indx >= 5 and indx <= 77):
# Check if the element is a valid BeautifulSoup "Tag" element:
# Source: https://stackoverflow.com/a/42802393/12511801
if type(div) is bs4.element.Tag:
# If no "table" is found on this div, then, it's a "date" - that's due I'm getting the "data" contained on the "table" HTML element:
if (div.find("table") is not None):
# Get the values for "Team A", "Team B" and "Result":
team_a = div.find('table').find("p", class_="txt1").get_text("", strip=True)
team_b = div.find('table').find("td", class_="col-xs-5 col-sm-3 col-md-3 text-center text-md-left card-table-r bgGray").find("p", class_="txt1").get_text("", strip=True)
# Here the original text has double spaces.
# Example: FAKENHAM CC WON BY 8 WICKETS
# (notice the double spaces between the words "WON" and "BY").
result = div.find('table').find("div", class_="fonts-gt").get_text("", strip=True).replace(" ", " ") # <== Here
else:
# Get the "date" and clear the other variables:
temp_date = div.get_text("", strip=True)
team_a = ""
team_b = ""
result = ""
# Add elements to the list:
if (len(team_a) > 0):
result_array.append({"Team A" : team_a, "Team B": team_b, "Result": result, "Date": temp_date})
# Remove duplicates - source: https://stackoverflow.com/a/9427216/12511801
result_array = [i for n, i in enumerate(result_array) if i not in result_array[n + 1:]]
# Build and display dataframe:
df_final = pd.DataFrame(result_array)
display(df_final)
结果:
索引 | 团队B | 结果日期|||
---|---|---|---|---|
0 | Halstead CC,埃塞克斯-第一届XI省 | Fakenham CC-1第一届XI省 | Fakenham CC被8个WICKETS击败 | 2022年9月17日星期六 |
1 | Battisford&CC区-XI第一区 | 哈尔斯特德CC,埃塞克斯-XI第二区 | 取消 | 2022年9月10日星期六 |
2 | 马尔顿CC-4第三届XI省 | 哈尔斯特德CC,埃塞克斯-第三届XI省 | 取消 | 2022年9月10日星期六 |
3 | 霍尔斯特德CC,埃塞克斯第一届XI | 沃灵顿CC-1st XI | 哈尔斯特德CC | |
4 | 霍尔斯特德CC,埃塞克斯-第二届XI | 邓莫CC-2和XI | 霍尔斯特德CC,艾塞克斯赢了25次2022年9月3日星期六 | |
5 | Mistley CC-1st XI | 哈尔斯特德CC,埃塞克斯-第一XI | 哈尔斯特德CC,艾塞克斯被4个WICKETS击败 | 2022年9月3日星期六|
6 | 埃塞克斯郡哈尔斯特德CC,NECL T20 | Coggeshall镇CC-NECL T20 | 2022年8月28日星期日,埃塞克斯郡霍尔斯特德CC以90分之差获胜 | |
7 | 哈尔斯特德CC,埃塞克斯NECL T20 | 米斯特里CC-NECL T202022年8月28日星期日,埃塞克斯哈尔斯特德CC以152跑的成绩获胜 | ||
8 | 霍尔斯特德CC,埃塞克斯第二届XI | Stowupland CC-1st XI | 哈尔斯特德CC | |
9 | 霍尔斯特德CC,埃塞克斯第三届XI队 | 真实赔率CC-1st XI队 | 哈尔斯特德CC | |
10 | 凯斯格雷夫CC-1st XI | 哈尔斯特德CC,埃塞克斯-第一XI | 哈尔斯特德CC,艾塞克斯被7个WICKETS击败 | 2022年8月27日星期六|
11 | Sudbury CC,萨福克郡-星期日XI第一届 | Halstead CC,埃塞克斯-NECL第一届XI | Sudbury CC,Suffolk以22分的成绩获胜 | 2022年8月21日星期日 |
12 | 圣玛格丽特CC,萨福克-第一XI省 | 哈尔斯特德CC,埃塞克斯-第二XI省 | 圣玛格丽特CC,苏福尔克以60分的优势获胜 | 2022年8月20日星期六 |
13 | Kelvedon和Feering CC-2nd XI | Halstead CC,Essex-3rd XI | >Kelvedon和Feerining CC被1个WICKET击败 | 2022年8月20日星期六 |
14 | 霍尔斯特德CC,埃塞克斯第一届XI | Woolpit CC-周六第一届XI | 哈尔斯特德CC | |
15 | 霍尔斯特德CC,埃塞克斯-第二届XI省 | 米尔登霍尔CC,萨福克-第四届XI省 | 哈尔斯特德CC | |
16 | 霍尔斯特德CC,埃塞克斯-第三届XI | Witham CC-3第三届XI | 哈尔斯特德CC | |
17 | Wivenhoe镇CC-1st XI | Halstead CC,Essex-1st XI | Halstead CC,Essex WON BY 3 WICKETS | 2022年8月13日星期六 |
18 | 霍尔斯特德CC,埃塞克斯-NECL第一届XI | 科尔切斯特和东埃塞克斯CC-NECL第一届XI | 霍尔斯特德CC,艾塞克斯被5个WICKETS击败>2022年8月7日星期日 | [/tr>|
19 | 伊普斯维奇CC-1st XI | 哈尔斯特德CC,埃塞克斯-XI第二届 | 哈尔斯特德CC,艾塞克斯以1次跑的优势获胜 | 2022年8月6日星期六 |
20 | 霍尔斯特德CC,埃塞克斯-第一XI省 | 海上克拉克顿CC-周六XI省 | 哈尔斯特德CC | |
21 | 霍尔斯特德CC,埃塞克斯-NECL第一届XI | 威克姆圣保罗CC-1st XI | 威克姆圣保罗CC被两个WICKETS击败 | 2022年7月31日星期日|
22 | Halstead CC,埃塞克斯-第二XI省 | West Bergholt CC-两个县,第一XI省 | Halstead CC2022年7月30日星期六 | |
23 | Halstead CC,埃塞克斯-第三XI省 | Abberton&CC-3区XI | ABBERTON&2022年7月30日星期六,CC区赢得6个奖杯 | |
24 | 科格斯霍尔镇CC-1st XI | 哈尔斯特德CC,埃塞克斯-第一XI | 哈尔斯特德CC,艾塞克斯以117次跑的成绩获胜 | 2022年7月30日星期六 |