Subversion Repositories SmartDukaan

Rev

Rev 16190 | Rev 16869 | 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
 
16019 kshitij.so 29
SOURCE_MAP = {'AMAZON':1,'FLIPKART':2,'SNAPDEAL':3,'SAHOLIC':4, 'SHOPCLUES.COM':5}
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
239
            if similarItem['available_price'] < prepaidBestPrice:
240
                prepaidBestOne = similarItem
241
                prepaidBestPrice = similarItem['available_price']
242
                prepaidBestSellerPoints = similarItem['bestSellerPoints']
243
            elif similarItem['available_price'] == prepaidBestPrice and prepaidBestSellerPoints < similarItem['bestSellerPoints']:
244
                prepaidBestOne = similarItem
245
                prepaidBestPrice = similarItem['available_price']
246
                prepaidBestSellerPoints = similarItem['bestSellerPoints']
247
            else:
248
                pass
16026 kshitij.so 249
    if bestOne is not None or prepaidBestOne is not None:
16019 kshitij.so 250
        for similarItem in similarItems:
251
            toUpdate.append(similarItem['_id'])
16026 kshitij.so 252
        if bestOne is not None:
253
            toUpdate.remove(bestOne['_id'])
254
            get_mongo_connection().Catalog.Deals.update({ '_id' : bestOne['_id'] }, {'$set':{'showDeal':1,'prepaidDeal':0 }})
255
        if prepaidBestOne is not None:
16076 kshitij.so 256
            if bestOne is not None:
257
                if prepaidBestOne['available_price'] < bestOne['available_price']: 
258
                    toUpdate.remove(prepaidBestOne['_id'])
259
                    get_mongo_connection().Catalog.Deals.update({ '_id' : prepaidBestOne['_id'] }, {'$set':{'showDeal':0,'prepaidDeal':1 }})
260
            else:
261
                toUpdate.remove(prepaidBestOne['_id'])
262
                get_mongo_connection().Catalog.Deals.update({ '_id' : prepaidBestOne['_id'] }, {'$set':{'showDeal':0,'prepaidDeal':1 }})
16019 kshitij.so 263
    if len(toUpdate) > 0:
264
        get_mongo_connection().Catalog.Deals.update({ '_id' : { "$in": toUpdate } }, {'$set':{'showDeal':0,'prepaidDeal':0 }},upsert=False, multi=True)
265
 
15869 kshitij.so 266
 
267
def bundleNewProduct(existingProduct, toBundle):
16095 kshitij.so 268
    global bundledProducts
269
    global exceptionList
15895 kshitij.so 270
    print "Adding new product"
271
    try:
272
        max_id = list(get_mongo_connection().Catalog.MasterData.find().sort([('_id',pymongo.DESCENDING)]).limit(1))
273
        existingProduct['_id'] = max_id[0]['_id'] + 1
274
        existingProduct['addedOn'] = to_java_date(datetime.now())
275
        existingProduct['available_price'] = toBundle.available_price
276
        existingProduct['updatedOn'] = to_java_date(datetime.now())
277
        existingProduct['codAvailable'] = toBundle.codAvailable
16095 kshitij.so 278
        existingProduct['coupon'] = str(toBundle.coupon)
279
        existingProduct['identifier'] = str(toBundle.identifier)
15895 kshitij.so 280
        existingProduct['in_stock'] = toBundle.in_stock
281
        existingProduct['marketPlaceUrl'] = toBundle.url
282
        existingProduct['rank'] = toBundle.rank
283
        existingProduct['source_product_name'] = toBundle.source_product_name
284
        existingProduct['url'] = toBundle.url
285
        get_mongo_connection().Catalog.MasterData.insert(existingProduct)
16095 kshitij.so 286
        newBundled = __NewBundled(toBundle, existingProduct)
287
        bundledProducts.append(newBundled)
15895 kshitij.so 288
        return {1:'Data added successfully.'}
289
    except Exception as e:
290
        print e
16095 kshitij.so 291
        exceptionList.append(toBundle)
15895 kshitij.so 292
        return {0:'Unable to add data.'}
15869 kshitij.so 293
 
16095 kshitij.so 294
def sendMail():
295
    message="""<html>
296
            <body>
297
            <h3>ShopClues Best Sellers Auto Bundled</h3>
298
            <table border="1" style="width:100%;">
299
            <thead>
300
            <tr>
301
            <th>Item Id</th>
302
            <th>Identifier</th>
303
            <th>Rank</th>
304
            <th>Product Name</th>
305
            <th>Bundle Id</th>
306
            <th>Bundled with Brand</th>
307
            <th>Bundled with Product Name</th>
308
            <th>Available_price</th>
309
            <th>In Stock</th>
310
            <th>Coupon</th>
311
            <th>COD Available</th>
312
            </tr></thead>
313
            <tbody>"""
314
    for bundledProduct in bundledProducts:
315
        newProduct = bundledProduct.newProduct
316
        oldProduct = bundledProduct.oldProduct
317
        message+="""<tr>
318
        <td style="text-align:center">"""+str(oldProduct.get('_id'))+"""</td>
319
        <td style="text-align:center">"""+oldProduct.get('identifier')+"""</td>
320
        <td style="text-align:center">"""+str(oldProduct.get('rank'))+"""</td>
321
        <td style="text-align:center">"""+(oldProduct.get('source_product_name'))+"""</td>
322
        <td style="text-align:center">"""+str(oldProduct.get('skuBundleId'))+"""</td>
323
        <td style="text-align:center">"""+(oldProduct.get('brand'))+"""</td>
324
        <td style="text-align:center">"""+(oldProduct.get('product_name'))+"""</td>
325
        <td style="text-align:center">"""+str(oldProduct.get('available_price'))+"""</td>
326
        <td style="text-align:center">"""+str(oldProduct.get('in_stock'))+"""</td>
327
        <td style="text-align:center">"""+str(oldProduct.get('coupon'))+"""</td>
328
        <td style="text-align:center">"""+str(oldProduct.get('codAvailable'))+"""</td>
329
        </tr>"""
330
    message+="""</tbody></table><h3>Items not bundled</h3><table border="1" style="width:100%;">
331
    <tr>
332
    <th>Identifier</th>
333
    <th>Rank</th>
334
    <th>Product Name</th>
335
    <th>Url</th>
336
    <th>Available Price</th>
337
    <th>In Stock</th>
338
    <th>COD Available</th>
339
    <th>Coupon</th>
16099 kshitij.so 340
    <th>Thumbnail</th>
16095 kshitij.so 341
    </tr></thead>
342
    <tbody>"""
343
    for exceptionItem in exceptionList:
344
        message+="""<tr>
345
        <td style="text-align:center">"""+str(exceptionItem.identifier)+"""</td>
346
        <td style="text-align:center">"""+str(exceptionItem.rank)+"""</td>
347
        <td style="text-align:center">"""+(exceptionItem.source_product_name)+"""</td>
348
        <td style="text-align:center">"""+(exceptionItem.url)+"""</td>
349
        <td style="text-align:center">"""+str(exceptionItem.available_price)+"""</td>
350
        <td style="text-align:center">"""+str(exceptionItem.in_stock)+"""</td>
351
        <td style="text-align:center">"""+str(exceptionItem.codAvailable)+"""</td>
352
        <td style="text-align:center">"""+str(exceptionItem.coupon)+"""</td>
16102 kshitij.so 353
        <td style="text-align:left">"""+(exceptionItem.thumbnail)+"""</td>
16095 kshitij.so 354
        </tr>"""
355
    message+="""</tbody></table></body></html>"""
356
    print message
16184 kshitij.so 357
    encoding = chardet.detect(message)
358
    try:
359
        message = message.decode(encoding.get('encoding'))
360
    except:
361
        pass
16182 kshitij.so 362
    #recipients = ['kshitij.sood@saholic.com']
363
    recipients = ['rajneesh.arora@saholic.com','kshitij.sood@saholic.com','chaitnaya.vats@saholic.com','manoj.kumar@saholic.com']
16095 kshitij.so 364
    msg = MIMEMultipart()
365
    msg['Subject'] = "Shopclues Best Sellers" + ' - ' + str(datetime.now())
366
    msg['From'] = ""
367
    msg['To'] = ",".join(recipients)
368
    msg.preamble = "Shopclues Best Sellers" + ' - ' + str(datetime.now())
369
    html_msg = MIMEText(message, 'html')
370
    msg.attach(html_msg)
371
 
372
    smtpServer = smtplib.SMTP('localhost')
373
    smtpServer.set_debuglevel(1)
374
    sender = 'dtr@shop2020.in'
375
    try:
376
        smtpServer.sendmail(sender, recipients, msg.as_string())
377
        print "Successfully sent email"
378
    except:
16101 kshitij.so 379
        traceback.print_exc()
16095 kshitij.so 380
        print "Error: unable to send email."
381
 
16183 kshitij.so 382
def resetRanks():
16103 kshitij.so 383
    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 384
 
15869 kshitij.so 385
def main():
16103 kshitij.so 386
    if options.reset == 'True':
387
        resetRanks()
15869 kshitij.so 388
    scrapeBestSellers()
16102 kshitij.so 389
    if len(bundledProducts)>0 or len(exceptionList) > 0:
390
        sendMail()
16190 kshitij.so 391
    else:
392
        "print nothing to send"
15869 kshitij.so 393
 
394
if __name__=='__main__':
395
    main()