-
Notifications
You must be signed in to change notification settings - Fork 51
/
Copy pathshopify-sites.py
319 lines (254 loc) · 9.75 KB
/
shopify-sites.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
'''
NERYS
a universal product monitor
Current Module: Shopify Sites
Usage:
NERYS will monitor specified sites for keywords and sends a Discord alert
when a page has a specified keyword. This can be used to monitor any site
on a product release date to automatically detect when a product has been
uploaded. Useful when monitoring hundreds of sites for shops in different
timezones.
Complete:
- find all products on Shopify site by keyword
- send discord notifications
- monitor for new products
- optimization for Shopify to return product checkout links by size
- find all products on other sites by keyword
- attempt to get product page links for universal sites
Left To Do:
- monitor for Shopify restocks
- monitor for restocks on other sites
-- find sold out by keyword
-- find sizes by keyword
-- find countdown timer by keyword
- detect cloudflare
- get product picture for other sites
- optimization for footsites
Credits:
Niveen Jegatheeswaran - Main Dev - https://github.com/snivyn/
kyb3r - Discord Embed - https://github.com/kyb3r/
'''
import requests
from log import log as log
import time
from threading import Thread
from datetime import datetime
import random
import json
import sqlite3
from bs4 import BeautifulSoup as soup
from discord_hooks import Webhook
from multiprocessing import Process
class FileNotFound(Exception):
''' Raised when a file required for the program to operate is missing. '''
class NoDataLoaded(Exception):
''' Raised when the file is empty. '''
class OutOfProxies(Exception):
''' Raised when there are no proxies left '''
def read_from_txt(path):
'''
(None) -> list of str
Loads up all sites from the sitelist.txt file in the root directory.
Returns the sites as a list
'''
# Initialize variables
raw_lines = []
lines = []
# Load data from the txt file
try:
f = open(path, "r")
raw_lines = f.readlines()
f.close()
# Raise an error if the file couldn't be found
except:
log('e', "Couldn't locate <" + path + ">.")
raise FileNotFound()
if(len(raw_lines) == 0):
raise NoDataLoaded()
# Parse the data
for line in raw_lines:
lines.append(line.strip("\n"))
# Return the data
return lines
def send_embed(alert_type, link, fields, site, image, product):
'''
(str, str, list, str, str, str) -> None
Sends a discord alert based on info provided.
'''
url = webhook
embed = Webhook(url, color=123123)
if(alert_type == "NEW_SHOPIFY"):
desc = "NEW: " + product
elif(alert_type == "RESTOCK_SHOPIFY"):
desc = "RESTOCK: " + product
embed.set_author(name='NERYS', icon='https://static.zerochan.net/Daenerys.Targaryen.full.2190849.jpg')
embed.set_desc(desc)
for field in fields:
if(alert_type == "NEW_SHOPIFY" or alert_type == "RESTOCK_SHOPIFY"):
cart_link = site + "/cart/" + str(field[1]) + ":1"
embed.add_field(name=str(field[0]), value=cart_link)
if(image is not None):
embed.set_thumbnail(image)
embed.set_image(image)
embed.set_footer(text='NERYS by @snivynGOD', icon='https://static.zerochan.net/Daenerys.Targaryen.full.2190849.jpg', ts=True)
embed.post()
def get_proxy(proxy_list):
'''
(list) -> dict
Given a proxy list <proxy_list>, a proxy is selected and returned.
'''
# Choose a random proxy
proxy = random.choice(proxy_list)
# Set up the proxy to be used
proxies = {
"http": str(proxy),
"https": str(proxy)
}
# Return the proxy
return proxies
def update_shopify_db(keywords, site, proxy_list):
while(True):
log('i', "Monitoring site <" + site + ">.")
# Create link to monitor (Kith is a special case)
if("kith.com" in site):
link = "https://kith.com/collections/footwear.atom"
else:
link = site + "/collections/all/products.atom"
working = False
# Get a proxy
proxies = get_proxy(proxy_list)
# Get the products on the site
try:
r = requests.get(link, proxies=proxies, timeout=3, verify=False)
except:
try:
proxies = get_proxy(proxy_list)
r = requests.get(link, proxies=proxies, timeout=5, verify=False)
except:
log('e', "Connection to URL <" + link + "> failed.")
continue
xml = soup(r.text, "xml")
products_raw = xml.findAll('entry')
# Get products with the specified keywords
for product in products_raw:
product_found = False
for keyword in keywords:
if(not product_found):
# Get the product info
title = product.find("title").text
link = product.find("link")["href"]
tags_raw = product.findAll("s:tag")
tags = []
for tag in tags_raw:
tags.append(tag.text.upper())
# Check if the keywords are in the product's name or tags
if(keyword.upper() in title.upper() or keyword.upper() in tags):
# Get the variants from the product
try:
r = requests.get(link + ".xml", proxies=proxies, timeout=3, verify=False)
working = True
except:
# Get a new proxy
proxies = get_proxy(proxy_list)
# Try again with a new proxy
try:
r = requests.get(link + ".xml", proxies=proxies, timeout=5, verify=False)
working = True
except:
working = False
# If the site/proxy is working
if(working):
# Break down the product page
xml = soup(r.text, "xml")
# Get the variants for the product
variants = []
raw_variants = xml.findAll("variant")
for raw_variant in raw_variants:
variants.append((raw_variant.find("title").text, raw_variant.find("id").text))
# Get the product's image if it's available
try:
image = xml.find("image").find("src").text
except:
image = None
# Store the product in the database
product_info = (title, link, variants, image, title, site)
alert = add_to_shopify_db(product_info)
product_found = True
# Send a Discord alert if the product is new
if(alert):
send_embed("NEW_SHOPIFY", link, variants, site, image, title)
# Wait the specified timeframe before checking the site again
time.sleep(delay)
def add_to_shopify_db(product):
# Initialize variables
title = product[0]
link = product[1]
stock = str(product[2])
alert = False
# Create database
conn = sqlite3.connect('products.db')
c = conn.cursor()
c.execute("""CREATE TABLE IF NOT EXISTS products_shopify(link TEXT UNIQUE, product TEXT, stock TEXT)""")
# Add product to database if it's unique
try:
c.execute("""INSERT INTO products_shopify (link, product, stock) VALUES (?, ?, ?)""", (link, title, stock))
log('s', "Found new product <" + title + ">.")
alert = True
except:
log('i', "Product <" + title + "> already exists in the database.")
# Close database
conn.commit()
c.close()
conn.close()
# Return whether or not it's a new product
return alert
''' --------------------------------- RUN --------------------------------- '''
if(__name__ == "__main__"):
# Ignore insecure messages
requests.packages.urllib3.disable_warnings()
# Initialize settings
keywords = [
"bred toe",
"gold toe",
"pharrell",
"holi",
"free throw line",
"kendrick",
"tinker",
"game royal",
"yeezy",
"human race",
"big bang",
"dont trip",
"don't trip",
"kung fu kenny",
"playstation",
"ovo air jordan",
"ovo jordan",
"wotherspoon",
"nike x off-white",
"off-white x nike",
"air jordan 1",
"wave runner",
"katrina",
"animal pack",
"acronym",
"vf sw",
"the ten",
"the 10"
]
webhook = "" # Put your webhook link here
delay = 5 # Lots of sites + few proxies = longer delay to avoid bans
# Load proxies
proxies = read_from_txt("proxies.txt")
log('i', str(len(proxies)) + " proxies loaded.")
# Store sites from txt files
shopify_sites = read_from_txt("shopify-sites.txt")
total_sites = len(shopify_sites)
log('i', str(total_sites) + " sites loaded.")
# Loop through each Shopify site
for site in shopify_sites:
# Monitor for new products
t = Thread(target=update_shopify_db, args=(keywords, site, proxies))
t.start()
time.sleep(1)