Subversion Repositories SmartDukaan

Rev

Rev 16184 | Rev 16505 | 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:
16019 kshitij.so 130
                if productInfo['inStock'] ==1:
131
                    get_mongo_connection().Catalog.MasterData.update({'_id':product[0]['_id']},{"$set":{'rank':rank, 'available_price':productInfo['price'], \
15895 kshitij.so 132
                                                                                                            'in_stock':productInfo['inStock'], 'codAvailable':productInfo['isCod'], \
16021 kshitij.so 133
                                                                                                            'coupon':productInfo['coupon'], 'updatedOn':to_java_date(datetime.now()),'priceUpdatedOn':to_java_date(datetime.now())}})
16084 kshitij.so 134
                    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 135
                else:
136
                    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())}})
137
                    get_mongo_connection().Catalog.Deals.update({'_id':product[0]['_id']}, {'$set' : {'in_stock':0}})
138
 
139
                try:
140
                    recomputeDeal(product[0])
141
                except:
142
                    print "Unable to compute deal for %s"%(product[0]['skuBundleId'])
143
 
15869 kshitij.so 144
            else:
145
                #Lets bundle product by finding similar url pattern
15895 kshitij.so 146
                uri = link.replace('http://m.shopclues.com','').replace(".html","")
147
                try:
148
                    int(uri[uri.rfind('-')+1:])
149
                    uri =  uri[:uri.rfind('-')]
150
                except:
151
                    pass
152
                product = list(get_mongo_connection().Catalog.MasterData.find({'source_id':5,'marketPlaceUrl':{'$regex': uri}}))
16099 kshitij.so 153
                toBundle = __ProductInfo(scin, rank, link, productInfo['price'], productInfo['inStock'],productInfo['isCod'], productName, productInfo['thumbnail'] ,productInfo['coupon'])
15869 kshitij.so 154
                if len(product) > 0:
15895 kshitij.so 155
                    bundleNewProduct(product[0], toBundle)
16028 kshitij.so 156
                    try:
157
                        recomputeDeal(product[0])
158
                    except:
159
                        print "Unable to compute deal for %s"%(product[0]['skuBundleId'])
15895 kshitij.so 160
                else:
161
                    exceptionList.append(toBundle)
15869 kshitij.so 162
        page = page+1
16019 kshitij.so 163
 
164
def populateNegativeDeals():
165
    negativeDeals = get_mongo_connection().Catalog.NegativeDeals.find().distinct('sku')
166
    mc.set("negative_deals", negativeDeals, 600)
167
 
168
def recomputePoints(item, deal):
169
    try:
170
        nlcPoints = getNlcPoints(item, deal['minNlc'], deal['maxNlc'], deal['available_price'])
171
    except:
172
        traceback.print_exc()
173
        nlcPoints = deal['nlcPoints']
174
    if item['manualDealThresholdPrice'] >= deal['available_price']:
175
        dealPoints = item['dealPoints']
176
    else:
177
        dealPoints = 0
178
    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']}})
179
 
180
 
181
def recomputeDeal(item):
182
    """Lets recompute deal for this bundle"""
183
    print "Recomputing for bundleId %d" %(item.get('skuBundleId'))
184
    skuBundleId = item['skuBundleId']
16026 kshitij.so 185
    item['dealFlag'] = 0
186
    item['dealType'] = 0
187
    item['dealPoints'] = 0
188
    item['manualDealThresholdPrice'] = None
189
    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']}))
190
    if len(manualDeals) > 0:
191
        item['dealFlag'] = 1
192
        item['dealType'] =manualDeals[0]['dealType']
193
        item['dealPoints'] = manualDeals[0]['dealPoints']
194
        item['manualDealThresholdPrice'] = manualDeals[0]['dealThresholdPrice']
16019 kshitij.so 195
    similarItems = list(get_mongo_connection().Catalog.Deals.find({'skuBundleId':skuBundleId}).sort([('available_price',pymongo.ASCENDING)]))
196
    bestPrice = float("inf")
197
    bestOne = None
198
    bestSellerPoints = 0
199
    toUpdate = []
200
    prepaidBestPrice = float("inf")
201
    prepaidBestOne = None
202
    prepaidBestSellerPoints = 0
203
    for similarItem in similarItems:
204
        if similarItem['_id'] == item['_id']:
205
            try:
206
                recomputePoints(item, similarItem)
207
            except:
208
                traceback.print_exc()
209
        if similarItem['codAvailable'] ==1:
210
            if mc.get("negative_deals") is None:
211
                populateNegativeDeals()
16181 kshitij.so 212
            if similarItem['in_stock'] == 0  or similarItem['_id'] in mc.get("negative_deals"):
16019 kshitij.so 213
                get_mongo_connection().Catalog.Deals.update({ '_id' : similarItem['_id'] }, {'$set':{'showDeal':0, 'prepaidDeal':0 }})
214
                continue
215
            if similarItem['source_id'] == SOURCE_MAP.get('SHOPCLUES.COM') and similarItem['rank']==0:
216
                get_mongo_connection().Catalog.Deals.update({ '_id' : similarItem['_id'] }, {'$set':{'showDeal':0,'prepaidDeal':0 }})
217
                continue
218
            if similarItem['available_price'] < bestPrice:
219
                bestOne = similarItem
220
                bestPrice = similarItem['available_price']
221
                bestSellerPoints = similarItem['bestSellerPoints']
222
            elif similarItem['available_price'] == bestPrice and bestSellerPoints < similarItem['bestSellerPoints']:
223
                bestOne = similarItem
224
                bestPrice = similarItem['available_price']
225
                bestSellerPoints = similarItem['bestSellerPoints']
226
            else:
227
                pass
228
        else:
229
            if mc.get("negative_deals") is None:
230
                populateNegativeDeals()
16181 kshitij.so 231
            if similarItem['in_stock'] == 0  or similarItem['_id'] in mc.get("negative_deals"):
16019 kshitij.so 232
                get_mongo_connection().Catalog.Deals.update({ '_id' : similarItem['_id'] }, {'$set':{'showDeal':0, 'prepaidDeal':0 }})
233
                continue
234
            if similarItem['source_id'] == SOURCE_MAP.get('SHOPCLUES.COM') and similarItem['rank']==0:
235
                get_mongo_connection().Catalog.Deals.update({ '_id' : similarItem['_id'] }, {'$set':{'showDeal':0,'prepaidDeal':0 }})
236
                continue
237
            if similarItem['available_price'] < prepaidBestPrice:
238
                prepaidBestOne = similarItem
239
                prepaidBestPrice = similarItem['available_price']
240
                prepaidBestSellerPoints = similarItem['bestSellerPoints']
241
            elif similarItem['available_price'] == prepaidBestPrice and prepaidBestSellerPoints < similarItem['bestSellerPoints']:
242
                prepaidBestOne = similarItem
243
                prepaidBestPrice = similarItem['available_price']
244
                prepaidBestSellerPoints = similarItem['bestSellerPoints']
245
            else:
246
                pass
16026 kshitij.so 247
    if bestOne is not None or prepaidBestOne is not None:
16019 kshitij.so 248
        for similarItem in similarItems:
249
            toUpdate.append(similarItem['_id'])
16026 kshitij.so 250
        if bestOne is not None:
251
            toUpdate.remove(bestOne['_id'])
252
            get_mongo_connection().Catalog.Deals.update({ '_id' : bestOne['_id'] }, {'$set':{'showDeal':1,'prepaidDeal':0 }})
253
        if prepaidBestOne is not None:
16076 kshitij.so 254
            if bestOne is not None:
255
                if prepaidBestOne['available_price'] < bestOne['available_price']: 
256
                    toUpdate.remove(prepaidBestOne['_id'])
257
                    get_mongo_connection().Catalog.Deals.update({ '_id' : prepaidBestOne['_id'] }, {'$set':{'showDeal':0,'prepaidDeal':1 }})
258
            else:
259
                toUpdate.remove(prepaidBestOne['_id'])
260
                get_mongo_connection().Catalog.Deals.update({ '_id' : prepaidBestOne['_id'] }, {'$set':{'showDeal':0,'prepaidDeal':1 }})
16019 kshitij.so 261
    if len(toUpdate) > 0:
262
        get_mongo_connection().Catalog.Deals.update({ '_id' : { "$in": toUpdate } }, {'$set':{'showDeal':0,'prepaidDeal':0 }},upsert=False, multi=True)
263
 
15869 kshitij.so 264
 
265
def bundleNewProduct(existingProduct, toBundle):
16095 kshitij.so 266
    global bundledProducts
267
    global exceptionList
15895 kshitij.so 268
    print "Adding new product"
269
    try:
270
        max_id = list(get_mongo_connection().Catalog.MasterData.find().sort([('_id',pymongo.DESCENDING)]).limit(1))
271
        existingProduct['_id'] = max_id[0]['_id'] + 1
272
        existingProduct['addedOn'] = to_java_date(datetime.now())
273
        existingProduct['available_price'] = toBundle.available_price
274
        existingProduct['updatedOn'] = to_java_date(datetime.now())
275
        existingProduct['codAvailable'] = toBundle.codAvailable
16095 kshitij.so 276
        existingProduct['coupon'] = str(toBundle.coupon)
277
        existingProduct['identifier'] = str(toBundle.identifier)
15895 kshitij.so 278
        existingProduct['in_stock'] = toBundle.in_stock
279
        existingProduct['marketPlaceUrl'] = toBundle.url
280
        existingProduct['rank'] = toBundle.rank
281
        existingProduct['source_product_name'] = toBundle.source_product_name
282
        existingProduct['url'] = toBundle.url
283
        get_mongo_connection().Catalog.MasterData.insert(existingProduct)
16095 kshitij.so 284
        newBundled = __NewBundled(toBundle, existingProduct)
285
        bundledProducts.append(newBundled)
15895 kshitij.so 286
        return {1:'Data added successfully.'}
287
    except Exception as e:
288
        print e
16095 kshitij.so 289
        exceptionList.append(toBundle)
15895 kshitij.so 290
        return {0:'Unable to add data.'}
15869 kshitij.so 291
 
16095 kshitij.so 292
def sendMail():
293
    message="""<html>
294
            <body>
295
            <h3>ShopClues Best Sellers Auto Bundled</h3>
296
            <table border="1" style="width:100%;">
297
            <thead>
298
            <tr>
299
            <th>Item Id</th>
300
            <th>Identifier</th>
301
            <th>Rank</th>
302
            <th>Product Name</th>
303
            <th>Bundle Id</th>
304
            <th>Bundled with Brand</th>
305
            <th>Bundled with Product Name</th>
306
            <th>Available_price</th>
307
            <th>In Stock</th>
308
            <th>Coupon</th>
309
            <th>COD Available</th>
310
            </tr></thead>
311
            <tbody>"""
312
    for bundledProduct in bundledProducts:
313
        newProduct = bundledProduct.newProduct
314
        oldProduct = bundledProduct.oldProduct
315
        message+="""<tr>
316
        <td style="text-align:center">"""+str(oldProduct.get('_id'))+"""</td>
317
        <td style="text-align:center">"""+oldProduct.get('identifier')+"""</td>
318
        <td style="text-align:center">"""+str(oldProduct.get('rank'))+"""</td>
319
        <td style="text-align:center">"""+(oldProduct.get('source_product_name'))+"""</td>
320
        <td style="text-align:center">"""+str(oldProduct.get('skuBundleId'))+"""</td>
321
        <td style="text-align:center">"""+(oldProduct.get('brand'))+"""</td>
322
        <td style="text-align:center">"""+(oldProduct.get('product_name'))+"""</td>
323
        <td style="text-align:center">"""+str(oldProduct.get('available_price'))+"""</td>
324
        <td style="text-align:center">"""+str(oldProduct.get('in_stock'))+"""</td>
325
        <td style="text-align:center">"""+str(oldProduct.get('coupon'))+"""</td>
326
        <td style="text-align:center">"""+str(oldProduct.get('codAvailable'))+"""</td>
327
        </tr>"""
328
    message+="""</tbody></table><h3>Items not bundled</h3><table border="1" style="width:100%;">
329
    <tr>
330
    <th>Identifier</th>
331
    <th>Rank</th>
332
    <th>Product Name</th>
333
    <th>Url</th>
334
    <th>Available Price</th>
335
    <th>In Stock</th>
336
    <th>COD Available</th>
337
    <th>Coupon</th>
16099 kshitij.so 338
    <th>Thumbnail</th>
16095 kshitij.so 339
    </tr></thead>
340
    <tbody>"""
341
    for exceptionItem in exceptionList:
342
        message+="""<tr>
343
        <td style="text-align:center">"""+str(exceptionItem.identifier)+"""</td>
344
        <td style="text-align:center">"""+str(exceptionItem.rank)+"""</td>
345
        <td style="text-align:center">"""+(exceptionItem.source_product_name)+"""</td>
346
        <td style="text-align:center">"""+(exceptionItem.url)+"""</td>
347
        <td style="text-align:center">"""+str(exceptionItem.available_price)+"""</td>
348
        <td style="text-align:center">"""+str(exceptionItem.in_stock)+"""</td>
349
        <td style="text-align:center">"""+str(exceptionItem.codAvailable)+"""</td>
350
        <td style="text-align:center">"""+str(exceptionItem.coupon)+"""</td>
16102 kshitij.so 351
        <td style="text-align:left">"""+(exceptionItem.thumbnail)+"""</td>
16095 kshitij.so 352
        </tr>"""
353
    message+="""</tbody></table></body></html>"""
354
    print message
16184 kshitij.so 355
    encoding = chardet.detect(message)
356
    try:
357
        message = message.decode(encoding.get('encoding'))
358
    except:
359
        pass
16182 kshitij.so 360
    #recipients = ['kshitij.sood@saholic.com']
361
    recipients = ['rajneesh.arora@saholic.com','kshitij.sood@saholic.com','chaitnaya.vats@saholic.com','manoj.kumar@saholic.com']
16095 kshitij.so 362
    msg = MIMEMultipart()
363
    msg['Subject'] = "Shopclues Best Sellers" + ' - ' + str(datetime.now())
364
    msg['From'] = ""
365
    msg['To'] = ",".join(recipients)
366
    msg.preamble = "Shopclues Best Sellers" + ' - ' + str(datetime.now())
367
    html_msg = MIMEText(message, 'html')
368
    msg.attach(html_msg)
369
 
370
    smtpServer = smtplib.SMTP('localhost')
371
    smtpServer.set_debuglevel(1)
372
    sender = 'dtr@shop2020.in'
373
    try:
374
        smtpServer.sendmail(sender, recipients, msg.as_string())
375
        print "Successfully sent email"
376
    except:
16101 kshitij.so 377
        traceback.print_exc()
16095 kshitij.so 378
        print "Error: unable to send email."
379
 
16183 kshitij.so 380
def resetRanks():
16103 kshitij.so 381
    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 382
 
15869 kshitij.so 383
def main():
16103 kshitij.so 384
    if options.reset == 'True':
385
        resetRanks()
15869 kshitij.so 386
    scrapeBestSellers()
16102 kshitij.so 387
    if len(bundledProducts)>0 or len(exceptionList) > 0:
388
        sendMail()
16190 kshitij.so 389
    else:
390
        "print nothing to send"
15869 kshitij.so 391
 
392
if __name__=='__main__':
393
    main()