Subversion Repositories SmartDukaan

Rev

Rev 16099 | Rev 16102 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
15869 kshitij.so 1
import urllib2
2
from BeautifulSoup import BeautifulSoup
3
import pymongo
4
import re
16019 kshitij.so 5
from dtr.utils.utils import to_java_date, getNlcPoints
15869 kshitij.so 6
import optparse
7
from datetime import datetime
8
import smtplib
9
from email.mime.text import MIMEText
10
from email.mime.multipart import MIMEMultipart
15895 kshitij.so 11
from dtr.utils import ShopCluesScraper
12
import traceback
16019 kshitij.so 13
from dtr.storage.MemCache import MemCache
15869 kshitij.so 14
 
15
con = None
16
parser = optparse.OptionParser()
17
parser.add_option("-m", "--m", dest="mongoHost",
18
                      default="localhost",
19
                      type="string", help="The HOST where the mongo server is running",
20
                      metavar="mongo_host")
21
 
22
(options, args) = parser.parse_args()
23
 
16019 kshitij.so 24
SOURCE_MAP = {'AMAZON':1,'FLIPKART':2,'SNAPDEAL':3,'SAHOLIC':4, 'SHOPCLUES.COM':5}
15869 kshitij.so 25
bestSellers = []
26
baseUrl = "http://m.shopclues.com/products/getProductList/mobiles:top-selling-mobiles-and-tablets.html/%s/page=%s"
15895 kshitij.so 27
headers = {
28
            'User-Agent':'Mozilla/5.0 (Linux; Android 4.3; Nexus 7 Build/JSS15Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.72 Safari/537.36',
29
            'Accept' : 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',      
30
            'Accept-Language' : 'en-US,en;q=0.8',                     
31
            'Accept-Charset' : 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
16019 kshitij.so 32
            'Connection':'keep-alive'
15895 kshitij.so 33
        }
15869 kshitij.so 34
now = datetime.now()
16019 kshitij.so 35
mc = MemCache(options.mongoHost)
16099 kshitij.so 36
sc = ShopCluesScraper.ShopCluesScraper(findThumbnail=True)
15869 kshitij.so 37
 
16095 kshitij.so 38
bundledProducts = []
39
exceptionList = []
15869 kshitij.so 40
 
16095 kshitij.so 41
 
15869 kshitij.so 42
class __ProductInfo:
43
 
44
    def __init__(self, identifier, rank, url, available_price, in_stock, codAvailable, source_product_name, thumbnail, coupon):
45
        self.identifier = identifier
46
        self.rank  = rank
47
        self.url = url
48
        self.available_price = available_price
49
        self.in_stock = in_stock
50
        self.codAvailable = codAvailable
51
        self.source_product_name = source_product_name
52
        self.thumbnail = thumbnail
16095 kshitij.so 53
        self.coupon = coupon
15869 kshitij.so 54
 
16095 kshitij.so 55
class __NewBundled:
56
    def __init__(self, newProduct, oldProduct):
57
        self.newProduct = newProduct
58
        self.oldProduct = oldProduct
59
 
15869 kshitij.so 60
def get_mongo_connection(host=options.mongoHost, port=27017):
61
    global con
62
    if con is None:
63
        print "Establishing connection %s host and port %d" %(host,port)
64
        try:
65
            con = pymongo.MongoClient(host, port)
66
        except Exception, e:
67
            print e
68
            return None
69
    return con
70
 
71
def getSoupObject(url):
72
    print "Getting soup object for"
73
    print url
74
    global RETRY_COUNT
75
    RETRY_COUNT = 1 
76
    while RETRY_COUNT < 10:
77
        try:
78
            soup = None
16019 kshitij.so 79
            request = urllib2.Request(url, headers=headers)
15869 kshitij.so 80
            response = urllib2.urlopen(request)   
81
            response_data = response.read()
82
            response.close()
83
            try:
84
                page=response_data.decode("utf-8")
85
                soup = BeautifulSoup(page,convertEntities=BeautifulSoup.HTML_ENTITIES)
86
            except:
16019 kshitij.so 87
                print traceback.print_exc()
15869 kshitij.so 88
                soup = BeautifulSoup(response_data,convertEntities=BeautifulSoup.HTML_ENTITIES)
89
            if soup is None:
90
                raise
91
            return soup
92
        except Exception as e:
16019 kshitij.so 93
            traceback.print_exc()
15869 kshitij.so 94
            print "Retrying"
95
            RETRY_COUNT = RETRY_COUNT + 1
96
 
97
 
98
def scrapeBestSellers():
99
    global bestSellers
16095 kshitij.so 100
    global exceptionList
15869 kshitij.so 101
    bestSellers = []
102
    rank = 0
103
    page = 1
104
    while (True):
105
        url = (baseUrl)%(page,page-1)
106
        soup = getSoupObject(url)
107
        productDivs = soup.findAll('div',{'class':'pd-list-cont'})
108
        if productDivs is None or len(productDivs)==0:
109
            return
110
        for productDiv in productDivs:
111
            rank = rank + 1
112
            info_tag =  productDiv.find('a')
113
            link = info_tag['href']
114
            scin = info_tag['data-id'].strip()
115
            print link
116
            print scin
15895 kshitij.so 117
            productName = productDiv.find('div',{'class':'pdt-name'}).string
118
            try:
119
                productInfo = sc.read(link)
120
            except Exception as e:
121
                traceback.print_exc()
122
                continue
15869 kshitij.so 123
            product = list(get_mongo_connection().Catalog.MasterData.find({'source_id':5,'identifier':scin}))
124
            if len(product) > 0:
16019 kshitij.so 125
                if productInfo['inStock'] ==1:
126
                    get_mongo_connection().Catalog.MasterData.update({'_id':product[0]['_id']},{"$set":{'rank':rank, 'available_price':productInfo['price'], \
15895 kshitij.so 127
                                                                                                            'in_stock':productInfo['inStock'], 'codAvailable':productInfo['isCod'], \
16021 kshitij.so 128
                                                                                                            'coupon':productInfo['coupon'], 'updatedOn':to_java_date(datetime.now()),'priceUpdatedOn':to_java_date(datetime.now())}})
16084 kshitij.so 129
                    get_mongo_connection().Catalog.Deals.update({'_id':product[0]['_id']}, {'$set' : {'rank':rank,'available_price':productInfo['price'] , 'in_stock':productInfo['inStock'],'codAvailable':productInfo['isCod']}})
16019 kshitij.so 130
                else:
131
                    get_mongo_connection().Catalog.MasterData.update({'_id':product[0]['_id']}, {'$set' : {'updatedOn':to_java_date(datetime.now()),'in_stock':0,'priceUpdatedOn':to_java_date(datetime.now())}})
132
                    get_mongo_connection().Catalog.Deals.update({'_id':product[0]['_id']}, {'$set' : {'in_stock':0}})
133
 
134
                try:
135
                    recomputeDeal(product[0])
136
                except:
137
                    print "Unable to compute deal for %s"%(product[0]['skuBundleId'])
138
 
15869 kshitij.so 139
            else:
140
                #Lets bundle product by finding similar url pattern
15895 kshitij.so 141
                uri = link.replace('http://m.shopclues.com','').replace(".html","")
142
                try:
143
                    int(uri[uri.rfind('-')+1:])
144
                    uri =  uri[:uri.rfind('-')]
145
                except:
146
                    pass
147
                product = list(get_mongo_connection().Catalog.MasterData.find({'source_id':5,'marketPlaceUrl':{'$regex': uri}}))
16099 kshitij.so 148
                toBundle = __ProductInfo(scin, rank, link, productInfo['price'], productInfo['inStock'],productInfo['isCod'], productName, productInfo['thumbnail'] ,productInfo['coupon'])
15869 kshitij.so 149
                if len(product) > 0:
15895 kshitij.so 150
                    bundleNewProduct(product[0], toBundle)
16028 kshitij.so 151
                    try:
152
                        recomputeDeal(product[0])
153
                    except:
154
                        print "Unable to compute deal for %s"%(product[0]['skuBundleId'])
15895 kshitij.so 155
                else:
156
                    exceptionList.append(toBundle)
15869 kshitij.so 157
        page = page+1
16019 kshitij.so 158
 
159
def populateNegativeDeals():
160
    negativeDeals = get_mongo_connection().Catalog.NegativeDeals.find().distinct('sku')
161
    mc.set("negative_deals", negativeDeals, 600)
162
 
163
def recomputePoints(item, deal):
164
    try:
165
        nlcPoints = getNlcPoints(item, deal['minNlc'], deal['maxNlc'], deal['available_price'])
166
    except:
167
        traceback.print_exc()
168
        nlcPoints = deal['nlcPoints']
169
    if item['manualDealThresholdPrice'] >= deal['available_price']:
170
        dealPoints = item['dealPoints']
171
    else:
172
        dealPoints = 0
173
    get_mongo_connection().Catalog.Deals.update({'_id':deal['_id']},{"$set":{'totalPoints':deal['totalPoints'] - deal['nlcPoints'] + nlcPoints - deal['dealPoints'] +dealPoints , 'nlcPoints': nlcPoints, 'dealPoints': dealPoints, 'manualDealThresholdPrice': item['manualDealThresholdPrice']}})
174
 
175
 
176
def recomputeDeal(item):
177
    """Lets recompute deal for this bundle"""
178
    print "Recomputing for bundleId %d" %(item.get('skuBundleId'))
179
    skuBundleId = item['skuBundleId']
16026 kshitij.so 180
    item['dealFlag'] = 0
181
    item['dealType'] = 0
182
    item['dealPoints'] = 0
183
    item['manualDealThresholdPrice'] = None
184
    manualDeals = list(get_mongo_connection().Catalog.ManualDeals.find({'startDate':{'$lte':to_java_date(datetime.now())},'endDate':{'$gte':to_java_date(datetime.now())},'source_id':item['source_id'], 'sku':item['_id']}))
185
    if len(manualDeals) > 0:
186
        item['dealFlag'] = 1
187
        item['dealType'] =manualDeals[0]['dealType']
188
        item['dealPoints'] = manualDeals[0]['dealPoints']
189
        item['manualDealThresholdPrice'] = manualDeals[0]['dealThresholdPrice']
16019 kshitij.so 190
    similarItems = list(get_mongo_connection().Catalog.Deals.find({'skuBundleId':skuBundleId}).sort([('available_price',pymongo.ASCENDING)]))
191
    bestPrice = float("inf")
192
    bestOne = None
193
    bestSellerPoints = 0
194
    toUpdate = []
195
    prepaidBestPrice = float("inf")
196
    prepaidBestOne = None
197
    prepaidBestSellerPoints = 0
198
    for similarItem in similarItems:
199
        if similarItem['_id'] == item['_id']:
200
            try:
201
                recomputePoints(item, similarItem)
202
            except:
203
                traceback.print_exc()
204
        if similarItem['codAvailable'] ==1:
205
            if mc.get("negative_deals") is None:
206
                populateNegativeDeals()
207
            if similarItem['in_stock'] == 0 or similarItem['maxprice'] is None or similarItem['maxprice'] < similarItem['available_price'] or similarItem['_id'] in mc.get("negative_deals"):
208
                get_mongo_connection().Catalog.Deals.update({ '_id' : similarItem['_id'] }, {'$set':{'showDeal':0, 'prepaidDeal':0 }})
209
                continue
210
            if similarItem['source_id'] == SOURCE_MAP.get('SHOPCLUES.COM') and similarItem['rank']==0:
211
                get_mongo_connection().Catalog.Deals.update({ '_id' : similarItem['_id'] }, {'$set':{'showDeal':0,'prepaidDeal':0 }})
212
                continue
213
            if similarItem['available_price'] < bestPrice:
214
                bestOne = similarItem
215
                bestPrice = similarItem['available_price']
216
                bestSellerPoints = similarItem['bestSellerPoints']
217
            elif similarItem['available_price'] == bestPrice and bestSellerPoints < similarItem['bestSellerPoints']:
218
                bestOne = similarItem
219
                bestPrice = similarItem['available_price']
220
                bestSellerPoints = similarItem['bestSellerPoints']
221
            else:
222
                pass
223
        else:
224
            if mc.get("negative_deals") is None:
225
                populateNegativeDeals()
226
            if similarItem['in_stock'] == 0 or similarItem['maxprice'] is None or similarItem['maxprice'] < similarItem['available_price'] or similarItem['_id'] in mc.get("negative_deals"):
227
                get_mongo_connection().Catalog.Deals.update({ '_id' : similarItem['_id'] }, {'$set':{'showDeal':0, 'prepaidDeal':0 }})
228
                continue
229
            if similarItem['source_id'] == SOURCE_MAP.get('SHOPCLUES.COM') and similarItem['rank']==0:
230
                get_mongo_connection().Catalog.Deals.update({ '_id' : similarItem['_id'] }, {'$set':{'showDeal':0,'prepaidDeal':0 }})
231
                continue
232
            if similarItem['available_price'] < prepaidBestPrice:
233
                prepaidBestOne = similarItem
234
                prepaidBestPrice = similarItem['available_price']
235
                prepaidBestSellerPoints = similarItem['bestSellerPoints']
236
            elif similarItem['available_price'] == prepaidBestPrice and prepaidBestSellerPoints < similarItem['bestSellerPoints']:
237
                prepaidBestOne = similarItem
238
                prepaidBestPrice = similarItem['available_price']
239
                prepaidBestSellerPoints = similarItem['bestSellerPoints']
240
            else:
241
                pass
16026 kshitij.so 242
    if bestOne is not None or prepaidBestOne is not None:
16019 kshitij.so 243
        for similarItem in similarItems:
244
            toUpdate.append(similarItem['_id'])
16026 kshitij.so 245
        if bestOne is not None:
246
            toUpdate.remove(bestOne['_id'])
247
            get_mongo_connection().Catalog.Deals.update({ '_id' : bestOne['_id'] }, {'$set':{'showDeal':1,'prepaidDeal':0 }})
248
        if prepaidBestOne is not None:
16076 kshitij.so 249
            if bestOne is not None:
250
                if prepaidBestOne['available_price'] < bestOne['available_price']: 
251
                    toUpdate.remove(prepaidBestOne['_id'])
252
                    get_mongo_connection().Catalog.Deals.update({ '_id' : prepaidBestOne['_id'] }, {'$set':{'showDeal':0,'prepaidDeal':1 }})
253
            else:
254
                toUpdate.remove(prepaidBestOne['_id'])
255
                get_mongo_connection().Catalog.Deals.update({ '_id' : prepaidBestOne['_id'] }, {'$set':{'showDeal':0,'prepaidDeal':1 }})
16019 kshitij.so 256
    if len(toUpdate) > 0:
257
        get_mongo_connection().Catalog.Deals.update({ '_id' : { "$in": toUpdate } }, {'$set':{'showDeal':0,'prepaidDeal':0 }},upsert=False, multi=True)
258
 
15869 kshitij.so 259
 
260
def bundleNewProduct(existingProduct, toBundle):
16095 kshitij.so 261
    global bundledProducts
262
    global exceptionList
15895 kshitij.so 263
    print "Adding new product"
264
    try:
265
        max_id = list(get_mongo_connection().Catalog.MasterData.find().sort([('_id',pymongo.DESCENDING)]).limit(1))
266
        existingProduct['_id'] = max_id[0]['_id'] + 1
267
        existingProduct['addedOn'] = to_java_date(datetime.now())
268
        existingProduct['available_price'] = toBundle.available_price
269
        existingProduct['updatedOn'] = to_java_date(datetime.now())
270
        existingProduct['codAvailable'] = toBundle.codAvailable
16095 kshitij.so 271
        existingProduct['coupon'] = str(toBundle.coupon)
272
        existingProduct['identifier'] = str(toBundle.identifier)
15895 kshitij.so 273
        existingProduct['in_stock'] = toBundle.in_stock
274
        existingProduct['marketPlaceUrl'] = toBundle.url
275
        existingProduct['rank'] = toBundle.rank
276
        existingProduct['source_product_name'] = toBundle.source_product_name
277
        existingProduct['url'] = toBundle.url
278
        get_mongo_connection().Catalog.MasterData.insert(existingProduct)
16095 kshitij.so 279
        newBundled = __NewBundled(toBundle, existingProduct)
280
        bundledProducts.append(newBundled)
15895 kshitij.so 281
        return {1:'Data added successfully.'}
282
    except Exception as e:
283
        print e
16095 kshitij.so 284
        exceptionList.append(toBundle)
15895 kshitij.so 285
        return {0:'Unable to add data.'}
15869 kshitij.so 286
 
16095 kshitij.so 287
def sendMail():
288
    message="""<html>
289
            <body>
290
            <h3>ShopClues Best Sellers Auto Bundled</h3>
291
            <table border="1" style="width:100%;">
292
            <thead>
293
            <tr>
294
            <th>Item Id</th>
295
            <th>Identifier</th>
296
            <th>Rank</th>
297
            <th>Product Name</th>
298
            <th>Bundle Id</th>
299
            <th>Bundled with Brand</th>
300
            <th>Bundled with Product Name</th>
301
            <th>Available_price</th>
302
            <th>In Stock</th>
303
            <th>Coupon</th>
304
            <th>COD Available</th>
305
            </tr></thead>
306
            <tbody>"""
307
    for bundledProduct in bundledProducts:
308
        newProduct = bundledProduct.newProduct
309
        oldProduct = bundledProduct.oldProduct
310
        message+="""<tr>
311
        <td style="text-align:center">"""+str(oldProduct.get('_id'))+"""</td>
312
        <td style="text-align:center">"""+oldProduct.get('identifier')+"""</td>
313
        <td style="text-align:center">"""+str(oldProduct.get('rank'))+"""</td>
314
        <td style="text-align:center">"""+(oldProduct.get('source_product_name'))+"""</td>
315
        <td style="text-align:center">"""+str(oldProduct.get('skuBundleId'))+"""</td>
316
        <td style="text-align:center">"""+(oldProduct.get('brand'))+"""</td>
317
        <td style="text-align:center">"""+(oldProduct.get('product_name'))+"""</td>
318
        <td style="text-align:center">"""+str(oldProduct.get('available_price'))+"""</td>
319
        <td style="text-align:center">"""+str(oldProduct.get('in_stock'))+"""</td>
320
        <td style="text-align:center">"""+str(oldProduct.get('coupon'))+"""</td>
321
        <td style="text-align:center">"""+str(oldProduct.get('codAvailable'))+"""</td>
322
        </tr>"""
323
    message+="""</tbody></table><h3>Items not bundled</h3><table border="1" style="width:100%;">
324
    <tr>
325
    <th>Identifier</th>
326
    <th>Rank</th>
327
    <th>Product Name</th>
328
    <th>Url</th>
329
    <th>Available Price</th>
330
    <th>In Stock</th>
331
    <th>COD Available</th>
332
    <th>Coupon</th>
16099 kshitij.so 333
    <th>Thumbnail</th>
16095 kshitij.so 334
    </tr></thead>
335
    <tbody>"""
336
    for exceptionItem in exceptionList:
337
        message+="""<tr>
338
        <td style="text-align:center">"""+str(exceptionItem.identifier)+"""</td>
339
        <td style="text-align:center">"""+str(exceptionItem.rank)+"""</td>
340
        <td style="text-align:center">"""+(exceptionItem.source_product_name)+"""</td>
341
        <td style="text-align:center">"""+(exceptionItem.url)+"""</td>
342
        <td style="text-align:center">"""+str(exceptionItem.available_price)+"""</td>
343
        <td style="text-align:center">"""+str(exceptionItem.in_stock)+"""</td>
344
        <td style="text-align:center">"""+str(exceptionItem.codAvailable)+"""</td>
345
        <td style="text-align:center">"""+str(exceptionItem.coupon)+"""</td>
16101 kshitij.so 346
        <td style="text-align:center">"""+(exceptionItem.thumbnail)+"""</td>
16095 kshitij.so 347
        </tr>"""
348
    message+="""</tbody></table></body></html>"""
349
    print message
350
    recipients = ['kshitij.sood@saholic.com']
351
    #recipients = ['rajneesh.arora@saholic.com','kshitij.sood@saholic.com','chaitnaya.vats@saholic.com','manoj.kumar@saholic.com']
352
    msg = MIMEMultipart()
353
    msg['Subject'] = "Shopclues Best Sellers" + ' - ' + str(datetime.now())
354
    msg['From'] = ""
355
    msg['To'] = ",".join(recipients)
356
    msg.preamble = "Shopclues Best Sellers" + ' - ' + str(datetime.now())
357
    html_msg = MIMEText(message, 'html')
358
    msg.attach(html_msg)
359
 
360
    smtpServer = smtplib.SMTP('localhost')
361
    smtpServer.set_debuglevel(1)
362
    sender = 'dtr@shop2020.in'
363
    try:
364
        smtpServer.sendmail(sender, recipients, msg.as_string())
365
        print "Successfully sent email"
366
    except:
16101 kshitij.so 367
        traceback.print_exc()
16095 kshitij.so 368
        print "Error: unable to send email."
369
 
15895 kshitij.so 370
 
16095 kshitij.so 371
 
372
 
15895 kshitij.so 373
 
15869 kshitij.so 374
def main():
375
    scrapeBestSellers()
16095 kshitij.so 376
    sendMail()
15869 kshitij.so 377
 
378
if __name__=='__main__':
379
    main()