Subversion Repositories SmartDukaan

Rev

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