[PYTHON] Extraire des pages des vidages Wikipedia

Wikipedia fournit un vidage de toutes les pages. Bien qu'il s'agisse d'une énorme quantité de données, un index est préparé de manière à pouvoir être manipulé lors de sa compression. Récupérons réellement les données.

Préparation

Une description des données de vidage est ci-dessous.

Veillez à ne pas ouvrir le fichier XML décompressé dans un éditeur ou un navigateur classique en raison de la taille énorme du fichier.

Les données pour la version japonaise de Wikipedia sont ci-dessous.

À partir de l'édition du 1er mai 2020 disponible au moment de la rédaction, nous utiliserons les deux fichiers suivants.

  1. jawiki-20200501-pages-articles-multistream.xml.bz2 3.0 GB
  2. jawiki-20200501-pages-articles-multistream-index.txt.bz2 23.9 MB

Le premier XML est les données du corps. Puisqu'il est déjà compressé et de cette taille, ce sera une taille ridicule lorsqu'il est agrandi, mais il ne sera pas agrandi cette fois car il est considéré comme pouvant être manipulé tout en étant compressé.

Le deuxième index se développe. Ce sera environ 107 Mo.

spécification

L'article suivant examine la structure des balises XML vidées.

La structure de la partie principale est la suivante. Un élément est stocké dans une balise de page.

<mediawiki>
    <siteinfo> ⋯ </siteinfo>
    <page> ⋯ </page>
    <page> ⋯ </page>
           ⋮
    <page> ⋯ </page>
</mediawiki>

Le fichier bz2 ne compresse pas simplement l'intégralité du fichier XML, mais se compose de blocs de 100 éléments. Vous pouvez retirer le bloc et le déployer précisément. Cette structure est appelée ** multi-flux **.

siteinfopage × 100page × 100

L'index a la structure suivante pour chaque ligne.

décalage bz2:id:title

Vérifiez les données réelles.

$ head -n 5 jawiki-20200501-pages-articles-multistream-index.txt
690:1:Wikipedia:Téléchargement du journal avril 2004
690:2:Wikipedia:Supprimer l'enregistrement/Journal passé décembre 2002
690:5:Ampasand
690:6:Wikipedia:Sandbox
690:10:Langue

Pour connaître la longueur d'un bloc commençant à 690, vous devez savoir où commence le bloc suivant.

$ head -n 101 jawiki-20200501-pages-articles-multistream-index.txt | tail -n 2
690:217:Liste des musiciens(groupe)
814164:219:Liste des titres de chansons

Étant donné que chaque élément est un élément, vous pouvez trouver le nombre total d'éléments en comptant le nombre de lignes. Il y a environ 2,5 millions d'articles.

$ wc -l jawiki-20200501-pages-articles-multistream-index.txt
2495246 jawiki-20200501-pages-articles-multistream-index.txt

sortir

Supprimons en fait un élément spécifique. La cible est "Qiita".

Acquisition d'informations

Recherchez "Qiita".

$ grep Qiita jawiki-20200501-pages-articles-multistream-index.txt
2919984762:3691277:Qiita
3081398799:3921935:Template:Qiita tag
3081398799:3921945:Template:Qiita tag/doc

Ignorez le modèle et ciblez le premier id = 3691277.

Fondamentalement, il y a 100 éléments par bloc, mais il y a des exceptions et ils semblent ne pas être alignés, alors vérifiez manuellement la position de départ du bloc suivant.

2919984762:3691305:Category:Relations bilatérales du Gabon
2920110520:3691306:Category:Relations Japon-Cameloon

Vous disposez de toutes les informations dont vous avez besoin.

id bloquer 次のbloquer
3691277 2919984762 2920110520

Python

Démarrez Python.

$ python
Python 3.8.2 (default, Apr  8 2020, 14:31:25)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.

Ouvrez le fichier compressé.

>>> f = open("jawiki-20200501-pages-articles-multistream.xml.bz2", "rb")

Spécifiez le décalage pour récupérer le bloc contenant l'élément Qiita.

>>> f.seek(2919984762)
2919984762
>>> block = f.read(2920110520 - 2919984762)

Développez le bloc pour obtenir la chaîne.

>>> import bz2
>>> data = bz2.decompress(block)
>>> xml = data.decode(encoding="utf-8")

Et vérifiez le contenu. Contient 100 balises de page.

>>> print(xml)
  <page>
    <title>Category:Maire Eba</title>
    <ns>14</ns>
    <id>3691165</id>
(Omis)

C'est gênant comme il est, alors analysez-le comme XML. L'élément racine est requis pour l'analyse, alors ajoutez-le de manière appropriée.

>>> import xml.etree.ElementTree as ET
>>> root = ET.fromstring("<root>" + xml + "</root>")

Vérifiez le contenu. Il y a 100 balises de page sous la racine.

>>> len(root)
100
>>> [child.tag for child in root]
['page', 'page',(Omis), 'page']

Obtenez la page en spécifiant l'identifiant. L'argument de find est une notation appelée XPath.

>>> page = root.find("page/[id='3691277']")

Et vérifiez le contenu.

>>> page.find("title").text
'Qiita'
>>> page.find("revision/text").text[:50]
'{{Infobox Website\n|Nom du site=Qiita\n|logo=\n|capture d'écran=\n|Le crâne'

Enregistrez en tant que fichier.

>>> tree = ET.ElementTree(page)
>>> tree.write("Qiita.xml", encoding="utf-8")

Vous obtiendrez un fichier qui ressemble à ceci:

Qiita.xml


<page>
    <title>Qiita</title>
    <ns>0</ns>
    <id>3691277</id>
    <revision>
      <id>77245770</id>
      <parentid>75514051</parentid>
      <timestamp>2020-04-26T12:21:10Z</timestamp>
      <contributor>
        <username>Linuxmetel</username>
        <id>1613984</id>
      </contributor>
      <comment>Ajout d'une explication sur la controverse de Qiita et le stock LGTM</comment>
      <model>wikitext</model>
      <format>text/x-wiki</format>
      <text bytes="4507" xml:space="preserve">{{Infobox Website
|Nom du site=Qiita
(Omis)
[[Category:Site Web japonais]]</text>
      <sha1>mtwuh9z42c7j6ku1irgizeww271k4dc</sha1>
    </revision>
  </page>

scénario

Une série de flux est résumée dans un script.

Stockez et utilisez l'index dans SQLite.

SQLite

Le script convertit l'index en TSV et génère du SQL pour l'ingestion.

python conv_index.py jawiki-20200501-pages-articles-multistream-index.txt

Trois fichiers seront générés.

Importez dans SQLite.

sqlite3 jawiki.db ".read jawiki-20200501-pages-articles-multistream-index.sql"

Vous êtes maintenant prêt.

Comment utiliser

La base de données ne contient que l'index, vous avez donc besoin du fichier xml.bz2 dans le même répertoire. Ne le renommez pas car la base de données contient le nom de fichier xml.bz2.

Si vous spécifiez le nom de la base de données et de l'élément, le résultat sera affiché. Par défaut, seul le contenu de la balise de texte est spécifié, mais si vous spécifiez -x, toutes les balises à l'intérieur de la balise de page seront affichées.

python mediawiki.py jawiki.db Qiita
python mediawiki.py -x jawiki.db Qiita

Vous pouvez exporter vers un fichier.

python mediawiki.py -o Qiita.txt jawiki.db Qiita
python mediawiki.py -o Qiita.xml -x jawiki.db Qiita

mediawiki.py est conçu pour être utilisé comme bibliothèque.

import mediawiki
db = mediawiki.DB("jawiki.db")
print(db["Qiita"].text)

Article associé

Articles sur les modules multiflux et bz2.

référence

J'ai fait référence aux spécifications d'index de Wikipedia.

L'API XML ElementTree a référencé la documentation.

J'ai étudié comment utiliser SQLite lors du traitement de données d'exemple de phrase.

Recommended Posts

Extraire des pages des vidages Wikipedia
Extraire le tableau de wikipedia
Extraire des données d'une page Web avec Python
Extraire les redirections des vidages Wikipedia
Comment obtenir une liste de liens à partir d'une page de wikipedia
# 5 [python3] Extraire des caractères d'une chaîne de caractères
Comment extraire le coefficient de la formule minute
Extrayez la quantité de caractéristiques (identité) du texte.
Récupérer une image d'une page Web et la redimensionner
J'ai créé un outil pour créer un nuage de mots à partir de wikipedia
Extraire la valeur la plus proche d'une valeur à partir d'un élément de liste en Python
Extraire une langue spécifique du Wiktionnaire
Essayez d'extraire une chaîne de caractères d'une image avec Python3
Comment extraire la chaîne de caractères souhaitée à partir d'une ligne 4 commandes
J'ai écrit un script pour extraire les liens de pages Web en Python
Trouvez tous les modèles pour extraire un nombre spécifique de l'ensemble