@@ -35,6 +35,7 @@ def __init__(self, section_name):
3535 self .section_name = section_name
3636
3737 self .citations = False
38+ self .messagebox = False
3839 self .span_depth = 0
3940 self .div_depth = 0
4041
@@ -55,14 +56,35 @@ def handle_starttag(self, tag, attrs):
5556 if attr [0 ] == 'class' and 'edit' in attr [1 ]:
5657 self .span_depth += 1
5758
58- elif tag == 'div' : # We want to skip thumbnail text and the inexplicable table of contents, and as such also need to track div depth
59+ elif tag == 'div' :
60+ # We want to skip thumbnail text and the inexplicable table of contents,
61+ # and as such also need to track div depth
5962 if self .div_depth :
6063 self .div_depth += 1
6164 else :
6265 for attr in attrs :
6366 if attr [0 ] == 'class' and ('thumb' in attr [1 ] or attr [1 ] == 'toc' ):
6467 self .div_depth += 1
6568
69+ elif tag == 'table' :
70+ # Message box templates are what we want to ignore here
71+ for attr in attrs :
72+ if (
73+ attr [0 ] == 'class'
74+ and any (classname in attr [1 ].lower () for classname in [
75+ # Most of list from https://en.wikipedia.org/wiki/Template:Mbox_templates_see_also
76+ 'ambox' , # messageboxes on article pages
77+ 'cmbox' , # messageboxes on category pages
78+ 'imbox' , # messageboxes on file (image) pages
79+ 'tmbox' , # messageboxes on talk pages
80+ 'fmbox' , # header and footer messageboxes
81+ 'ombox' , # messageboxes on other types of page
82+ 'mbox' , # for messageboxes that are used in different namespaces and change their presentation accordingly
83+ 'dmbox' , # for disambiguation messageboxes
84+ ])
85+ ):
86+ self .messagebox = True
87+
6688 elif tag == 'ol' :
6789 for attr in attrs :
6890 if attr [0 ] == 'class' and 'references' in attr [1 ]:
@@ -77,9 +99,11 @@ def handle_endtag(self, tag):
7799 self .span_depth -= 1
78100 if self .div_depth and tag == 'div' :
79101 self .div_depth -= 1
102+ if self .messagebox and tag == 'table' :
103+ self .messagebox = False
80104
81105 def handle_data (self , data ):
82- if self .consume and not any ([self .citations , self .span_depth , self .div_depth ]):
106+ if self .consume and not any ([self .citations , self .messagebox , self . span_depth , self .div_depth ]):
83107 if not (self .is_header and data == self .section_name ): # Skip the initial header info only
84108 self .result += data
85109
@@ -225,14 +249,19 @@ def mw_section(server, query, section):
225249 for entry in sections ['parse' ]['sections' ]:
226250 if entry ['anchor' ] == section :
227251 section_number = entry ['index' ]
252+ # Needed to handle sections from transcluded pages properly
253+ # e.g. template documentation (usually pulled in from /doc subpage).
254+ # One might expect this prop to be nullable because in most cases it
255+ # will simply repeat the requested page title, but it's always set.
256+ fetch_title = quote (entry ['fromtitle' ])
228257 break
229258
230259 if not section_number :
231260 return None
232261
233262 snippet_url = ('https://{0}/w/api.php?format=json&redirects'
234263 '&action=parse&page={1}&prop=text'
235- '§ion={2}' ).format (server , query , section_number )
264+ '§ion={2}' ).format (server , fetch_title , section_number )
236265
237266 data = get (snippet_url ).json ()
238267
0 commit comments