├── README.md └── searches.py /README.md: -------------------------------------------------------------------------------- 1 | # Searches book 2 | 3 | Searches is a book made with Google search entries. It’s like a diary you didn’t know you were writing. 4 | More info at [ishback.com/searches](ishback.com/searches) 5 | 6 | ## Create your own Searches book: 7 | 8 | ### Download your search history 9 | 10 | 1. Go to [https://history.google.com](https://history.google.com). You’ll need to enter your Google email and password if you’re not logged in yet. 11 | 2. In the ‘Web & App Activity’ section, click on the icon with the three dots on the top right corner, and 12 | click ‘Download searches’. 13 | 3. Choose ‘Create archive’. You will receive an email from Google when the archive is ready to download. 14 | 4. Unzip the archive. You should get a folder ‘Searches’ that contains index.html and another folder ‘Searches’ 15 | 16 | ### Download DrawBot 17 | 18 | The book is generated with DrawBot, a free application for Mac. 19 | 20 | 5. To download DrawBot, go to [http://www.drawbot.com/content/download.html](http://www.drawbot.com/content/download.html). 21 | 22 | ### Download the searches.py script 23 | 24 | searches.py is a python script that takes your searches and creates a book. 25 | 26 | 6. Download searches.py from here: 27 | 7. Place searches.py in the same directory than the folder you unzipped, ‘Searches’ (where the index.html is). 28 | 29 | ### Create the book 30 | 31 | 8. Open searches.py with Drawbot. Press ⌘+R to run the script. The book will appear on the left side. 32 | 9. To save the book in PDF, go to File > Export as PDF. You can also print the book directly from DrawBot. 33 | 34 | By default, the script will create a book of your 2015 searches. If you wish to create a book for past years, change the year in line 6. 35 | 36 | -------------------------------------------------------------------------------- /searches.py: -------------------------------------------------------------------------------- 1 | import json 2 | import datetime 3 | import os 4 | 5 | #which year do you want to create a book for? 6 | year = "2015" 7 | 8 | gutter = 10 #margin for cutting guides 9 | cut = 5 #length of the cutting guides 10 | size(450 + gutter*2, 660 + gutter*2) 11 | 12 | searches = [] 13 | dates = [] 14 | hours = [] 15 | searches_month = [] 16 | 17 | searches_txt = '' 18 | dates_txt = '' 19 | hours_txt = '' 20 | txt = FormattedString() 21 | txt += '' 22 | 23 | hyphenation(False) 24 | 25 | offset = 14 26 | w = 280 #textbox width 27 | h = 520 #textbox height 28 | y = 70 29 | #for left pages 30 | x1 = width()/2 - w/2 - offset 31 | #for right pages 32 | x2 = width()/2 - w/2 + offset 33 | 34 | stroke(0.8) 35 | 36 | #print installedFonts() 37 | #dates_font = "RobotoMono-BoldItalic" 38 | dates_font = "Menlo-BoldItalic" 39 | hours_font = "RobotoMono-Thin" 40 | #searches_font = "Menlo" 41 | searches_font = "Menlo" # Menlo # "LucidaGrande" 42 | pagenum_font = "Menlo" 43 | title_font = "Menlo-Italic" 44 | titlePage_font = "Menlo-Italic" 45 | summary_font = "Menlo" 46 | 47 | margin_title_w = 100 48 | margin_title_h = 50 49 | 50 | #dates_size = 9 51 | dates_size = 8 52 | hours_size = 4.3 53 | #searches_size = 7 54 | searches_size = 7 # 7 # 7.5 55 | pagenum_size = 6 56 | titlePage_size = 6 57 | title_size = 9 58 | summary_size = 7 59 | lh = 12 60 | hours_baseline = 0 61 | 62 | lastDate = "0000000000" 63 | validSearches = 0 64 | 65 | path = "Searches" 66 | json_files = [pos_json for pos_json in os.listdir(path) if pos_json.endswith('.json') if pos_json.startswith(year)] 67 | 68 | print "year:", year 69 | 70 | for i in range(12): 71 | searches_month.append(0) 72 | 73 | first = 1 74 | for js in json_files: 75 | with open(os.path.join(path, js)) as data_file: 76 | print js 77 | data = json.load(data_file) 78 | num_searches = len(data["event"]) 79 | 80 | for i in reversed(range(num_searches)): 81 | time = data["event"][i]["query"]["id"][0]["timestamp_usec"] 82 | 83 | search = data["event"][i]["query"]["query_text"] 84 | #we clean up searches for directions 85 | if "->" in search or "," in search: 86 | pass 87 | 88 | else: 89 | date = datetime.datetime.utcfromtimestamp(int(time)/1000000).strftime('%A, %d %b') 90 | #date = datetime.datetime.utcfromtimestamp(int(time)/1000000).strftime('%A, %B %-d') 91 | hour = datetime.datetime.utcfromtimestamp(int(time)/1000000).strftime('%H:%M') 92 | #print date 93 | validSearches += 1 94 | searches.append(search) 95 | dates.append(date) 96 | hours.append(hour) 97 | 98 | if date[:7] == lastDate[:7]: # same day 99 | txt.append(search + '', font=searches_font, fontSize=searches_size, lineHeight=lh) 100 | txt.append(' ' + hour + ' ', font=hours_font, fontSize=hours_size, lineHeight=lh, baselineShift=hours_baseline) 101 | txt.baselineShift(0) 102 | 103 | else: 104 | txt.lineHeight(lh+1) # different day 105 | if first: 106 | txt.append(date, font=dates_font, fontSize=dates_size) 107 | first = 0 108 | else: 109 | txt.append('\n' + '\n' + '\n' + date, font=dates_font, fontSize=dates_size) #.upper() 110 | txt.append('\n' + '\n', font=searches_font, fontSize=searches_size, lineHeight=lh-5) 111 | txt.append(search + '', font=searches_font, fontSize=searches_size, lineHeight=lh) 112 | txt.append(' ' + hour + ' ', font=hours_font, fontSize=hours_size, lineHeight=lh, baselineShift=hours_baseline) 113 | txt.baselineShift(0) 114 | 115 | month_num = int(datetime.datetime.fromtimestamp(int(time)/1000000).strftime('%m')) - 1 116 | searches_month[month_num] += 1 117 | 118 | lastDate = date 119 | 120 | # function to print the cutting guides on each page 121 | def printGuides(): 122 | stroke(0) 123 | strokeWidth(0.2) 124 | 125 | fill(None) 126 | line((gutter, 0), (gutter, cut)) 127 | line((0, gutter), (cut, gutter)) 128 | line((width()-gutter, 0), (width()-gutter, cut)) 129 | line((width(), gutter), (width()-cut, gutter)) 130 | line((0, height()-gutter), (cut, height()-gutter)) 131 | line((gutter, height()), (gutter, height()-cut)) 132 | line((width()-gutter, height()), (width()-gutter, height()-cut)) 133 | line((width(), height()-gutter), (width()-cut, height()-gutter)) 134 | 135 | # print the title on the first page 136 | font(title_font) 137 | fontSize(title_size) 138 | fill(0) 139 | stroke(None) 140 | textBox("Searches " + year, (width()/2+80, height()/2, 200, 10)) 141 | printGuides() 142 | 143 | #blank page 144 | newPage(width(), height()) 145 | printGuides() 146 | 147 | overflow_txt = txt 148 | p = 1 149 | 150 | while overflow_txt: 151 | newPage(width(), height()) 152 | 153 | #If the first char of the new page is a new line we remove the new line 154 | while str(overflow_txt[:1]) == "\n": 155 | overflow_txt = overflow_txt[1:] 156 | 157 | if p == 1: 158 | overflow_txt = textBox(overflow_txt,(x2, y, w, h-200), align="left") 159 | #txt = overflow_txt 160 | font(pagenum_font) 161 | fontSize(pagenum_size) 162 | fill(0) 163 | text(str(p+1), (x2 + w/2, 35)) 164 | 165 | 166 | elif p % 2 == 0: 167 | overflow_txt = textBox(overflow_txt,(x1, y, w, h), align="left") 168 | font(pagenum_font) 169 | fontSize(pagenum_size) 170 | fill(0) 171 | text(str(p+1), (x1 + w/2, 45)) 172 | font(titlePage_font) 173 | fontSize(titlePage_size) 174 | fill(0) 175 | textBox("SEARCHES", (width() - margin_title_w, height() - margin_title_h, 40, 10), align="right") 176 | 177 | 178 | else: 179 | overflow_txt = textBox(overflow_txt,(x2, y, w, h), align="left") 180 | font(pagenum_font) 181 | fontSize(pagenum_size) 182 | fill(0) 183 | text(str(p+1), (x2 + w/2, 45)) 184 | font(titlePage_font) 185 | fontSize(titlePage_size) 186 | fill(0) 187 | textBox(year, (margin_title_w - 40, height() - margin_title_h, 40, 10), align="left") 188 | 189 | printGuides() 190 | p += 1 191 | 192 | # a blank page before the summary 193 | newPage(width(), height()) 194 | p += 1 195 | printGuides() 196 | newPage(width(), height()) 197 | if p%2==0: 198 | shift = -offset 199 | else: shift = offset 200 | 201 | summary_x = 140 202 | summary_y = 400 203 | 204 | font(summary_font) 205 | fontSize(summary_size) 206 | fill(0) 207 | 208 | textBox("Year:", (summary_x+shift, summary_y+15, 200, 10)) 209 | textBox(year, (summary_x+100+shift, summary_y+15, 250, 10)) 210 | 211 | textBox("Total searches:", (summary_x+shift, summary_y, 200, 10)) 212 | textBox(str(validSearches), (summary_x+100+shift, summary_y, 250, 10)) 213 | 214 | textBox("Average per month:", (summary_x+shift, summary_y-15, 200, 10)) 215 | textBox(str(round(validSearches/12,1)), (summary_x+100+shift, summary_y-15, 250, 10)) 216 | 217 | textBox("Average per day:", (summary_x+shift, summary_y-30, 200, 10)) 218 | textBox(str(round(validSearches/365,1)), (summary_x+100+shift, summary_y-30, 250, 10)) 219 | 220 | textBox("Searches each month:", (summary_x+shift, summary_y-45, 200, 10)) 221 | for i in range(0, 12): 222 | month = datetime.date(1900, i+1, 1).strftime('%b') 223 | textBox(month + ": " + str(searches_month[i]), (summary_x+100+shift, summary_y-45-15*i, 250, 10)) 224 | rect(summary_x+150+shift, summary_y-40-15*i, searches_month[i]/validSearches*300, 3) 225 | 226 | stroke(0) 227 | strokeWidth(0.2) 228 | line(100 + shift,100,width()-100 + shift,100) 229 | stroke(None) 230 | fontSize(summary_size) 231 | lineHeight(10) 232 | textBox("This book has been generated with DrawBot, drawbot.com\n A project by Ishac Bertran, ishback.com", (100 + shift, 50, width()-200, 40), align="center") 233 | printGuides() 234 | 235 | print 'pageCount', pageCount() 236 | print searches_month 237 | print 'validSearches', validSearches 238 | 239 | 240 | 241 | 242 | --------------------------------------------------------------------------------