Skip to content

Commit 431405f

Browse files
authored
adding files
1 parent 9db27a1 commit 431405f

File tree

8 files changed

+707
-2
lines changed

8 files changed

+707
-2
lines changed

Google map scraper/images/GMS.png

29.9 KB
Loading

Google map scraper/images/Home.png

27.8 KB
Loading
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
"""
2+
This module contain the code for saving the scraped data
3+
"""
4+
5+
6+
import pandas as pd
7+
import os
8+
9+
10+
class DataSaver:
11+
def __init__(self, selectedpath, outputformat, messageshowfunc) -> None:
12+
self.selectedPath = selectedpath
13+
self.outputFormat = outputformat
14+
self.messageShowFunc = messageshowfunc
15+
16+
def save(self, datalist):
17+
"""
18+
This function will save the data that has been scrapped.
19+
This can be call if any error occurs while scraping , or if scraping is done successfully.
20+
In both cases we have to save the scraped data.
21+
"""
22+
23+
if len(datalist) > 0:
24+
self.messageShowFunc(custom=True, value="Saving the data")
25+
26+
dataFrame = pd.DataFrame(datalist)
27+
totalRecords = dataFrame.shape[0]
28+
29+
filename = "/gms output"
30+
31+
if self.outputFormat == "excel":
32+
extension = ".xlsx"
33+
elif self.outputFormat == "csv":
34+
extension = ".csv"
35+
elif self.outputFormat == "json":
36+
extension = ".json"
37+
38+
joinedPath = self.selectedPath + filename + extension
39+
40+
if os.path.exists(joinedPath):
41+
index = 1
42+
while True:
43+
filename = f"/gms output{index}"
44+
45+
joinedPath = self.selectedPath + filename + extension
46+
47+
if os.path.exists(joinedPath):
48+
index += 1
49+
50+
else:
51+
break
52+
53+
if self.outputFormat == "excel":
54+
dataFrame.to_excel(joinedPath, index=False)
55+
elif self.outputFormat == "csv":
56+
dataFrame.to_csv(joinedPath, index=False)
57+
58+
elif self.outputFormat == "json":
59+
dataFrame.to_json(joinedPath, indent=4, orient="records")
60+
61+
self.messageShowFunc(savingdata=True, totalrecords=totalRecords)
62+
else:
63+
self.messageShowFunc(
64+
custom=True, value="Oops! You did not scrape any record..."
65+
)
Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
"""
2+
This module contain the code for frontend
3+
"""
4+
5+
6+
import tkinter as tk
7+
from tkinter import ttk, filedialog, WORD
8+
from scraper import Backend
9+
import os
10+
import threading
11+
import json
12+
13+
14+
class Frontend(Backend):
15+
def __init__(self):
16+
self.settingsPath = self.pathmaker("settings/outputpath.json")
17+
18+
"""Initializing frontend layout"""
19+
20+
self.root = tk.Tk()
21+
icon = tk.PhotoImage(file=self.pathmaker("images/GMS.png"))
22+
23+
self.root.iconphoto(True, icon)
24+
self.root.geometry("850x650")
25+
self.root.resizable(False, False)
26+
self.root.title("Google maps scraper")
27+
28+
self.style = ttk.Style()
29+
self.style.map(
30+
"my.TButton", # making style for our buttons
31+
foreground=[("active", "green")],
32+
background=[("active", "white")],
33+
)
34+
35+
bgimage = tk.PhotoImage(file=self.pathmaker("images/Home.png"))
36+
37+
self.imglabel = tk.Label(self.root, image=bgimage)
38+
self.imglabel.place(x=0, y=0, relwidth=1, relheight=1)
39+
self.imglabel.image = bgimage
40+
41+
"""For search entry"""
42+
self.search_label = ttk.Label(
43+
self.root,
44+
text="Search:",
45+
font=("Franklin Gothic Medium", 17),
46+
foreground="green",
47+
background="white",
48+
)
49+
self.search_label.place(x=255, y=175)
50+
51+
self.search_box = ttk.Entry(self.root, width=30, font=("Arial", 15))
52+
self.search_box.place(x=355, y=180)
53+
54+
"""For submit button"""
55+
self.submit_button = ttk.Button(
56+
self.root,
57+
text="Submit",
58+
width=15,
59+
command=self.getinput,
60+
style="my.TButton",
61+
)
62+
self.submit_button.place(x=355, y=320)
63+
64+
"""for output format entry"""
65+
self.outputFormatButtonLabel = ttk.Label(
66+
self.root,
67+
text="Format:",
68+
font=("Franklin Gothic Medium", 17),
69+
foreground="green",
70+
background="white",
71+
)
72+
self.outputFormatButtonLabel.place(x=255, y=230)
73+
74+
self.outputFormatButton = ttk.Combobox(
75+
self.root, values=["Excel", "Json", "Csv"], state="readonly"
76+
)
77+
self.outputFormatButton.place(x=355, y=240)
78+
79+
"""for message box"""
80+
self.show_text = tk.Text(
81+
self.root,
82+
font=("arial", 13),
83+
height=10,
84+
width=35,
85+
state="disabled",
86+
border=False,
87+
wrap=WORD,
88+
highlightbackground="black",
89+
highlightthickness=2,
90+
)
91+
self.show_text.place(x=295, y=440)
92+
93+
"""For reset settings button"""
94+
self.resetSettingsButton = ttk.Button(
95+
self.root,
96+
text="Reset settings",
97+
width=15,
98+
command=self.resetsettings,
99+
style="my.TButton",
100+
)
101+
self.resetSettingsButton.place(x=20, y=590)
102+
103+
104+
self.__replacingtext(
105+
"Welcome to Google Maps Scraper!\n\nLet's start scraping..."
106+
)
107+
108+
def __replacingtext(self, text):
109+
"""This function will insert the text in text showing box"""
110+
111+
self.show_text.config(state="normal")
112+
# self.messageShowBox.delete(index1=1.0,index2=tkinter.END)
113+
self.show_text.insert(tk.END, "• " + text)
114+
self.show_text.insert(tk.END, "\n\n")
115+
self.show_text.see(tk.END)
116+
self.show_text.config(state="disabled")
117+
118+
def pathmaker(self, relativepath):
119+
"""Get absolute path to resurce, for deployment of this application
120+
using PyInstaller"""
121+
122+
try:
123+
# PyInstaller creates a temp folder and stores path in _MEIPASS
124+
base_path = sys._MEIPASS
125+
except Exception as p:
126+
base_path = os.path.abspath(".")
127+
128+
return os.path.join(base_path, relativepath)
129+
130+
def getinput(self):
131+
self.searchQuery = self.search_box.get()
132+
self.outputFormatValue = self.outputFormatButton.get()
133+
134+
if len(self.searchQuery) == 0 and len(self.outputFormatValue) == 0:
135+
self.__replacingtext(text="Oops! Your query is not valid")
136+
137+
elif len(self.searchQuery) == 0:
138+
self.__replacingtext(text="Oops! You did empty search")
139+
elif len(self.outputFormatValue) == 0:
140+
self.__replacingtext(text="Oops! You did not select output format")
141+
142+
else:
143+
self.askingfolderpath()
144+
145+
if len(self.outputfolderpath) == 0:
146+
self.__replacingtext(
147+
"You did not select any folder\nKindly submit again and select one folder where files will be stored"
148+
)
149+
else:
150+
self.submit_button.config(state="disabled")
151+
152+
self.searchQuery = self.searchQuery.lower()
153+
self.outputFormatValue = self.outputFormatValue.lower()
154+
155+
self.threadToStartBackend = threading.Thread(target=self.startscraping)
156+
self.threadToStartBackend.start()
157+
158+
def closingbrowser(self):
159+
"""It will close the browser when the app is closed"""
160+
161+
try:
162+
super().closeThread.set()
163+
self.root.destroy()
164+
except:
165+
pass
166+
167+
def startscraping(self):
168+
super().__init__(
169+
self.searchQuery,
170+
self.outputFormatValue,
171+
self.messageshowing,
172+
self.outputfolderpath,
173+
)
174+
175+
self.mainscraping()
176+
177+
def messageshowing(
178+
self,
179+
interruptionerror=False,
180+
savingdata=False,
181+
totalrecords=None,
182+
custom=False,
183+
value=None,
184+
noresultfound=False,
185+
):
186+
187+
if interruptionerror:
188+
self.__replacingtext("Interruption in browser is absorved")
189+
self.submit_button.config(state="normal")
190+
try:
191+
if self.threadToStartBackend.is_alive():
192+
self.threadToStartBackend.join()
193+
except:
194+
pass
195+
196+
elif savingdata:
197+
self.__replacingtext(
198+
f"Scraped data is saved\nTotal records saved: {totalrecords}"
199+
)
200+
self.submit_button.config(state="normal")
201+
try:
202+
if self.threadToStartBackend.is_alive():
203+
self.threadToStartBackend.join()
204+
except:
205+
pass
206+
207+
elif noresultfound:
208+
self.submit_button.config(state="normal")
209+
try:
210+
if self.threadToStartBackend.is_alive():
211+
self.threadToStartBackend.join()
212+
except:
213+
pass
214+
215+
self.__replacingtext("We are sorry but, No results found for your search query on googel maps....")
216+
217+
elif custom:
218+
self.__replacingtext(text=value)
219+
220+
def askingfolderpath(self):
221+
with open(self.settingsPath, "r") as f:
222+
self.outputfolderpath = json.load(f)["path"]
223+
224+
if len(self.outputfolderpath) == 0:
225+
self.__replacingtext(
226+
"Kindly select a folder where scraped data will be saved"
227+
)
228+
self.outputfolderpath = filedialog.askdirectory()
229+
230+
with open(self.settingsPath, "w") as f:
231+
json.dump({"path": self.outputfolderpath}, f)
232+
233+
elif os.path.exists(self.outputfolderpath):
234+
pass
235+
else:
236+
self.__replacingtext(
237+
"The folder you selected is no longer present.\nSo select new folder"
238+
)
239+
240+
self.outputfolderpath = filedialog.askdirectory()
241+
with open(self.settingsPath, "w") as f:
242+
json.dump({"path": self.outputfolderpath}, f)
243+
244+
self.__replacingtext("")
245+
246+
def resetsettings(self):
247+
with open(self.settingsPath, "w") as f:
248+
json.dump({"path": ""}, f)
249+
250+
251+
if __name__ == "__main__":
252+
app = Frontend()
253+
app.root.protocol("WM_DELETE_WINDOW", app.closingbrowser)
254+
app.root.mainloop()

0 commit comments

Comments
 (0)