#!/opt/local/bin/python ##!/usr/bin/python # minidumper v. .01 # Copyright, 1995-2005, Brian Mingus # # This file is part of minidumper # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # Takes a mediawiki xml dump, a list of the pages that you want from # the xml dump and extracts them to stdout # Example usage: # minidumper wikipedia-xml-dump.xml allowed_titles.list --tags=title,id > minidump.xml from optparse import OptionParser import re class MiniDumper: def __init__(self): self.titleRE = re.compile(' (.*)\n') self.allowListRE = '' self.currentPage = '' self.xmlPOST = '' self.firstTime = True # For determining when to pring xmlPRE self.counter = 0 # So we know when to quit (don't parse the whole dump unnecessarily) self.limit = 0 # Needs to be set to the length of the list of titles you gave me self.finished = False # We check this to see if counter == limit, and print the end of the dump if so self.xmlPRE = '\ \n\ \n\ Wikipedia\n\ http://en.wikipedia.org/wiki/Main_Page\n\ MediaWiki 1.10alpha\n\ first-letter\n\ \n\ \n\ \n\ ' def PageBuilder(self, thisLine): """ This takes lines of input and uses them to build pages. It should be fairly robust to interference, as the correct number of spaces are required on the tags. When a page is completed (indicated by ) it is passed to AnalyzePage """ if thisLine == ' \n': self.currentPage = thisLine elif thisLine == ' \n': self.currentPage += thisLine self.AnalyzePage(self.currentPage) else: self.currentPage += thisLine def AllowList(self, listFileName): """ The allow list takes newline separated text file of page titles and returns a regular expression object that places boolean OR (|) before each title This was designed to work with a list of 150,000 titles, so pass it a big list if you want. """ f = open(listFileName,'r') titles = f.readlines() titles = [titles[i][:-1] for i in range(len(titles))] # removes trailing newlines titleList = [self.Escaper(title) for title in titles] self.limit = len(titleList) longLine = '' for title in range(len(titleList)): longLine += titleList[title] longLine = longLine[:-1] # remove trailing pipe print "Regex: " + longLine # TODO: why is this a list f.close() self.allowListRE = re.compile(longLine) def Escaper(self, string): """ Just puts a pipe inbetween each one and escapes it TODO: Remove trailing pipe! """ return str(re.escape(string) + '|') def AnalyzePage(self, page, allowedTags = []): """ AnalyzePage parses the page for its tags and compares it against the allow list You can optionally specify that you only want a subset of tags and the page will then be parsed by BeautifulSoup. It's a very cheap parse because we can use the SoupStrainer to only get the stuff we want. If the regular expression matches this pages title, send it to stdout """ # print "AnalyzePage: \n" + page titleMatch = self.titleRE.search(page) if titleMatch == None: return title = titleMatch.group(1) print "Title: " + title # Check title against supplied list if self.allowListRE.match(title) == None: return # It passed all of our checks - have it! print page self.counter += 1 if self.counter == self.limit: self.finished = True def main(): parser = OptionParser() parser.add_option("-t", "--tags", dest="tags", help="Comma-separated list of tags which are subordinate to the tag to pay attention to. Current tags in the dump are page, title, id, revision, etc...") (options, args) = parser.parse_args() xmlFile = args[0] listFile = args[1] extractor = MiniDumper() extractor.AllowList(listFile) f = open(xmlFile) thisLine = None print extractor.xmlPRE while not thisLine == '': thisLine = f.readline() extractor.PageBuilder(thisLine) if extractor.finished == True: print extractor.xmlPOST return main()