从键字典中,如果正则表达式为真,则在 python 中拆分为两个键和值
From key dictionary, split into both two keys and values in python if regex is true
当我发现下一个问题时,我正试图做一些网络抓取:
这些是我搜索的链接的嵌套字典输出:
d1 = {'Gaia Project': {'Jugadores': '1 a 4', 'Duración': '60 – 150 minutos', 'Edad': '12+', 'Dureza': '4.37', 'Precio': '59,46€', 'Género': 'Eurogame – Mayorías', 'Editorial': 'Maldito Games', 'Diseñador/a': 'Jens Drögemüller', 'Total': '8.5', 'Aspecto / Componentes': '8', 'Diversión': '8', 'Variabilidad': '9.5', 'Originalidad': '9', 'Mecánicas': '8.5', 'Nota de lectores10 Votos': '8.5'}}
d2 = {'Churchill': {'Jugadores': '1 a 3', 'Duración': '60 – 300 minutos', 'Edad': '14+', 'Dureza': '3.28', 'Precio': '71,96€', 'Género': 'Eurogame – Construcción de Rutas, Económico.', 'Editorial': 'GMT Games\xa0/\xa0Devir', 'Diseñador/a': 'Mark Herman', 'Total': '8.9', 'Aspecto / Componentes': '8.1', 'Interacción': '9.7', 'Variabilidad': '8', 'Originalidad': '8.7', 'Mecánicas': '9.2'}}
正如您在 d1 中看到的,最后一类提到:
'Nota de lectores10 Votos': '8.5'
我想拆分成两个键和值,所以字典应该是这样的(见最后):
{'Gaia Project': {'Jugadores': '1 a 4', 'Duración': '60 – 150 minutos', 'Edad': '12+', Dureza': '4.37', 'Precio': '59,46€', 'Género': 'Eurogame – Mayorías', 'Editorial': 'Maldito Games', 'Diseñador/a': 'Jens Drögemüller', 'Total': '8.5', 'Aspecto / Componentes': '8', 'Diversión': '8', 'Variabilidad': '9.5', 'Originalidad': '9', 'Mecánicas': '8.5', 'Nota de lectores': '8.5', 'N. Votes: 10 Votos'}}
这是我试过的:
pattern_votes= r' de lectores\d.*'
if key.startswith('Nota'):
lectores = category.split(pattern_votes)
category.append(lectores[0],"N. Votes")
value.append(lectores[1])
其中 category 将是 'N. Votes' 和 value '10 Votos'。
我也尝试了 if(filter(pattern_votes,d1))
但显然没有任何反应。
这些分别是来自类别和值的列表:
category = ['Jugadores', 'Duración', 'Edad', 'Dureza', 'Precio', 'Género', 'Editorial', 'Diseñador/a', 'Total', 'Aspecto / Componentes', 'Diversión', 'Variabilidad', 'Originalidad', 'Mecánicas', 'Nota de lectores10 Votos']
value = ['1 a 4', '60 – 150 minutos', '12+', '4.37', '59,46€', 'Eurogame – Mayorías', 'Maldito Games', 'Jens Drögemüller', '8.5', '8', '8', '9.5', '9', '8.5', '8.5']
感谢您的帮助!
编辑
正如 Kuldeep 所建议的,这是我的代码:
最后这个字符串是我试过没用的
import requests
import re
from bs4 import BeautifulSoup
import os
from collections import defaultdict
link = "https://mishigeek.com/gaia-project-resena-en-solitario/"
link2 = "https://mishigeek.com/churchill-resena-en-espanol-es-un-wargame/"
#def get_ratings(review):
# Capturo la cabecera de la petición HTTP
def get_info(link):
headers = requests.utils.default_headers()
headers.update(
{
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.82 Safari/537.36',
}
)
# Me conecto a la url con .get()
sitemap_soup = requests.get(link, headers=headers)
sitemap_soup.close()
if (sitemap_soup.ok==True):
soup = BeautifulSoup(sitemap_soup.text,features="html.parser")
d= defaultdict(dict)
key=[]
category=[]
value=[]
otros=[] # Other set of category and values that will have to split.
pattern = r'-resena.*$'
pattern_votes= r' de lectores\d.*'
# Mediante los bucle for, se buscan todos los valores que coincida con el soup.select
for each_part in soup.select('figure[class*="wp-block-table"]'):
for each_part in soup.select('tr'):
otros.append(each_part.get_text())
split_items = (i.split(':') for i in otros[:8])
category, value = zip(*split_items)
category, value = map(list, (category, value))
nombre = re.sub(pattern,'',os.path.basename(link[:-1])).replace('-', ' ').title()
key.append(nombre)
category.append("Total")
for each_part in soup.select('div[class*="lets-review-block lets-review-block__final-score"]'):
value.append(each_part.get_text())
for each_part in soup.select('div[class*="lets-review-block__crit__title lr-font-h"]'):
category.append(each_part.get_text())
for each_part in soup.select('div[class*="lets-review-block__crit__score"]'):
value.append(each_part.get_text())
for k in key:
for c,v in zip(category,value):
d[k][c]=v
print(d)
print(category)
print(value)
'''
if key.startswith('Nota'):
lectores = category.split(pattern_votes)
category.append(lectores[0],"N. Votos")
value.append(lectores[1])
'''
我们的步骤是什么:
- 遍历所有电影及其属性
- 查找具有特定名称的属性
- 提取票数
- 更新属性
让我们来实施它:
import re
pattern = r"Nota de lectores(\d+).*" # our pattern to match full key and extract number of votes
for movie, properties in movies.items(): # 1
m = None
for k, v in properties.items():
if m := re.match(pattern, k): # 2, this syntax assumes python 3.8
break
if m is not None:
# 4
del properties[m.group(0)] # remove old key
properties["Nota de lectores"] = v # store previous value
properties["Votes"] = m.group(1) # 3
请注意,我们无法在循环期间更新属性,因为我们无法在迭代期间更改字典大小。
让我们从最小的问题开始:如何将 'Nota de lectores10 Votos' 拆分为 'Nota de lectores' 和 '10 Votos'。我的方法是使用 itertools
库:使用 takewhile
获取第一个数字之前的部分,使用 dropwhile
获取从第一个数字开始的部分。
import itertools
def split_before_number(text):
"""Split text into 2 parts: before the first digit and the rest."""
def not_digit(c):
"""Return True if character c is not a digit."""
return not c.isdigit()
before = ''.join(itertools.takewhile(not_digit, text))
after = ''.join(itertools.dropwhile(not_digit, text))
return before, after
测试一下:
>>> split_before_number('Nota de lectores10 Votos')
('Nota de lectores', '10 Votos')
接下来,我想解决将一对key/value转换为1对或2对的问题:
# This pair 'Jugadores': '1 a 4'
# Becomes: 'Jugadores': '1 a 4'
# This pair: 'Nota de lectores10 Votos': '8.5'
# Becomes: 'Nota de lectores': '8.5'
# and 'N. Votes': '10 Votos'
对应的代码:
def split_key_and_value(key, value):
if not key.startswith("Nota"):
yield key, value
return
key1, value2 = split_before_number(key)
yield key1, value
yield "N. Votes", value2
测试一下:
>>> dict(split_key_and_value('Nota de lectores10 Votos', "8.5"))
{'Nota de lectores': '8.5', 'N. Votes': '10 Votos'}
>>> dict(split_key_and_value("Jugadores", "1 a 4"))
{'Jugadores': '1 a 4'}
有了这些函数,我们现在可以解决更大的问题:转换 d1
的值的键和值,我称之为 v1
:
def transform(dict_object):
"""Split some specific keys and values and form a new dict."""
new_dict_object = {}
for original_key, original_value in dict_object.items():
for key, value in split_key_and_value(original_key, original_value):
new_dict_object[key] = value
return new_dict_object
测试一下:
>>> d1 = {'Gaia Project': {'Jugadores': '1 a 4',
'Duración': '60 – 150 minutos',
'Edad': '12+',
'Dureza': '4.37',
'Precio': '59,46€',
'Género': 'Eurogame – Mayorías',
'Editorial': 'Maldito Games',
'Diseñador/a': 'Jens Drögemüller',
'Total': '8.5',
'Aspecto / Componentes': '8',
'Diversión': '8',
'Variabilidad': '9.5',
'Originalidad': '9',
'Mecánicas': '8.5',
'Nota de lectores10 Votos': '8.5'}}
>>> v1 = d1["Gaia Project"]
>>> transform(v1)
{'Jugadores': '1 a 4',
'Duración': '60 – 150 minutos',
'Edad': '12+',
'Dureza': '4.37',
'Precio': '59,46€',
'Género': 'Eurogame – Mayorías',
'Editorial': 'Maldito Games',
'Diseñador/a': 'Jens Drögemüller',
'Total': '8.5',
'Aspecto / Componentes': '8',
'Diversión': '8',
'Variabilidad': '9.5',
'Originalidad': '9',
'Mecánicas': '8.5',
'Nota de lectores': '8.5',
'N. Votes': '10 Votos'}
现在我们可以转换 d1
值,我们可以在 d1 上应用该转换:
>>> d1 = {key: transform(value) for key, value in d1.items()}
>>> d1
{'Gaia Project': {'Jugadores': '1 a 4',
'Duración': '60 – 150 minutos',
'Edad': '12+',
'Dureza': '4.37',
'Precio': '59,46€',
'Género': 'Eurogame – Mayorías',
'Editorial': 'Maldito Games',
'Diseñador/a': 'Jens Drögemüller',
'Total': '8.5',
'Aspecto / Componentes': '8',
'Diversión': '8',
'Variabilidad': '9.5',
'Originalidad': '9',
'Mecánicas': '8.5',
'Nota de lectores': '8.5',
'N. Votes': '10 Votos'}}
当我发现下一个问题时,我正试图做一些网络抓取:
这些是我搜索的链接的嵌套字典输出:
d1 = {'Gaia Project': {'Jugadores': '1 a 4', 'Duración': '60 – 150 minutos', 'Edad': '12+', 'Dureza': '4.37', 'Precio': '59,46€', 'Género': 'Eurogame – Mayorías', 'Editorial': 'Maldito Games', 'Diseñador/a': 'Jens Drögemüller', 'Total': '8.5', 'Aspecto / Componentes': '8', 'Diversión': '8', 'Variabilidad': '9.5', 'Originalidad': '9', 'Mecánicas': '8.5', 'Nota de lectores10 Votos': '8.5'}}
d2 = {'Churchill': {'Jugadores': '1 a 3', 'Duración': '60 – 300 minutos', 'Edad': '14+', 'Dureza': '3.28', 'Precio': '71,96€', 'Género': 'Eurogame – Construcción de Rutas, Económico.', 'Editorial': 'GMT Games\xa0/\xa0Devir', 'Diseñador/a': 'Mark Herman', 'Total': '8.9', 'Aspecto / Componentes': '8.1', 'Interacción': '9.7', 'Variabilidad': '8', 'Originalidad': '8.7', 'Mecánicas': '9.2'}}
正如您在 d1 中看到的,最后一类提到:
'Nota de lectores10 Votos': '8.5'
我想拆分成两个键和值,所以字典应该是这样的(见最后):
{'Gaia Project': {'Jugadores': '1 a 4', 'Duración': '60 – 150 minutos', 'Edad': '12+', Dureza': '4.37', 'Precio': '59,46€', 'Género': 'Eurogame – Mayorías', 'Editorial': 'Maldito Games', 'Diseñador/a': 'Jens Drögemüller', 'Total': '8.5', 'Aspecto / Componentes': '8', 'Diversión': '8', 'Variabilidad': '9.5', 'Originalidad': '9', 'Mecánicas': '8.5', 'Nota de lectores': '8.5', 'N. Votes: 10 Votos'}}
这是我试过的:
pattern_votes= r' de lectores\d.*'
if key.startswith('Nota'):
lectores = category.split(pattern_votes)
category.append(lectores[0],"N. Votes")
value.append(lectores[1])
其中 category 将是 'N. Votes' 和 value '10 Votos'。
我也尝试了 if(filter(pattern_votes,d1))
但显然没有任何反应。
这些分别是来自类别和值的列表:
category = ['Jugadores', 'Duración', 'Edad', 'Dureza', 'Precio', 'Género', 'Editorial', 'Diseñador/a', 'Total', 'Aspecto / Componentes', 'Diversión', 'Variabilidad', 'Originalidad', 'Mecánicas', 'Nota de lectores10 Votos']
value = ['1 a 4', '60 – 150 minutos', '12+', '4.37', '59,46€', 'Eurogame – Mayorías', 'Maldito Games', 'Jens Drögemüller', '8.5', '8', '8', '9.5', '9', '8.5', '8.5']
感谢您的帮助!
编辑 正如 Kuldeep 所建议的,这是我的代码:
最后这个字符串是我试过没用的
import requests
import re
from bs4 import BeautifulSoup
import os
from collections import defaultdict
link = "https://mishigeek.com/gaia-project-resena-en-solitario/"
link2 = "https://mishigeek.com/churchill-resena-en-espanol-es-un-wargame/"
#def get_ratings(review):
# Capturo la cabecera de la petición HTTP
def get_info(link):
headers = requests.utils.default_headers()
headers.update(
{
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.82 Safari/537.36',
}
)
# Me conecto a la url con .get()
sitemap_soup = requests.get(link, headers=headers)
sitemap_soup.close()
if (sitemap_soup.ok==True):
soup = BeautifulSoup(sitemap_soup.text,features="html.parser")
d= defaultdict(dict)
key=[]
category=[]
value=[]
otros=[] # Other set of category and values that will have to split.
pattern = r'-resena.*$'
pattern_votes= r' de lectores\d.*'
# Mediante los bucle for, se buscan todos los valores que coincida con el soup.select
for each_part in soup.select('figure[class*="wp-block-table"]'):
for each_part in soup.select('tr'):
otros.append(each_part.get_text())
split_items = (i.split(':') for i in otros[:8])
category, value = zip(*split_items)
category, value = map(list, (category, value))
nombre = re.sub(pattern,'',os.path.basename(link[:-1])).replace('-', ' ').title()
key.append(nombre)
category.append("Total")
for each_part in soup.select('div[class*="lets-review-block lets-review-block__final-score"]'):
value.append(each_part.get_text())
for each_part in soup.select('div[class*="lets-review-block__crit__title lr-font-h"]'):
category.append(each_part.get_text())
for each_part in soup.select('div[class*="lets-review-block__crit__score"]'):
value.append(each_part.get_text())
for k in key:
for c,v in zip(category,value):
d[k][c]=v
print(d)
print(category)
print(value)
'''
if key.startswith('Nota'):
lectores = category.split(pattern_votes)
category.append(lectores[0],"N. Votos")
value.append(lectores[1])
'''
我们的步骤是什么:
- 遍历所有电影及其属性
- 查找具有特定名称的属性
- 提取票数
- 更新属性
让我们来实施它:
import re
pattern = r"Nota de lectores(\d+).*" # our pattern to match full key and extract number of votes
for movie, properties in movies.items(): # 1
m = None
for k, v in properties.items():
if m := re.match(pattern, k): # 2, this syntax assumes python 3.8
break
if m is not None:
# 4
del properties[m.group(0)] # remove old key
properties["Nota de lectores"] = v # store previous value
properties["Votes"] = m.group(1) # 3
请注意,我们无法在循环期间更新属性,因为我们无法在迭代期间更改字典大小。
让我们从最小的问题开始:如何将 'Nota de lectores10 Votos' 拆分为 'Nota de lectores' 和 '10 Votos'。我的方法是使用 itertools
库:使用 takewhile
获取第一个数字之前的部分,使用 dropwhile
获取从第一个数字开始的部分。
import itertools
def split_before_number(text):
"""Split text into 2 parts: before the first digit and the rest."""
def not_digit(c):
"""Return True if character c is not a digit."""
return not c.isdigit()
before = ''.join(itertools.takewhile(not_digit, text))
after = ''.join(itertools.dropwhile(not_digit, text))
return before, after
测试一下:
>>> split_before_number('Nota de lectores10 Votos')
('Nota de lectores', '10 Votos')
接下来,我想解决将一对key/value转换为1对或2对的问题:
# This pair 'Jugadores': '1 a 4'
# Becomes: 'Jugadores': '1 a 4'
# This pair: 'Nota de lectores10 Votos': '8.5'
# Becomes: 'Nota de lectores': '8.5'
# and 'N. Votes': '10 Votos'
对应的代码:
def split_key_and_value(key, value):
if not key.startswith("Nota"):
yield key, value
return
key1, value2 = split_before_number(key)
yield key1, value
yield "N. Votes", value2
测试一下:
>>> dict(split_key_and_value('Nota de lectores10 Votos', "8.5"))
{'Nota de lectores': '8.5', 'N. Votes': '10 Votos'}
>>> dict(split_key_and_value("Jugadores", "1 a 4"))
{'Jugadores': '1 a 4'}
有了这些函数,我们现在可以解决更大的问题:转换 d1
的值的键和值,我称之为 v1
:
def transform(dict_object):
"""Split some specific keys and values and form a new dict."""
new_dict_object = {}
for original_key, original_value in dict_object.items():
for key, value in split_key_and_value(original_key, original_value):
new_dict_object[key] = value
return new_dict_object
测试一下:
>>> d1 = {'Gaia Project': {'Jugadores': '1 a 4',
'Duración': '60 – 150 minutos',
'Edad': '12+',
'Dureza': '4.37',
'Precio': '59,46€',
'Género': 'Eurogame – Mayorías',
'Editorial': 'Maldito Games',
'Diseñador/a': 'Jens Drögemüller',
'Total': '8.5',
'Aspecto / Componentes': '8',
'Diversión': '8',
'Variabilidad': '9.5',
'Originalidad': '9',
'Mecánicas': '8.5',
'Nota de lectores10 Votos': '8.5'}}
>>> v1 = d1["Gaia Project"]
>>> transform(v1)
{'Jugadores': '1 a 4',
'Duración': '60 – 150 minutos',
'Edad': '12+',
'Dureza': '4.37',
'Precio': '59,46€',
'Género': 'Eurogame – Mayorías',
'Editorial': 'Maldito Games',
'Diseñador/a': 'Jens Drögemüller',
'Total': '8.5',
'Aspecto / Componentes': '8',
'Diversión': '8',
'Variabilidad': '9.5',
'Originalidad': '9',
'Mecánicas': '8.5',
'Nota de lectores': '8.5',
'N. Votes': '10 Votos'}
现在我们可以转换 d1
值,我们可以在 d1 上应用该转换:
>>> d1 = {key: transform(value) for key, value in d1.items()}
>>> d1
{'Gaia Project': {'Jugadores': '1 a 4',
'Duración': '60 – 150 minutos',
'Edad': '12+',
'Dureza': '4.37',
'Precio': '59,46€',
'Género': 'Eurogame – Mayorías',
'Editorial': 'Maldito Games',
'Diseñador/a': 'Jens Drögemüller',
'Total': '8.5',
'Aspecto / Componentes': '8',
'Diversión': '8',
'Variabilidad': '9.5',
'Originalidad': '9',
'Mecánicas': '8.5',
'Nota de lectores': '8.5',
'N. Votes': '10 Votos'}}