]> code.communitydata.science - covid19.git/blob - wikipedia/scripts/fetch_enwiki_revisions.py
2c0ef7ab1aed2d179507258416ef9544b550cbc5
[covid19.git] / wikipedia / scripts / fetch_enwiki_revisions.py
1 #!/usr/bin/env python3
2
3 ###############################################################################
4 #
5 # This script assumes the presence of the COVID-19 repo.
6
7 # It (1) reads in the article list and then (2) calls the Wikimedia API to 
8 # fetch view information for each article. Output is to (3) JSON and TSV.
9 #
10 ###############################################################################
11
12 import argparse
13 import logging
14 import os.path
15 import json
16 import datetime
17
18 from requests import Request
19 from csv import DictWriter
20 from mw import api
21 import digobs
22
23
24 def parse_args():
25
26     parser = argparse.ArgumentParser(description='Call the views API to collect Wikipedia revision data.')
27     parser.add_argument('-o', '--output_folder', help='Where to save output', default="wikipedia/data", type=str)
28     parser.add_argument('-i', '--article_file', help='File listing article names', default="wikipedia/resources/enwp_wikiproject_covid19_articles.txt", type=str)
29     parser.add_argument('-L', '--logging_level', help='Logging level. Options are debug, info, warning, error, critical. Default: info.', default='info', type=str), 
30     parser.add_argument('-W', '--logging_destination', help='Logging destination file. (default: standard error)', type=str), 
31     args = parser.parse_args()
32     return(args)
33
34 def main():
35     args = parse_args()
36
37     output_path = args.output_folder
38     article_filename = args.article_file
39
40     #handle -L
41     loglevel = digobs.get_loglevel(args.logging_level)
42
43     #handle -W
44     if args.logging_destination:
45         logging.basicConfig(filename=args.logging_destination, filemode='a', level=loglevel)
46     else:
47         logging.basicConfig(level=loglevel)
48
49     export_time = str(datetime.datetime.now())
50     export_date = datetime.datetime.today().strftime("%Y%m%d")
51
52     logging.info(f"Starting run at {export_time}")
53     logging.info(f"Last commit: {digobs.git_hash()}")
54
55     json_output_filename = os.path.join(output_path, f"digobs_covid19-wikipedia-enwiki_revisions-{export_date}.json")
56     tsv_output_filename =  os.path.join(output_path, f"digobs_covid19-wikipedia-enwiki_revisions-{export_date}.tsv")
57     
58     api_session = api.Session("https://en.wikipedia.org/w/api.php")
59
60     # list of properties from the API we want to gather (basically all of
61     # them supported by mediawik-utilities)
62
63     rv_props =  {'revid' : 'ids',
64                  'timestamp' : 'timestamp',
65                  'user' : 'user',
66                  'userid' : 'userid',
67                  'size' : 'size',
68                  'sha1' : 'sha1',
69                  'contentmodel' : 'contentmodel',
70                  'tags' : 'tags',
71                  'flags' : 'flags',
72                  'comment' : 'comment',
73                  'content' : 'content' }
74
75     exclude_from_tsv = ['tags', 'comment', 'content', 'flags']
76
77     # load the list of articles
78     with open(article_filename, 'r') as infile:
79         article_list= list(map(str.strip, infile))
80
81     def get_revisions_for_page(title):
82         return api_session.revisions.query(properties=rv_props.values(),
83                                            titles={title},
84                                            direction="newer")
85
86     tsv_fields = ['title', 'pageid', 'namespace']
87     tsv_fields = tsv_fields + list(rv_props.keys())
88
89     # drop fields that we identified for exclusion
90     tsv_fields = [e for e in tsv_fields if e not in exclude_from_tsv]
91
92     # add special export fields
93     tsv_fields = tsv_fields + ['anon', 'minor', 'url', 'export_timestamp', 'export_commit']
94
95     export_info = { 'git_commit' : digobs.git_hash(),
96                     'timestamp' : export_time }
97
98     with open(json_output_filename, 'w') as json_output, \
99          open(tsv_output_filename, 'w') as tsv_output:
100
101         tsv_writer = DictWriter(tsv_output, fieldnames=tsv_fields, delimiter="\t")
102         tsv_writer.writeheader()
103
104         for article in article_list:
105             logging.info(f"pulling revisions for: {article}")
106             for rev in get_revisions_for_page(article):
107                 logging.debug(f"processing raw revision: {rev}")
108
109                 # add export metadata
110                 rev['exported'] = export_info
111
112                 # save the json version of the code
113                 print(json.dumps(rev), file=json_output)
114
115                 # handle missing data
116                 if "sha1" not in rev:
117                     rev["sha1"] = ""
118
119                 if "userhidden" in rev:
120                     rev["user"] = ""
121                     rev["userid"] = ""
122
123                 # recode anon so it's true or false instead of present/missing
124                 if "anon" in rev:
125                     rev["anon"] = True
126                 else:
127                     rev["anon"] = False
128                     
129                 # let's recode "minor" in the same way
130                 if "minor" in rev:
131                     rev["minor"] = True
132                 else:
133                     rev["minor"] = False
134
135                 # add page title information
136                 rev['title'] = rev['page']['title']
137                 rev['pageid'] = rev['page']['pageid']
138                 rev['namespace'] = rev['page']['ns']
139
140                 # construct a URL
141                 rev['url'] = Request('GET', 'https://en.wikipedia.org/w/index.php',
142                                      params={'title' : rev['title'].replace(" ", "_"),
143                                             'oldid' : rev['revid']}).prepare().url
144
145                 rev['export_timestamp'] = export_time
146                 rev['export_commit'] = digobs.git_hash(short=True)
147
148                 tsv_writer.writerow({k: rev[k] for k in tsv_fields})
149
150 if __name__ == "__main__":
151     main()

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