]> code.communitydata.science - wikia_userroles_scraper.git/blob - userroles_from_logevents.py
8c28cc3c5df24ecbaa2f47150b5e7416bde94e27
[wikia_userroles_scraper.git] / userroles_from_logevents.py
1 #!/usr/bin/env python3
2
3 # Obtain user roles data from the Wikia logevents api
4 # Copyright (C) 2018  Nathan TeBlunthuis
5
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
10
11
12 from os import path
13 import argparse
14 import time
15 import re
16 import os
17 from json.decoder import JSONDecodeError
18 from scraper_utils import prepare_output, read_wikilist, add_parser_arguments
19 import requests
20
21
22 def write_logevents(logevents, out):
23     for logevent in logevents:
24         # if there is hidden information, we skip this one because there
25         # is nothing to report
26         if any(['userhidden' in logevent,
27                 'actionhidden' in logevent,
28                 'commenthidden' in logevent]):
29             continue
30
31         le_output = [logevent['comment'],
32                      str(logevent['logid']),
33                      str(logevent['ns']),
34                      str(logevent['pageid']),
35                      logevent['timestamp'],
36                      logevent['title'],
37                      logevent['type'],
38                      str(logevent['user'])]
39
40         if "rights" in logevent:
41             le_output.extend(['false',
42                               logevent['rights']['new'],
43                               logevent['rights']['old']])
44         else:
45             le_output.extend(['true', '', ''])
46
47         out.write("\t".join(le_output) + "\n")
48     out.flush()
49     # output data
50
51
52 def write_blockevents(logevents, out):
53     for logevent in logevents:
54         # if there is hidden information, we skip this one because there
55         # is nothing to report
56         if any(['userhidden' in logevent,
57                 'actionhidden' in logevent,
58                 'commenthidden' in logevent]):
59             continue
60
61         le_output = [logevent['comment'],
62                      str(logevent['logid']),
63                      str(logevent['ns']),
64                      str(logevent['pageid']),
65                      logevent['timestamp'],
66                      logevent['title'],
67                      logevent['type'],
68                      str(logevent['user'])]
69
70         if "rights" in logevent:
71             le_output.extend(['false',
72                               logevent['rights']['new'],
73                               logevent['rights']['old']])
74         else:
75             le_output.extend(['true', '', ''])
76
77         out.write("\t".join(le_output) + "\n")
78     out.flush()
79     # output data
80
81
82 def get_events_for_wiki(wikiname, url, output_dir, blocks_output=None, wikitype="wikia"):
83     out = open("{0}/{1}.tsv".format(output_dir, wikiname), "w")
84
85     out.write("\t".join(['comment', 'logid', 'ns', 'pageid', 'timestamp',
86                          'title', 'type', 'user', 'ancient', 'rights-new',
87                          'rights-old\n']))
88
89     if wikitype == "wikia":
90         api_url = url + '/api.php'
91     else:  # wikitype == wikipedia
92         api_url = url + "/w/api.php"
93
94     letype = 'rights'
95
96     if blocks_output is not None:
97         letype = 'rights|block|unblock'
98         blockout = open("{0}/{1}.tsv".format(blocks_output, wikiname), "w")
99         blockout.write("\t".join(['comment', 'logid', 'ns', 'pageid', 'timestamp',
100                                   'title', 'type', 'user', 'ancient', 'rights-new',
101                                   'rights-old\n']))
102
103     query = {'action': 'query',
104              'list': 'logevents',
105              'letype': letype,
106              'lelimit': '500',
107              'format': 'json',
108              'ledir': 'newer'}
109
110     try:
111         response = requests.get(api_url, params=query)
112         rv = response.json()
113
114     except (JSONDecodeError):
115         api_url = response.url
116         # print api_url # debug
117         if wikitype == "wikia":
118             re_str = "^http://(community|www).wikia.com/"
119         else:  # wikitype == "wikipedia"
120             re_str = "^(http|https)://.*wikipedia.org/"
121
122         if re.match(re_str, api_url):
123             # api_url
124             # 'http://community.wikia.com/wiki/Community_Central:Not_a_valid_Wikia':
125             print("ERROR: %s no longer exists" % wikiname)
126             return
127         else:
128             response = requests.get(api_url, params=query)
129             rv = response.json()
130
131     try:
132         logevents = rv['query']['logevents']
133
134         blockevents = [e for e in logevents
135                        if (e['action'] in ['block', 'unblock'])
136                        or (e['type'] in ['block', 'unblock'])]
137
138         logevents = [e for e in logevents if e not in blockevents]
139
140         write_logevents(logevents, out)
141
142         write_blockevents(blockevents, blockout)
143
144     except KeyError:
145         print("ERROR: %s contains no logevent data" % wikiname)
146         return
147
148     while 'query-continue' in rv or 'continue' in rv:
149         if 'query-continue' in rv:
150             query['lestart'] = rv['query-continue']['logevents']['lestart']
151         else:
152             query['continue'] = str(rv['continue'])
153             query['lecontinue'] = str(rv['continue']['lecontinue'])
154
155         response = requests.get(api_url, params=query)
156         rv = response.json()
157         logevents = rv['query']['logevents']
158         write_logevents(logevents, out)
159
160     out.close()
161
162
163 # the call is
164 # %run userroles_from_logevents.py --sep=\\t --nuke-old --blocks-output=/com/projects/messagewalls/userroles/blockevents ../identifyWikis/wikiteamWikilist.tsv /com/projects/messagewalls/userroles/listusers
165 if __name__ == '__main__':
166     parser = argparse.ArgumentParser(
167         description="Get user roles for Wikis from the Mediawiki list users API")
168
169     parser = add_parser_arguments(parser)
170
171     parser.add_argument('--blocks-output',
172                         type=str,
173                         help='Path to output block event logs. If empty, blocks are ignored.'
174                         )
175
176     args = parser.parse_args()
177     output_path = args.output
178     blocks_output = args.blocks_output
179     header = not args.no_header
180
181     prepare_output(output_path, args.nuke_old)
182
183     if blocks_output is not None:
184         prepare_output(blocks_output, args.nuke_old)
185
186     wikilist = read_wikilist(args)
187     deleted = []
188     notauthorized = []
189
190     files = [os.path.join(output_path, i) for i in os.listdir(output_path)]
191
192     # interate through the list of wikis
193     # for line in ["anime,http://anime.wikia.com/"]:
194     # for line in ["blogging,http://blogging.wikia.com/"]:
195     wikilist = read_wikilist(args)
196
197     # for line in open("list_of_wikis.csv", "r").readlines():
198
199     for wiki, url, wikitype in wikilist:
200         if "{0}.{1}".format(path.join(output_path, wiki), 'tsv') in files:
201             print("SKIPPING: file \"%s\" already exists)" % wiki)
202             continue
203
204         if wiki in files:
205             print("SKIPPING: file \"%s\" already exists)" % wiki)
206             continue
207
208         print("Processing wiki: %s" % wiki)
209         get_events_for_wiki(
210             wiki,
211             url,
212             output_dir=output_path,
213             blocks_output=blocks_output,
214             wikitype=wikitype)
215
216         time.sleep(1)

Community Data Science Collective || Want to submit a patch?