将 h4 映射到数据帧 Beautifulsoup python 中的 div 个兄弟姐妹
Map h4 to div siblings in dataframe Beautifulsoup python
我正在抓取网页,但无法将信息映射到数据框中。 HTML 中没有表格。这是 HTML:
的示例
html= [
<h2>Event Title<h2>
<div class="row">
<h4>Category 1<h4>
<div>A<div>
<h4>Category 2<h4>
<div>B<div>
<h4>Category 3<h4>
<div>C<div>
<h4>Category 4<h4>
<div>D<div>
]
这是我在 python 中使用请求和 Beautifulsoup 的代码:
data = []
event = soup.find('h2')
for i in soup.find_all('div', {'class': 'row'}):
categories = [x.text for x in i.findAll('h4')]
info = [x.text for x in i.findAll('div')]
datum = {'event': event.get_text().replace('\n', '').replace('\r', ''),
'categories ': categories ,
'info ': info }
data.append(datum)
df = pd.DataFrame(data)
df
数据框最终看起来像一个事件标题和两个列表:
index - event - categories - info
1 - Event Title - ['Category 1','Category 2','Category 3','Category 4'] - ["Category 1 \n A\n Category 2\n B\n Category 3\n C\n Category 4\n D\n"]
我希望它以某种方式映射以结束,以便 h4 类别 1 与 div A 相关。
index - event - categories - info
1 - Event Title - Category 1 - A
2 - Event Title - Category 2 - B
3 - Event Title - Category 3 - C
4 - Event Title - Category 4 - D
由于 h4 和 div 是兄弟姐妹而不是 parent-child ,可以在我的网络抓取代码中将其分开吗?我有多个事件标题不同的页面,而且数据太大,无法手动完成。
我也试过,其中:
data = []
event = soup.find('h2').get_text()
for i in soup.find_all('div', {'class': 'row'}):
categories = [x.text for x in soup.findAll('h4')]
cats = soup.find_all('h4')
cat = cats[3]
info = cat.findNextSiblings('div')
datum = {'event': event, 'categories ': categories , 'info': info}
data.append(datum)
df1 = pd.DataFrame(data)
df1
这个结果给了我一个 df:
index - event - categories - info
1 - Event Title - ['Category 1','Category 2','Category 3','Category 4'] - [<div>A<div>, <div>B<div>, <div>C<div>, <div>D<div>]
这是检查元素的网页链接:
https://www.ibjjfdb.com/ChampionshipResults/926/PublicResults
任何想法都会有所帮助。谢谢!
类型、类别和信息在您的链接 example 中都处于同一级别,因此您必须遍历它们并在遇到新类型或类别时立即更新类型和类别(请注意——我不得不为结果类型引入一个新的列类型。
关于 pandas 数据框:如果您首先将所有数据收集到一个列表中,然后才在最后从该列表中创建一个数据框,那么它在性能方面要好得多,并且在代码中也更容易阅读.
import pandas as pd
import requests
from bs4 import BeautifulSoup
import re
data = []
r = requests.get("https://www.ibjjfdb.com/ChampionshipResults/926/PublicResults")
soup = BeautifulSoup(r.content)
event = soup.find('h2').get_text(strip=True)
for i in soup.find_all('div', {'class': 'col-xs-12'}):
for s in i.find_all(['h3','h4','div'],recursive=False):
if s.name == 'h3':
typ = re.sub('\s+', ' ', s.get_text(strip=True))
elif s.name == 'h4':
cat = re.sub('\s+', ' ', s.get_text(strip=True))
elif s.name == 'div':
divs = s.find_all('div')
if len(divs) > 0:
for di in divs:
info = re.sub('\s+', ' ', di.get_text(strip=True))
else:
info = re.sub('\s+', ' ', s.get_text(strip=True))
data.append((event,typ,cat,info))
df = pd.DataFrame(data, columns=['Event','Type','Category','Info'])
这会产生一个具有 452 行和 4 列的数据帧,示例输出 df.iloc[0]
:
Event World Jiu-Jitsu IBJJF Championship 2018
Type Results of Academies
Category Adult Male
Info 10 - Ribeiro Jiu-Jitsu - 15
我正在抓取网页,但无法将信息映射到数据框中。 HTML 中没有表格。这是 HTML:
的示例html= [
<h2>Event Title<h2>
<div class="row">
<h4>Category 1<h4>
<div>A<div>
<h4>Category 2<h4>
<div>B<div>
<h4>Category 3<h4>
<div>C<div>
<h4>Category 4<h4>
<div>D<div>
]
这是我在 python 中使用请求和 Beautifulsoup 的代码:
data = []
event = soup.find('h2')
for i in soup.find_all('div', {'class': 'row'}):
categories = [x.text for x in i.findAll('h4')]
info = [x.text for x in i.findAll('div')]
datum = {'event': event.get_text().replace('\n', '').replace('\r', ''),
'categories ': categories ,
'info ': info }
data.append(datum)
df = pd.DataFrame(data)
df
数据框最终看起来像一个事件标题和两个列表:
index - event - categories - info
1 - Event Title - ['Category 1','Category 2','Category 3','Category 4'] - ["Category 1 \n A\n Category 2\n B\n Category 3\n C\n Category 4\n D\n"]
我希望它以某种方式映射以结束,以便 h4 类别 1 与 div A 相关。
index - event - categories - info
1 - Event Title - Category 1 - A
2 - Event Title - Category 2 - B
3 - Event Title - Category 3 - C
4 - Event Title - Category 4 - D
由于 h4 和 div 是兄弟姐妹而不是 parent-child ,可以在我的网络抓取代码中将其分开吗?我有多个事件标题不同的页面,而且数据太大,无法手动完成。
我也试过,其中:
data = []
event = soup.find('h2').get_text()
for i in soup.find_all('div', {'class': 'row'}):
categories = [x.text for x in soup.findAll('h4')]
cats = soup.find_all('h4')
cat = cats[3]
info = cat.findNextSiblings('div')
datum = {'event': event, 'categories ': categories , 'info': info}
data.append(datum)
df1 = pd.DataFrame(data)
df1
这个结果给了我一个 df:
index - event - categories - info
1 - Event Title - ['Category 1','Category 2','Category 3','Category 4'] - [<div>A<div>, <div>B<div>, <div>C<div>, <div>D<div>]
这是检查元素的网页链接: https://www.ibjjfdb.com/ChampionshipResults/926/PublicResults
任何想法都会有所帮助。谢谢!
类型、类别和信息在您的链接 example 中都处于同一级别,因此您必须遍历它们并在遇到新类型或类别时立即更新类型和类别(请注意——我不得不为结果类型引入一个新的列类型。
关于 pandas 数据框:如果您首先将所有数据收集到一个列表中,然后才在最后从该列表中创建一个数据框,那么它在性能方面要好得多,并且在代码中也更容易阅读.
import pandas as pd
import requests
from bs4 import BeautifulSoup
import re
data = []
r = requests.get("https://www.ibjjfdb.com/ChampionshipResults/926/PublicResults")
soup = BeautifulSoup(r.content)
event = soup.find('h2').get_text(strip=True)
for i in soup.find_all('div', {'class': 'col-xs-12'}):
for s in i.find_all(['h3','h4','div'],recursive=False):
if s.name == 'h3':
typ = re.sub('\s+', ' ', s.get_text(strip=True))
elif s.name == 'h4':
cat = re.sub('\s+', ' ', s.get_text(strip=True))
elif s.name == 'div':
divs = s.find_all('div')
if len(divs) > 0:
for di in divs:
info = re.sub('\s+', ' ', di.get_text(strip=True))
else:
info = re.sub('\s+', ' ', s.get_text(strip=True))
data.append((event,typ,cat,info))
df = pd.DataFrame(data, columns=['Event','Type','Category','Info'])
这会产生一个具有 452 行和 4 列的数据帧,示例输出 df.iloc[0]
:
Event World Jiu-Jitsu IBJJF Championship 2018
Type Results of Academies
Category Adult Male
Info 10 - Ribeiro Jiu-Jitsu - 15