Python 抓取维基百科类别页面
Python scraping of Wikipedia category page
我有这个维基百科分类页面:https://fr.wikipedia.org/wiki/Cat%C3%A9gorie:Pi%C3%A8ce_de_th%C3%A9%C3%A2tre_du_XVIIIe_si%C3%A8cle
我想打开列出的每个剧本的页面(例如 https://fr.wikipedia.org/wiki/L%27Oiseau_vert)并打印它的第一句话(例如 L'Oiseau vert (L'augellino belverde) est une comédie de Carlo Gozzi (auteur italien de pièces de théâtre) parue en 1765)。第一列有播放标题,第二列有第一句话的数据框也不错。
我试图通过 BeautifulSoup
获取所有页面链接并用 wikipedia.summary()
打印第一句但结果并不令人满意,因为 wikipedia
模块经常重定向到错误的文章.部分问题可能是由剧名中的法语特殊字符(é、â等)引起的
是否有更好的方法直接从分类页面访问个别文章?
似乎相关,但没有进一步帮助我。
下面是一个如何仅使用 beautifulsoup
即可实现的示例:
import requests
from bs4 import BeautifulSoup
def get_categories(data):
print("Getting categories...")
categories = {}
soup = BeautifulSoup(data, "lxml")
group_divs = soup.find_all("div", {"class": "mw-category-group"})
for div in group_divs:
links = div.find_all("a")
for link in links:
title = link.get("title")
href = link.get("href")
categories[title] = "https://fr.wikipedia.org" + href
print(f"Found Categories: {len(categories)}")
return categories
def get_first_paragraph(data):
soup = BeautifulSoup(data, "lxml")
parser_output = soup.find("div", {"class": "mw-parser-output"})
first_paragraph = parser_output.find("p", {"class": None}, recursive=False)
return first_paragraph.text
def process_categories(categories):
result = {}
for title, link in categories.items():
print(f"Processing Piece: {title}, on link: {link}")
data = requests.get(link).content
first_paragraph = get_first_paragraph(data)
result[title] = first_paragraph.strip()
return result
def clean_categories(categories):
return {k: v for k, v in categories.items() if "Catégorie" not in k}
def main():
categories_url = "https://fr.wikipedia.org/wiki/Cat%C3%A9gorie:Pi%C3%A8ce_de_th%C3%A9%C3%A2tre_du_XVIIIe_si%C3%A8cle"
data_categories = requests.get(categories_url).content
categories = get_categories(data_categories)
categories = clean_categories(categories)
result = process_categories(categories)
print(result) # create dataframe etc...
if __name__ == "__main__":
main()
代码不言自明:
- 首先我们找到有
category-group
class的div
,提取所有a
元素,得到title
和href
- 然后对于每个
category
即片段我们解析 HTML 并得到 div
中的第一个 p
和 mw-parser-output
class (那应该是第一句)。
Note: I added clean_categories
since category-group
picked up unwanted things that had Catégorie
in them.
前几部分的输出示例:
Getting categories...
Found Categories: 198
Processing Piece: Les Acteurs de bonne foi, on link: https://fr.wikipedia.org/wiki/Les_Acteurs_de_bonne_foi
Processing Piece: Adamire ou la Statue de l'honneur, on link: https://fr.wikipedia.org/wiki/Adamire_ou_la_Statue_de_l%27honneur
Processing Piece: Agamemnon (Lemercier), on link: https://fr.wikipedia.org/wiki/Agamemnon_(Lemercier)
Processing Piece: Agathocle (Voltaire), on link: https://fr.wikipedia.org/wiki/Agathocle_(Voltaire)
结果:
{"Adamire ou la Statue de l'honneur": "Adamire ou la Statue de l'honneur est "
'la traduction par Thomas-Simon '
'Gueullette de la pièce de théâtre '
"italienne l'Adamira overo la Statua "
"dell'Honore de Giacinto Andrea "
'Cicognini représentée pour la première '
'fois en France le 12 décembre 1717 à '
"Paris, à l'Hôtel de Bourgogne.",
'Agamemnon (Lemercier)': 'Agamemnon est une tragédie en cinq actes considérée '
"comme le chef-d'œuvre dramatique de Népomucène "
'Lemercier. Elle fut représentée au Théâtre de la '
'République le 5 floréal an V (24 avril 1797) et '
'valut à son auteur une célébrité immédiate.',
'Agathocle (Voltaire)': 'Agathocle est une tragédie écrite par Voltaire, '
'représentée pour la première fois le 31 mai 1779, '
'sur la scène de la Comédie-Française.',
'Les Acteurs de bonne foi': 'Les Acteurs de bonne foi est une comédie en un '
'acte et en prose de Marivaux, jouée pour la '
'première fois chez Quinault cadette le 30 '
'octobre 1748.'}
有一种更好的方法可以直接从类别页面访问各个文章:维基百科API!
你可以试试这个:
import requests
url = "https://fr.wikipedia.org/w/api.php"
params = {
"action": "query",
"cmtitle": "Catégorie:Pièce de théâtre du XVIIIe siècle",
"cmlimit": "50",
"list": "categorymembers",
"format": "json"
}
req = requests.get(url=url, params=params)
pages = req.json()['query']['categorymembers']
# here just iterate over category individual pages
for page in pages:
# eg. page = {'pageid': 622757, 'ns': 0, 'title': 'Les Acteurs de bonne foi'}
_url = 'https://fr.wikipedia.org/w/api.php'
_params = {
'format': 'json',
'action': 'query',
'prop': 'extracts',
'exintro': True,
'explaintext': True,
'redirects': 1,
'pageids': page['pageid'],
}
req = requests.get(_url, _params)
summary = req.json()['query']['pages'][str(page['pageid'])]['extract']
如果 'Les Acteurs de bonne foi' 摘要 returns:
'Les Acteurs de bonne foi est une comédie en un acte et en prose de
Marivaux, jouée pour la première fois chez Quinault cadette le 30
octobre 1748.\nMarivaux fit jouer les Acteurs de bonne foi au
Théâtre-Français en 1755, mais la pièce ne réussit pas. Elle fut
publiée pour la première fois dans le Conservateur de novembre 1757.
L’intérêt de la pièce repose principalement sur un jeu qu’entretient
Marivaux avec son lecteur grâce à la mise en abyme. En effet, le texte
mêle au sein d’une même page : entretien des acteurs sur leurs vies
respectives, dialogues sur les possibilités de jeu et de mise en scène
ainsi que répliques d’un texte qui est alors joué. Dans cette pièce,
qui est la dernière que l’auteur ait fait jouer sur un grand théâtre,
où la scène de comédie est rapidement détournée et donne lieu à une
confusion entre la situation réelle et la scène jouée, la mise en
abyme révèle l’importance de l’illusion théâtrale.'
我有这个维基百科分类页面:https://fr.wikipedia.org/wiki/Cat%C3%A9gorie:Pi%C3%A8ce_de_th%C3%A9%C3%A2tre_du_XVIIIe_si%C3%A8cle
我想打开列出的每个剧本的页面(例如 https://fr.wikipedia.org/wiki/L%27Oiseau_vert)并打印它的第一句话(例如 L'Oiseau vert (L'augellino belverde) est une comédie de Carlo Gozzi (auteur italien de pièces de théâtre) parue en 1765)。第一列有播放标题,第二列有第一句话的数据框也不错。
我试图通过 BeautifulSoup
获取所有页面链接并用 wikipedia.summary()
打印第一句但结果并不令人满意,因为 wikipedia
模块经常重定向到错误的文章.部分问题可能是由剧名中的法语特殊字符(é、â等)引起的
是否有更好的方法直接从分类页面访问个别文章?
下面是一个如何仅使用 beautifulsoup
即可实现的示例:
import requests
from bs4 import BeautifulSoup
def get_categories(data):
print("Getting categories...")
categories = {}
soup = BeautifulSoup(data, "lxml")
group_divs = soup.find_all("div", {"class": "mw-category-group"})
for div in group_divs:
links = div.find_all("a")
for link in links:
title = link.get("title")
href = link.get("href")
categories[title] = "https://fr.wikipedia.org" + href
print(f"Found Categories: {len(categories)}")
return categories
def get_first_paragraph(data):
soup = BeautifulSoup(data, "lxml")
parser_output = soup.find("div", {"class": "mw-parser-output"})
first_paragraph = parser_output.find("p", {"class": None}, recursive=False)
return first_paragraph.text
def process_categories(categories):
result = {}
for title, link in categories.items():
print(f"Processing Piece: {title}, on link: {link}")
data = requests.get(link).content
first_paragraph = get_first_paragraph(data)
result[title] = first_paragraph.strip()
return result
def clean_categories(categories):
return {k: v for k, v in categories.items() if "Catégorie" not in k}
def main():
categories_url = "https://fr.wikipedia.org/wiki/Cat%C3%A9gorie:Pi%C3%A8ce_de_th%C3%A9%C3%A2tre_du_XVIIIe_si%C3%A8cle"
data_categories = requests.get(categories_url).content
categories = get_categories(data_categories)
categories = clean_categories(categories)
result = process_categories(categories)
print(result) # create dataframe etc...
if __name__ == "__main__":
main()
代码不言自明:
- 首先我们找到有
category-group
class的div
,提取所有a
元素,得到title
和href
- 然后对于每个
category
即片段我们解析 HTML 并得到div
中的第一个p
和mw-parser-output
class (那应该是第一句)。
Note: I added
clean_categories
sincecategory-group
picked up unwanted things that hadCatégorie
in them.
前几部分的输出示例:
Getting categories...
Found Categories: 198
Processing Piece: Les Acteurs de bonne foi, on link: https://fr.wikipedia.org/wiki/Les_Acteurs_de_bonne_foi
Processing Piece: Adamire ou la Statue de l'honneur, on link: https://fr.wikipedia.org/wiki/Adamire_ou_la_Statue_de_l%27honneur
Processing Piece: Agamemnon (Lemercier), on link: https://fr.wikipedia.org/wiki/Agamemnon_(Lemercier)
Processing Piece: Agathocle (Voltaire), on link: https://fr.wikipedia.org/wiki/Agathocle_(Voltaire)
结果:
{"Adamire ou la Statue de l'honneur": "Adamire ou la Statue de l'honneur est "
'la traduction par Thomas-Simon '
'Gueullette de la pièce de théâtre '
"italienne l'Adamira overo la Statua "
"dell'Honore de Giacinto Andrea "
'Cicognini représentée pour la première '
'fois en France le 12 décembre 1717 à '
"Paris, à l'Hôtel de Bourgogne.",
'Agamemnon (Lemercier)': 'Agamemnon est une tragédie en cinq actes considérée '
"comme le chef-d'œuvre dramatique de Népomucène "
'Lemercier. Elle fut représentée au Théâtre de la '
'République le 5 floréal an V (24 avril 1797) et '
'valut à son auteur une célébrité immédiate.',
'Agathocle (Voltaire)': 'Agathocle est une tragédie écrite par Voltaire, '
'représentée pour la première fois le 31 mai 1779, '
'sur la scène de la Comédie-Française.',
'Les Acteurs de bonne foi': 'Les Acteurs de bonne foi est une comédie en un '
'acte et en prose de Marivaux, jouée pour la '
'première fois chez Quinault cadette le 30 '
'octobre 1748.'}
有一种更好的方法可以直接从类别页面访问各个文章:维基百科API!
你可以试试这个:
import requests
url = "https://fr.wikipedia.org/w/api.php"
params = {
"action": "query",
"cmtitle": "Catégorie:Pièce de théâtre du XVIIIe siècle",
"cmlimit": "50",
"list": "categorymembers",
"format": "json"
}
req = requests.get(url=url, params=params)
pages = req.json()['query']['categorymembers']
# here just iterate over category individual pages
for page in pages:
# eg. page = {'pageid': 622757, 'ns': 0, 'title': 'Les Acteurs de bonne foi'}
_url = 'https://fr.wikipedia.org/w/api.php'
_params = {
'format': 'json',
'action': 'query',
'prop': 'extracts',
'exintro': True,
'explaintext': True,
'redirects': 1,
'pageids': page['pageid'],
}
req = requests.get(_url, _params)
summary = req.json()['query']['pages'][str(page['pageid'])]['extract']
如果 'Les Acteurs de bonne foi' 摘要 returns:
'Les Acteurs de bonne foi est une comédie en un acte et en prose de Marivaux, jouée pour la première fois chez Quinault cadette le 30 octobre 1748.\nMarivaux fit jouer les Acteurs de bonne foi au Théâtre-Français en 1755, mais la pièce ne réussit pas. Elle fut publiée pour la première fois dans le Conservateur de novembre 1757. L’intérêt de la pièce repose principalement sur un jeu qu’entretient Marivaux avec son lecteur grâce à la mise en abyme. En effet, le texte mêle au sein d’une même page : entretien des acteurs sur leurs vies respectives, dialogues sur les possibilités de jeu et de mise en scène ainsi que répliques d’un texte qui est alors joué. Dans cette pièce, qui est la dernière que l’auteur ait fait jouer sur un grand théâtre, où la scène de comédie est rapidement détournée et donne lieu à une confusion entre la situation réelle et la scène jouée, la mise en abyme révèle l’importance de l’illusion théâtrale.'