Subversion Repositories SmartDukaan

Rev

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