Subversion Repositories SmartDukaan

Rev

Rev 16869 | Rev 19189 | 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
17747 kshitij.so 287
        existingProduct['showVideo'] = 0
288
        existingProduct['shippingCost'] = 0
289
        existingProduct['quantity'] = 1
290
        existingProduct['videoLink'] = ""
15895 kshitij.so 291
        get_mongo_connection().Catalog.MasterData.insert(existingProduct)
16095 kshitij.so 292
        newBundled = __NewBundled(toBundle, existingProduct)
293
        bundledProducts.append(newBundled)
15895 kshitij.so 294
        return {1:'Data added successfully.'}
295
    except Exception as e:
296
        print e
16095 kshitij.so 297
        exceptionList.append(toBundle)
15895 kshitij.so 298
        return {0:'Unable to add data.'}
15869 kshitij.so 299
 
16095 kshitij.so 300
def sendMail():
301
    message="""<html>
302
            <body>
303
            <h3>ShopClues Best Sellers Auto Bundled</h3>
304
            <table border="1" style="width:100%;">
305
            <thead>
306
            <tr>
307
            <th>Item Id</th>
308
            <th>Identifier</th>
309
            <th>Rank</th>
310
            <th>Product Name</th>
311
            <th>Bundle Id</th>
312
            <th>Bundled with Brand</th>
313
            <th>Bundled with Product Name</th>
314
            <th>Available_price</th>
315
            <th>In Stock</th>
316
            <th>Coupon</th>
317
            <th>COD Available</th>
318
            </tr></thead>
319
            <tbody>"""
320
    for bundledProduct in bundledProducts:
321
        newProduct = bundledProduct.newProduct
322
        oldProduct = bundledProduct.oldProduct
323
        message+="""<tr>
324
        <td style="text-align:center">"""+str(oldProduct.get('_id'))+"""</td>
325
        <td style="text-align:center">"""+oldProduct.get('identifier')+"""</td>
326
        <td style="text-align:center">"""+str(oldProduct.get('rank'))+"""</td>
327
        <td style="text-align:center">"""+(oldProduct.get('source_product_name'))+"""</td>
328
        <td style="text-align:center">"""+str(oldProduct.get('skuBundleId'))+"""</td>
329
        <td style="text-align:center">"""+(oldProduct.get('brand'))+"""</td>
330
        <td style="text-align:center">"""+(oldProduct.get('product_name'))+"""</td>
331
        <td style="text-align:center">"""+str(oldProduct.get('available_price'))+"""</td>
332
        <td style="text-align:center">"""+str(oldProduct.get('in_stock'))+"""</td>
333
        <td style="text-align:center">"""+str(oldProduct.get('coupon'))+"""</td>
334
        <td style="text-align:center">"""+str(oldProduct.get('codAvailable'))+"""</td>
335
        </tr>"""
336
    message+="""</tbody></table><h3>Items not bundled</h3><table border="1" style="width:100%;">
337
    <tr>
338
    <th>Identifier</th>
339
    <th>Rank</th>
340
    <th>Product Name</th>
341
    <th>Url</th>
342
    <th>Available Price</th>
343
    <th>In Stock</th>
344
    <th>COD Available</th>
345
    <th>Coupon</th>
16099 kshitij.so 346
    <th>Thumbnail</th>
16095 kshitij.so 347
    </tr></thead>
348
    <tbody>"""
349
    for exceptionItem in exceptionList:
350
        message+="""<tr>
351
        <td style="text-align:center">"""+str(exceptionItem.identifier)+"""</td>
352
        <td style="text-align:center">"""+str(exceptionItem.rank)+"""</td>
353
        <td style="text-align:center">"""+(exceptionItem.source_product_name)+"""</td>
354
        <td style="text-align:center">"""+(exceptionItem.url)+"""</td>
355
        <td style="text-align:center">"""+str(exceptionItem.available_price)+"""</td>
356
        <td style="text-align:center">"""+str(exceptionItem.in_stock)+"""</td>
357
        <td style="text-align:center">"""+str(exceptionItem.codAvailable)+"""</td>
358
        <td style="text-align:center">"""+str(exceptionItem.coupon)+"""</td>
16102 kshitij.so 359
        <td style="text-align:left">"""+(exceptionItem.thumbnail)+"""</td>
16095 kshitij.so 360
        </tr>"""
361
    message+="""</tbody></table></body></html>"""
362
    print message
16184 kshitij.so 363
    encoding = chardet.detect(message)
364
    try:
365
        message = message.decode(encoding.get('encoding'))
366
    except:
367
        pass
16182 kshitij.so 368
    #recipients = ['kshitij.sood@saholic.com']
369
    recipients = ['rajneesh.arora@saholic.com','kshitij.sood@saholic.com','chaitnaya.vats@saholic.com','manoj.kumar@saholic.com']
16095 kshitij.so 370
    msg = MIMEMultipart()
371
    msg['Subject'] = "Shopclues Best Sellers" + ' - ' + str(datetime.now())
372
    msg['From'] = ""
373
    msg['To'] = ",".join(recipients)
374
    msg.preamble = "Shopclues Best Sellers" + ' - ' + str(datetime.now())
375
    html_msg = MIMEText(message, 'html')
376
    msg.attach(html_msg)
377
 
378
    smtpServer = smtplib.SMTP('localhost')
379
    smtpServer.set_debuglevel(1)
380
    sender = 'dtr@shop2020.in'
381
    try:
382
        smtpServer.sendmail(sender, recipients, msg.as_string())
383
        print "Successfully sent email"
384
    except:
16101 kshitij.so 385
        traceback.print_exc()
16095 kshitij.so 386
        print "Error: unable to send email."
387
 
16183 kshitij.so 388
def resetRanks():
16103 kshitij.so 389
    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 390
 
15869 kshitij.so 391
def main():
16103 kshitij.so 392
    if options.reset == 'True':
393
        resetRanks()
15869 kshitij.so 394
    scrapeBestSellers()
16102 kshitij.so 395
    if len(bundledProducts)>0 or len(exceptionList) > 0:
396
        sendMail()
16190 kshitij.so 397
    else:
398
        "print nothing to send"
15869 kshitij.so 399
 
400
if __name__=='__main__':
401
    main()