前言
最近因為一些研究上的需要,需要進行問卷調查。雖然也可以用自己架的伺服器和網頁界面,可是難免擔心資安的疑慮。 於是就想到可以使用 Google Forms,來進行問卷調查與回收。 為了避免未來有需要時忘記作法,便記下筆記當作未來的參考。
這次將使用 Kaggle 的 Dogs vs. Cats 資料集作為示範,每題會給兩張圖片,要求使用者選出貓貓照片。
資料準備
首先下載 train.zip
並且解壓縮,緊接著我們撰寫一個程式來產生必要的檔案:
# prepare.py
def prepare(input_dir, output_dir, web_root, num_outputs, names, seed):
random.seed(seed)
image_dir = os.path.join(output_dir, 'images')
os.makedirs(image_dir, exist_ok=True)
# load choices for each question
choices = []
for name in names:
named_images = []
# write hashes of this name to a file
# so we can analyse results later
id_path = os.path.join(output_dir, name + '.txt')
with open(id_path, 'w') as id_file:
for i in range(1, num_outputs + 1):
fname = os.path.join(input_dir, '{}.{}.jpg'.format(name, i))
h = md5(fname)
named_images.append(h)
id_file.write(h + '\n')
# put images to a separate directory
outpath = os.path.join(image_dir, '{}.jpg'.format(h))
shutil.copyfile(fname, outpath)
choices.append(named_images)
# output url for each image
url_path = os.path.join(output_dir, 'urls.tsv')
with open(url_path, 'w') as outfile:
outfile.write('h\turl\n')
for named_images in choices:
for h in named_images:
outfile.write('{}\t{}/images/{}.jpg\n'.format(h, web_root, h))
# output survey file
survey_path = os.path.join(output_dir, 'survey.tsv')
with open(survey_path, 'w') as outfile:
header = '\t'.join([str(n) for n in range(1, len(names) + 1)])
outfile.write('num\t' + header + '\n')
for n in range(num_outputs):
options = [named_images[n] for named_images in choices]
random.shuffle(options)
outfile.write('{}\t{}\n'.format(n + 1, '\t'.join(options)))
這裡包含三個部份,第一個部份會把貓和狗指定題數 num_outputs
的圖片抓出,計算 hash
,並且紀錄每一題要用哪個 hash
。最後把 hash
寫進獨立的檔案,好讓未來可以知道每個 hash
對應到貓還是狗。
第二個部份則是根據指定的 web_root
來產生每個 hash
對應的網址,在產生問卷前要先將圖片上傳到這個位置,才能讓 script 抓取到對應的圖片。不過抓取完後,圖片就會存在 Google 裡,所以問卷本身不再需要原始的網址。
第三個部份則是產生實際的問卷檔案,別忘了隨機打亂選項的順序,好讓使用者看不出哪個選項是來自哪裡。
寫好後執行
python prepare.py train output --web-root http://WEB_ROOT
應該會產生下述檔案:
output/
├── cat.txt
├── dog.txt
├── images
│ ├── 00f1acf458ae561796d9abf10e384f31.jpg
│ ├── ......
├── survey.tsv
└── urls.tsv
首先先將 images
的所有檔案上傳到自己指定的 web_root
網頁空間。
然後產生一個 Google Sheets,將 survey.tsv
和 urls.tsv
分別匯入成為 survey
和 urls
兩個 tabs。範例可參考:〈Dogs vs. Cats Survey〉。
撰寫問卷產生的程式
接下來進入該 Google Sheets,點擊 Tools -> Script editor...
,編輯 Code.gs
。
新增一個函式抓取問卷資料:
function getSurveyData(sheetName) {
var arrayOfArrays = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName || 'survey').getDataRange().getValues();
var headers = arrayOfArrays.shift();
return arrayOfArrays;
}
再新增一個函式抓取網址資料:
function getUrlData(sheetName) {
var arrayOfArrays = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName || 'urls').getDataRange().getValues();
var headers = arrayOfArrays.shift();
var mapOfUrls = {};
for (var i=0; i<arrayOfArrays.length; i+=1) {
var h = arrayOfArrays[i][0];
var url = arrayOfArrays[i][1];
mapOfUrls[h] = url;
}
return mapOfUrls;
}
最後就是問卷產生了,為了避免產生太多 requests,造成連線逾時,也加了等待和重試的機制。
function makeOurForm() {
var title = 'Dogs vs. Cats Survey';
var desc = 'Please select the picture that looks like a cat.';
var mapOfUrls = getUrlData();
var surveyData = getSurveyData();
var form = FormApp.create(title)
form.setDescription(desc);
for (var i=0; i<surveyData.length; i++) {
Utilities.sleep(10);
var item = form.addMultipleChoiceItem();
item.setTitle('Q' + surveyData[i][0] + ': Which one looks like a cat?')
.setChoices([
item.createChoice('1'),
item.createChoice('2')
])
.setRequired(true);
for (var j=1; j<surveyData[i].length; j++) {
var name = '(' + j + ')';
var h = surveyData[i][j];
var img = UrlFetchApp.fetch(mapOfUrls[h]);
Utilities.sleep(100);
var imgItem = form.addImageItem();
try {
imgItem.setTitle(name).setImage(img);
} catch (e) {
Utilities.sleep(500);
imgItem.setTitle(name).setImage(img);
}
}
}
}
點擊 Run -> makeOurForm
熱騰騰的問卷就產生好了,可參考下圖。
程式碼
照慣例,程式碼放在下述地方供參考: