Mercurial > hg > horiscopes
comparison V5/synastry.py @ 23:11d4e438045e
make version 5
author | DaveM |
---|---|
date | Mon, 09 Apr 2018 15:07:21 +0100 |
parents | |
children | d2bd074d9284 |
comparison
equal
deleted
inserted
replaced
22:a5b8e2b91d8f | 23:11d4e438045e |
---|---|
1 import random | |
2 import csv | |
3 import re | |
4 import requests | |
5 import time | |
6 from bs4 import BeautifulSoup | |
7 | |
8 import pdb | |
9 | |
10 class compatibility: | |
11 def __init__(self): | |
12 self.rules = [] | |
13 self.uniqueID = 0 | |
14 print 'Warning, need to fix [Vertex, Ascendant House, South Node, IC/MC and None Location] issues' | |
15 | |
16 def addRule(self,planetTuple,aspectList,score): | |
17 rule = compatibilityRule(self.uniqueID,planetTuple,aspectList,score) | |
18 self.rules.append(rule) | |
19 self.uniqueID += 1 | |
20 | |
21 def findRule(self,planet): | |
22 ruleList = [r for r in self.rules if r.planet == planet] | |
23 print ruleList | |
24 return ruleList | |
25 | |
26 def readFile(self,filename): | |
27 text = [] | |
28 with open(filename) as fp: | |
29 line = fp.readline() | |
30 text.append(line.strip()) | |
31 while line: | |
32 line = fp.readline() | |
33 text.append(line.strip()) | |
34 return text | |
35 | |
36 def parseCompatRules(self,filename): | |
37 comList = self.readFile(filename) | |
38 for com in comList: | |
39 # print com | |
40 planetTuple = None | |
41 aspectList = None | |
42 score = None | |
43 c = com.split(',') | |
44 if len(c) == 4: | |
45 if len(c[1]) > 1: | |
46 aspectList = [] | |
47 planetTuple = tuple((c[0].lower(),c[2].lower())) | |
48 score = int(c[3]) | |
49 for subset in c[1].lower().split(' '): | |
50 aspectList.append(subset) | |
51 elif len(c[1]) == 0 : | |
52 if 'house' not in c[2]: | |
53 print 'some error where rule is not house' | |
54 planetTuple = (c[0].lower(),'house') | |
55 houseNo = re.findall('\d+', c[2]) | |
56 if len(houseNo) != 1: | |
57 print 'multiple house numbers found - ERROR' | |
58 aspectList = int(houseNo[0]) | |
59 score = int(c[3]) | |
60 self.addRule(planetTuple,aspectList,score) | |
61 | |
62 def calcCompatibility(self, horiscope): | |
63 score = 0 | |
64 for r in sorted(self.rules): | |
65 if 'vertex' in r.planet: | |
66 # print 'ERROR - catch Vertex issue' | |
67 pass | |
68 elif 'southnode' in r.planet: | |
69 # print 'ERROR - catch South Node issue' | |
70 pass | |
71 elif 'ic/mc' in r.planet: | |
72 # print 'ERROR - catch IC/MC issue' | |
73 pass | |
74 elif r.planet[1] == 'house' and r.planet[0] == 'asc': | |
75 # print 'ERROR - catch Ascendant House issue' | |
76 pass | |
77 elif horiscope.planets[r.planet[0]].angleA is None: | |
78 # print 'Error - None Location' | |
79 return None | |
80 elif r.planet[1] == 'house': | |
81 if horiscope.isInHouse(r.planet[0],r.aspect): | |
82 score += r.score | |
83 print r.planet[0] +' '+ r.planet[1] +' '+ str(aspect)+' '+str(r.score) | |
84 elif r.planet[0] == r.planet[1]: | |
85 aspect,variance = horiscope.calcAspect(r.planet[0],r.planet[1]) | |
86 if aspect is not None: | |
87 if aspect in r.aspect: | |
88 score += r.score | |
89 print r.planet[0]+' '+aspect +' '+ r.planet[1] +' '+ str(r.score) | |
90 else: | |
91 for order in [0,1]: | |
92 aspect,variance = horiscope.calcAspect(r.planet[order],r.planet[not order]) | |
93 if aspect is not None: | |
94 # print aspect | |
95 # currentR = r | |
96 # pdb.set_trace() | |
97 if aspect in r.aspect: | |
98 score += r.score | |
99 print r.planet[0] +' '+ aspect +' '+ r.planet[1] +' '+ str(r.score) | |
100 else: | |
101 print r.planet[0] +' '+ aspect +' '+ r.planet[1] +' 0' | |
102 print score | |
103 return score | |
104 | |
105 | |
106 | |
107 | |
108 class compatibilityRule: | |
109 def __init__(self,uniqueId,planetTuple,aspectList,score): | |
110 self.id = uniqueId | |
111 self.planet = planetTuple | |
112 self.aspect = aspectList | |
113 self.score = score | |
114 | |
115 | |
116 class Person: | |
117 url = 'https://horoscopes.astro-seek.com/calculate-love-compatibility/' | |
118 def __init__(self,personDict): | |
119 # self. = planetPositions() | |
120 self.id = personDict['ID'] | |
121 self.dob = personDict['DOB'] | |
122 self.tob = personDict['TOB'] | |
123 self.cob = personDict['COB'] | |
124 self.p_dob = personDict['pDOB'] | |
125 self.p_tob = personDict['pTOB'] | |
126 self.p_cob = personDict['pCOB'] | |
127 self.horiscope = None | |
128 self.resp = None | |
129 self.issue = 'INCOMPLETE' | |
130 | |
131 def identifyIssues(self): | |
132 if self.id is None: | |
133 self.issue = 'id' | |
134 elif self.dob is None: | |
135 self.issue = 'dob' | |
136 elif self.tob is None: | |
137 self.issue = 'tob' | |
138 elif self.cob is None: | |
139 self.issue = 'cob' | |
140 elif self.p_dob is None: | |
141 self.issue = 'p_dob' | |
142 elif self.p_tob is None: | |
143 self.issue = 'p_tob' | |
144 elif self.p_cob is None: | |
145 self.issue = 'p_cob' | |
146 else: | |
147 self.issue = None | |
148 return self.issue | |
149 | |
150 def makePayload(self): | |
151 if type(self.cob) is str: | |
152 cob_0 = float(self.cob.split(',')[0][1:]) | |
153 cob_1 = float(self.cob.split(',')[1]) | |
154 self.cob = (cob_0,cob_1) | |
155 if type(self.p_cob) is str: | |
156 pcob_0 = float(self.p_cob.split(',')[0][1:]) | |
157 pcob_1 = float(self.p_cob.split(',')[1]) | |
158 self.p_cob = (pcob_0,pcob_1) | |
159 if type(self.dob) is str: | |
160 self.dob = self.dob[1:-1].split(',') | |
161 if type(self.p_dob) is str: | |
162 self.p_dob = self.p_dob[1:-1].split(',') | |
163 if type(self.tob) is str: | |
164 self.tob = self.tob[1:-1].split(',') | |
165 if type(self.p_tob) is str: | |
166 self.p_tob = self.p_tob[1:-1].split(',') | |
167 | |
168 self.payload = {'send_calculation':'1', #Req | |
169 'muz_narozeni_den':self.dob[0], | |
170 'muz_narozeni_mesic':self.dob[1], | |
171 'muz_narozeni_rok':self.dob[2], | |
172 'muz_narozeni_hodina':self.tob[0], | |
173 'muz_narozeni_minuta':self.tob[1], | |
174 'muz_narozeni_city':'', | |
175 'muz_narozeni_mesto_hidden':'Manually+place%3A+%C2%B0%27N%2C+%C2%B0%27E',#auto | |
176 'muz_narozeni_stat_hidden':'XX', | |
177 'muz_narozeni_podstat_kratky_hidden':'', | |
178 'muz_narozeni_podstat_hidden':'', | |
179 'muz_narozeni_podstat2_kratky_hidden':'', | |
180 'muz_narozeni_podstat3_kratky_hidden':'', | |
181 'muz_narozeni_input_hidden':'', | |
182 'muz_narozeni_sirka_stupne':str(abs(self.cob[0])).split('.')[0], | |
183 'muz_narozeni_sirka_minuty':str(float('0.'+str(self.cob[0]).split('.')[1])*60).split('.')[0], | |
184 'muz_narozeni_sirka_smer': '1' if self.cob[0]<0 else '0', #address N Dir (0':'N',1':'S) | |
185 'muz_narozeni_delka_stupne':str(abs(self.cob[1])).split('.')[0], #address E - Main | |
186 'muz_narozeni_delka_minuty':str(float('0.'+str(self.cob[1]).split('.')[1])*60).split('.')[0], | |
187 'muz_narozeni_delka_smer': '1' if self.cob[1]<0 else '0', #address E Dir (0':'E',1':'W) | |
188 'muz_narozeni_timezone_form':'auto', | |
189 'muz_narozeni_timezone_dst_form':'auto', | |
190 'send_calculation':'1', | |
191 'zena_narozeni_den':self.p_dob[0], | |
192 'zena_narozeni_mesic':self.p_dob[1], | |
193 'zena_narozeni_rok':self.p_dob[2], | |
194 'zena_narozeni_hodina':self.p_tob[0], | |
195 'zena_narozeni_minuta':self.p_tob[1], | |
196 'zena_narozeni_city':'', | |
197 'zena_narozeni_mesto_hidden':'Manually+place%3A+%C2%B0%27N%2C+%C2%B0%27E', | |
198 'zena_narozeni_stat_hidden':'XX', | |
199 'zena_narozeni_podstat_kratky_hidden':'', | |
200 'zena_narozeni_podstat_hidden':'', | |
201 'zena_narozeni_podstat2_kratky_hidden':'', | |
202 'zena_narozeni_podstat3_kratky_hidden':'', | |
203 'zena_narozeni_input_hidden':'', | |
204 'zena_narozeni_sirka_stupne':str(abs(self.p_cob[0])).split('.')[0], | |
205 'zena_narozeni_sirka_minuty':str(float('0.'+str(self.p_cob[0]).split('.')[1])*60).split('.')[0], | |
206 'zena_narozeni_sirka_smer': '1' if self.p_cob[0]<0 else '0', | |
207 'zena_narozeni_delka_stupne':str(abs(self.p_cob[1])).split('.')[0], | |
208 'zena_narozeni_delka_minuty':str(float('0.'+str(self.p_cob[1]).split('.')[1])*60).split('.')[0], | |
209 'zena_narozeni_delka_smer': '1' if self.p_cob[1]<0 else '0', | |
210 'zena_narozeni_timezone_form':'auto', | |
211 'zena_narozeni_timezone_dst_form':'auto', | |
212 'switch_interpretations':'0', | |
213 'house_system':'placidus', | |
214 'uhel_orbis':'#tabs_redraw'} | |
215 | |
216 def requestURL(self): | |
217 self.resp = requests.get(self.url, params=self.payload) | |
218 time.sleep(5) | |
219 return self.resp | |
220 | |
221 def parsePage(self): | |
222 self.horiscope = None | |
223 if('Please use valid date.' in self.resp.content): | |
224 self.issue = 'dob' | |
225 return self.horiscope | |
226 elif('Please use valid time.' in self.resp.content): | |
227 self.issue = 'tob' | |
228 return self.horiscope | |
229 gotLocation = 0 | |
230 self.horiscope = planetPositions() | |
231 soup = BeautifulSoup(self.resp.content, 'lxml') | |
232 tcCell = soup.find_all('div', attrs={'class':'right-sedy-banner-svetlejsi'}) | |
233 for cell in tcCell: | |
234 if "Planets in partner's house" in cell.get_text(): | |
235 gotLocation = 1 | |
236 divList = cell.find_all('div') | |
237 for i in range(len(divList)): | |
238 planetName = divList[i].getText().lower().strip().replace(':','').split(' ')[0] | |
239 if planetName in planetPositions.planetNames: | |
240 if gotLocation and not '/' in planetName: | |
241 self.horiscope.planets[planetName].setHouse(divList[i+2].getText(),divList[i+4].getText()) | |
242 else: | |
243 self.horiscope.planets[planetName].setLocation(divList[i+2].getText(),divList[i+1].img.attrs['alt'],0) | |
244 self.horiscope.planets[planetName].setLocation(divList[i+4].getText(),divList[i+3].img.attrs['alt'],1) | |
245 return self.horiscope | |
246 | |
247 | |
248 | |
249 class planetRelation: | |
250 noHouseList = ['asc','ic','dsc','mc','asc/mc','sun/moon'] | |
251 zodiacAngle = {'aries':0,'taurus':30,'gemini':60,'cancer':90,'leo':120,'virgo':150,'libra':180,'scorpio':210,'sagittarius':240,'capricorn':270,'aquarius':300,'pisces':330} | |
252 | |
253 def __init__(self,planetName): | |
254 self.name = planetName | |
255 self.angleA = None | |
256 self.angleB = None | |
257 if planetName not in planetRelation.noHouseList: | |
258 self.houseA = None | |
259 self.houseB = None | |
260 | |
261 def setLocation(self,value,sign,isB): | |
262 signVal = planetRelation.zodiacAngle[sign.lower()] | |
263 signVal+= float('.'.join(value.encode('ascii','replace').split('?'))[:-1]) | |
264 # print self.name,sign.lower(),planetRelation.zodiacAngle[sign.lower()],value,signVal | |
265 if not isB: | |
266 self.angleA = signVal | |
267 else: | |
268 self.angleB = signVal | |
269 | |
270 def setHouse(self,A,B): | |
271 self.houseA = int(A.encode('ascii','ignore')) | |
272 self.houseB = int(B.encode('ascii','ignore')) | |
273 | |
274 def test_random(self): | |
275 self.angleA = random.random()*360 | |
276 self.angleB = random.random()*360 | |
277 | |
278 | |
279 class planetPositions: | |
280 aspectDict = {'conjunction':0,'semi-square':45,'sextile':60,'square':90,'trine':120,'opposition':180} | |
281 # zodiacAngle = {'aries':0,'taurus':30,'gemini':60,'cancer':90,'leo':120,'virgo':150,'libra':180,'scorpio':210,'sagittarius':240,'capricorn':270,'aquarius':300,'pisces':330} | |
282 # Taken from https://en.wikipedia.org/wiki/Astrological_sign, with reference from https://en.wikipedia.org/wiki/Astrological_symbols#Signs_of_the_zodiac | |
283 planetNames = ['sun','moon','mercury','venus','mars','jupiter','saturn','uranus','neptune','pluto','node','lilith','chiron','asc','ic','dsc','mc','asc/mc','sun/moon'] | |
284 def __init__(self): | |
285 self.planets = {} | |
286 for p in planetPositions.planetNames: | |
287 self.planets[p] = planetRelation(p) | |
288 self.aspect = {} | |
289 | |
290 def test_random(self): | |
291 for planet in self.planets: | |
292 self.planets[planet].test_random() | |
293 | |
294 def calcAngle(self,componentA,componentB): | |
295 print componentA,componentB | |
296 self.angle = abs(self.planets[componentA].angleA - self.planets[componentB].angleB) | |
297 self.angleRange = self.angle-10,self.angle+10 | |
298 | |
299 def calcAspect(self,componentA,componentB): | |
300 self.calcAngle(componentA,componentB) | |
301 # print componentA,componentB,self.angle,self.planets[componentA].angleA,self.planets[componentB].angleB | |
302 for aspect in planetPositions.aspectDict: | |
303 if self.angleRange[0] < planetPositions.aspectDict[aspect] and self.angleRange[1] > planetPositions.aspectDict[aspect]: | |
304 # print aspect#,componentA,componentB,self.angle | |
305 aspectDiff = round(abs(self.angle - planetPositions.aspectDict[aspect]),2) | |
306 self.aspect[componentA,componentB] = (aspect,aspectDiff) | |
307 print componentA,componentB,self.angle,aspect,aspectDiff | |
308 return aspect,aspectDiff | |
309 return None,None | |
310 | |
311 def isInHouse(self,component,houseNo): | |
312 # print (self.planets[component].houseA,self.planets[component].houseB,houseNo) | |
313 if (self.planets[component].houseA == houseNo) or (self.planets[component].houseB == houseNo): | |
314 return True | |
315 return False | |
316 | |
317 def makeAllAspectTreple(self): | |
318 self.aspectTreple = {} | |
319 for p1 in planetPositions.planetNames: | |
320 for p2 in planetPositions.planetNames: | |
321 aspect = self.calcAspect(p1,p2)[0] | |
322 if aspect is not None: | |
323 self.aspectTreple[(p1,p2,aspect)] = 1 | |
324 | |
325 def calcAllAspects(self): | |
326 for p1 in planetPositions.planetNames: | |
327 for p2 in planetPositions.planetNames: | |
328 self.calcAspect(p1,p2) | |
329 | |
330 def printPositions(self): | |
331 for p in planetPositions.planetNames: | |
332 if p in planetRelation.noHouseList: | |
333 print p,self.planets[p].angleA,self.planets[p].angleB | |
334 else: | |
335 print p,self.planets[p].angleA,self.planets[p].angleB,self.planets[p].houseA,self.planets[p].houseB | |
336 | |
337 | |
338 | |
339 | |
340 |