]> code.communitydata.science - covid19.git/blob - wikipedia/scripts/fetch_enwiki_revisions.py
Merge pull request #15 from aaronshaw/master
[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=digobs.get_loglevel), 
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 -W
41     if args.logging_destination:
42         logging.basicConfig(filename=args.logging_destination, filemode='a', level=args.logging_level)
43     else:
44         logging.basicConfig(level=args.logging_level)
45
46     export_time = str(datetime.datetime.now())
47     export_date = datetime.datetime.today().strftime("%Y%m%d")
48
49     logging.info(f"Starting run at {export_time}")
50     logging.info(f"Last commit: {digobs.git_hash()}")
51
52     json_output_filename = os.path.join(output_path, f"digobs_covid19-wikipedia-enwiki_revisions-{export_date}.json")
53     tsv_output_filename =  os.path.join(output_path, f"digobs_covid19-wikipedia-enwiki_revisions-{export_date}.tsv")
54     
55     api_session = api.Session("https://en.wikipedia.org/w/api.php")
56
57     # list of properties from the API we want to gather (basically all of
58     # them supported by mediawik-utilities)
59
60     rv_props =  {'revid' : 'ids',
61                  'timestamp' : 'timestamp',
62                  'user' : 'user',
63                  'userid' : 'userid',
64                  'size' : 'size',
65                  'sha1' : 'sha1',
66                  'contentmodel' : 'contentmodel',
67                  'tags' : 'tags',
68                  'flags' : 'flags',
69                  'comment' : 'comment',
70                  'content' : 'content' }
71
72     exclude_from_tsv = ['tags', 'comment', 'content', 'flags']
73
74     # load the list of articles
75     with open(article_filename, 'r') as infile:
76         article_list= list(map(str.strip, infile))
77
78     def get_revisions_for_page(title):
79         return api_session.revisions.query(properties=rv_props.values(),
80                                            titles={title},
81                                            direction="newer")
82
83     tsv_fields = ['title', 'pageid', 'namespace']
84     tsv_fields = tsv_fields + list(rv_props.keys())
85
86     # drop fields that we identified for exclusion
87     tsv_fields = [e for e in tsv_fields if e not in exclude_from_tsv]
88
89     # add special export fields
90     tsv_fields = tsv_fields + ['anon', 'minor', 'url', 'export_timestamp', 'export_commit']
91
92     export_info = { 'git_commit' : digobs.git_hash(),
93                     'timestamp' : export_time }
94
95     with open(json_output_filename, 'w') as json_output, \
96          open(tsv_output_filename, 'w') as tsv_output:
97
98         tsv_writer = DictWriter(tsv_output, fieldnames=tsv_fields, delimiter="\t")
99         tsv_writer.writeheader()
100
101         for article in article_list:
102             logging.info(f"pulling revisions for: {article}")
103             for rev in get_revisions_for_page(article):
104                 logging.debug(f"processing raw revision: {rev}")
105
106                 # add export metadata
107                 rev['exported'] = export_info
108
109                 # save the json version of the code
110                 print(json.dumps(rev), file=json_output)
111
112                 # handle missing data
113                 if "sha1" not in rev:
114                     rev["sha1"] = ""
115
116                 if "userhidden" in rev:
117                     rev["user"] = ""
118                     rev["userid"] = ""
119
120                 # recode anon so it's true or false instead of present/missing
121                 if "anon" in rev:
122                     rev["anon"] = True
123                 else:
124                     rev["anon"] = False
125                     
126                 # let's recode "minor" in the same way
127                 if "minor" in rev:
128                     rev["minor"] = True
129                 else:
130                     rev["minor"] = False
131
132                 # add page title information
133                 rev['title'] = rev['page']['title']
134                 rev['pageid'] = rev['page']['pageid']
135                 rev['namespace'] = rev['page']['ns']
136
137                 # construct a URL
138                 rev['url'] = Request('GET', 'https://en.wikipedia.org/w/index.php',
139                                      params={'title' : rev['title'].replace(" ", "_"),
140                                             'oldid' : rev['revid']}).prepare().url
141
142                 rev['export_timestamp'] = export_time
143                 rev['export_commit'] = digobs.git_hash(short=True)
144
145                 tsv_writer.writerow({k: rev[k] for k in tsv_fields})
146
147 if __name__ == "__main__":
148     main()

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