Dans cet article, j'aimerais compléter cet article et vous expliquer comment utiliser Wikipédia WikiExtractor de manière plus flexible, en filtrant les articles par catégorie.
Tout a commencé par le fait que j'avais besoin de définitions pour différents termes. Les termes et leurs définitions sont généralement la première phrase de chaque page Wikipédia. En suivant le chemin le plus simple, j'ai extrait tous les articles et j'ai rapidement récupéré tout ce dont j'avais besoin avec des habitués. Le problème est que les définitions ont dépassé 500 Mo et qu'il y avait trop de choses inutiles, par exemple, des entités nommées, des villes, des années, etc. dont je n'ai pas besoin.
J'ai correctement supposé que l'outil WikiExtractor (j'utiliserai une version différente, le lien sera ci-dessous) a une sorte de filtre, et il s'est avéré être un filtre de catégorie. Les catégories sont des balises pour les articles qui ont une structure hiérarchique pour organiser les pages. J'étais heureux de mettre en place la catégorie "Sciences exactes", croyant très naïvement que tous les articles qui se rapportent aux sciences exactes seront inclus dans la liste, mais le miracle ne s'est pas produit - chaque page a son propre petit ensemble de catégories et il n'y a aucune information sur une seule page sur la façon dont ces catégories sont liées. Cela signifie que si j'ai besoin de pages sur les sciences exactes, je dois indiquer toutes les catégories qui sont les descendants de "Sciences exactes".
Eh bien, peu importe, maintenant je vais trouver un service, pensais-je, qui expédierait facilement toutes les catégories d'un début donné à moi. Malheureusement, je n'ai trouvé cela que là où vous pouvez voir comment ces catégories sont liées. Une tentative d'itération manuelle sur les catégories a également échoué, mais j'étais "content" que ces catégories aient une structure non pas d'un arbre, comme je le pensais tout ce temps, mais juste d'un graphe orienté avec des cycles. De plus, la hiérarchie elle-même flotte beaucoup - je dirai à l'avance qu'en définissant le point de départ "Mathématiques", vous pouvez facilement atteindre Alexandre I. En conséquence, il me suffisait de restaurer ce graphique localement et d'obtenir en quelque sorte une liste de catégories qui m'intéressaient.
, : - , , , - .
Ubuntu 16.04, , , 18.04 .
- ruwiki-latest-pages-articles.xml.bz2
- ruwiki-latest-categorylinks.sql.gz
- ruwiki-latest-category.sql.gz
- ruwiki-latest-page.sql.gz
categorylinks , , [[Category:Title]] , . cl_from, id , cl_to, . , id , page () page_id page_title. , . , , , , , . category([](category table)) cat_title. pages-articles.xml .
mysql. ,
sudo apt-get install mysql-server mysql-client
, mysql , .
$ mysql -u username -p
mysql> create database category;
mysql> create database categorylinks;
mysql> create database page;
, . .
$ mysql -u username -p category < ruwiki-latest-category.sql
$ mysql -u username -p categorylinks < ruwiki-latest-categorylinks.sql
$ mysql -u username -p page < ruwiki-latest-page.sql
, csv.
mysql> select page_title, cl_to from categorylinks.categorylinks join page.page
on cl_from = page_id where page_title in (select cat_title from category) INTO outfile '/var/lib/mysql-files/category.csv' FIELDS terminated by ';' enclosed by '"' lines terminated by '\n';
. .
, , — , . , , , , 1,6 1,1. .
import pandas as pd
import networkx as nx
from tqdm.auto import tqdm, trange
#Filtering
df = pd.read_csv("category.csv", sep=";", error_bad_lines=False)
df = df.dropna()
df_filtered = df[df.parant.str.contains("[--]+:") != True]
df_filtered = df_filtered[df_filtered.parant.str.contains(",_") != True]
df_filtered = df_filtered[df_filtered.parant.str.contains("__") != True]
df_filtered = df_filtered[df_filtered.parant.str.contains("_") != True]
df_filtered = df_filtered[df_filtered.parant.str.contains(",_") != True]
df_filtered = df_filtered[df_filtered.parant.str.contains("__") != True]
df_filtered = df_filtered[df_filtered.parant.str.contains("__") != True]
df_filtered = df_filtered[df_filtered.parant.str.contains("_") != True]
df_filtered = df_filtered[df_filtered.parant.str.contains("__") != True]
df_filtered = df_filtered[df_filtered.parant.str.contains("") != True]
# Graph recovering
G = nx.DiGraph()
c = 0
for i, gr in tqdm(df_filtered.groupby('child')):
vertex = set()
edges = []
for i, r in gr.iterrows():
G.add_node(r.parant, color="white")
G.add_node(r.child, color="white")
G.add_edge(r.parant, r.child)
, , , , .
counter = 0
nodes = []
def dfs(G, node, max_depth):
global nodes, counter
G.nodes[node]['color'] = 'gray'
nodes.append(node)
counter += 1
if counter == max_depth:
counter -= 1
return
for v in G.successors(node):
if G.nodes[v]['color'] == 'white':
dfs(G, v, max_depth)
elif G.nodes[v]['color'] == 'gray':
continue
counter -= 1
, nodes . " " 5 . 2500 . , , , , - , , , — , . , , .
, .
_
CAM
__
_
_
__
__
__
__
__
___
_
...
_
___
__
_____
_
_
____
_
_
_
_
__
_
_()
...
_
_
_
_
_
_
-_
_
_
_
_
_
Cependant, pour appliquer ces catégories au filtrage de la langue russe, vous devez modifier quelque chose dans les sources. J'ai utilisé cette version. Il y a maintenant quelque chose de nouveau, peut-être que les correctifs ci-dessous ne sont plus pertinents. Dans le fichier WikiExtractor.py, vous devez remplacer «Catégorie» par «Catégorie» à deux endroits. Les zones avec la version déjà corrigée sont présentées ci-dessous:
tagRE = re.compile(r'(.*?)<(/?\w+)[^>]*?>(?:([^<]*)(<.*?>)?)?')
# 1 2 3 4
keyRE = re.compile(r'key="(\d*)"')
catRE = re.compile(r'\[\[:([^\|]+).*\]\].*') # capture the category name [[Category:Category name|Sortkey]]"
def load_templates(file, output_file=None):
...
if inText:
page.append(line)
# extract categories
if line.lstrip().startswith('[[:'):
mCat = catRE.search(line)
if mCat:
catSet.add(mCat.group(1))
Après cela, vous devez exécuter la commande
python WikiExtractor.py --filter_category categories --output wiki_filtered ruwiki-latest-pages-articles.xml
où categories est le fichier avec les catégories. Les articles filtrés seront dans wiki_filtered.
C'est tout. Merci de votre attention.