Subversion Repositories SmartDukaan

Rev

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