Subversion Repositories SmartDukaan

Rev

Rev 16021 | Rev 16028 | 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")
21
 
22
(options, args) = parser.parse_args()
23
 
16019 kshitij.so 24
SOURCE_MAP = {'AMAZON':1,'FLIPKART':2,'SNAPDEAL':3,'SAHOLIC':4, 'SHOPCLUES.COM':5}
15869 kshitij.so 25
exceptionList = []
26
bestSellers = []
27
baseUrl = "http://m.shopclues.com/products/getProductList/mobiles:top-selling-mobiles-and-tablets.html/%s/page=%s"
15895 kshitij.so 28
headers = {
29
            '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',
30
            'Accept' : 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',      
31
            'Accept-Language' : 'en-US,en;q=0.8',                     
32
            'Accept-Charset' : 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
16019 kshitij.so 33
            'Connection':'keep-alive'
15895 kshitij.so 34
        }
15869 kshitij.so 35
now = datetime.now()
16019 kshitij.so 36
mc = MemCache(options.mongoHost)
15895 kshitij.so 37
sc = ShopCluesScraper.ShopCluesScraper()
15869 kshitij.so 38
 
39
 
40
class __ProductInfo:
41
 
42
    def __init__(self, identifier, rank, url, available_price, in_stock, codAvailable, source_product_name, thumbnail, coupon):
43
        self.identifier = identifier
44
        self.rank  = rank
45
        self.url = url
46
        self.available_price = available_price
47
        self.in_stock = in_stock
48
        self.codAvailable = codAvailable
49
        self.source_product_name = source_product_name
50
        self.thumbnail = thumbnail
51
        self.coupon = coupon 
52
 
53
def get_mongo_connection(host=options.mongoHost, port=27017):
54
    global con
55
    if con is None:
56
        print "Establishing connection %s host and port %d" %(host,port)
57
        try:
58
            con = pymongo.MongoClient(host, port)
59
        except Exception, e:
60
            print e
61
            return None
62
    return con
63
 
64
def getSoupObject(url):
65
    print "Getting soup object for"
66
    print url
67
    global RETRY_COUNT
68
    RETRY_COUNT = 1 
69
    while RETRY_COUNT < 10:
70
        try:
71
            soup = None
16019 kshitij.so 72
            request = urllib2.Request(url, headers=headers)
15869 kshitij.so 73
            response = urllib2.urlopen(request)   
74
            response_data = response.read()
75
            response.close()
76
            try:
77
                page=response_data.decode("utf-8")
78
                soup = BeautifulSoup(page,convertEntities=BeautifulSoup.HTML_ENTITIES)
79
            except:
16019 kshitij.so 80
                print traceback.print_exc()
15869 kshitij.so 81
                soup = BeautifulSoup(response_data,convertEntities=BeautifulSoup.HTML_ENTITIES)
82
            if soup is None:
83
                raise
84
            return soup
85
        except Exception as e:
16019 kshitij.so 86
            traceback.print_exc()
15869 kshitij.so 87
            print "Retrying"
88
            RETRY_COUNT = RETRY_COUNT + 1
89
 
90
 
91
def scrapeBestSellers():
92
    global bestSellers
93
    bestSellers = []
94
    rank = 0
95
    page = 1
96
    while (True):
97
        url = (baseUrl)%(page,page-1)
98
        soup = getSoupObject(url)
99
        productDivs = soup.findAll('div',{'class':'pd-list-cont'})
100
        if productDivs is None or len(productDivs)==0:
101
            return
102
        for productDiv in productDivs:
103
            rank = rank + 1
104
            info_tag =  productDiv.find('a')
105
            link = info_tag['href']
106
            scin = info_tag['data-id'].strip()
107
            print link
108
            print scin
15895 kshitij.so 109
            productName = productDiv.find('div',{'class':'pdt-name'}).string
110
            try:
111
                productInfo = sc.read(link)
112
            except Exception as e:
113
                traceback.print_exc()
114
                continue
15869 kshitij.so 115
            product = list(get_mongo_connection().Catalog.MasterData.find({'source_id':5,'identifier':scin}))
116
            if len(product) > 0:
16019 kshitij.so 117
                if productInfo['inStock'] ==1:
118
                    get_mongo_connection().Catalog.MasterData.update({'_id':product[0]['_id']},{"$set":{'rank':rank, 'available_price':productInfo['price'], \
15895 kshitij.so 119
                                                                                                            'in_stock':productInfo['inStock'], 'codAvailable':productInfo['isCod'], \
16021 kshitij.so 120
                                                                                                            'coupon':productInfo['coupon'], 'updatedOn':to_java_date(datetime.now()),'priceUpdatedOn':to_java_date(datetime.now())}})
16019 kshitij.so 121
                    get_mongo_connection().Catalog.Deals.update({'_id':product[0]['_id']}, {'$set' : {'available_price':productInfo['price'] , 'in_stock':productInfo['inStock'],'codAvailable':productInfo['isCod']}})
122
                else:
123
                    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())}})
124
                    get_mongo_connection().Catalog.Deals.update({'_id':product[0]['_id']}, {'$set' : {'in_stock':0}})
125
 
126
                try:
127
                    recomputeDeal(product[0])
128
                except:
129
                    print "Unable to compute deal for %s"%(product[0]['skuBundleId'])
130
 
15869 kshitij.so 131
            else:
132
                #Lets bundle product by finding similar url pattern
15895 kshitij.so 133
                uri = link.replace('http://m.shopclues.com','').replace(".html","")
134
                try:
135
                    int(uri[uri.rfind('-')+1:])
136
                    uri =  uri[:uri.rfind('-')]
137
                except:
138
                    pass
139
                product = list(get_mongo_connection().Catalog.MasterData.find({'source_id':5,'marketPlaceUrl':{'$regex': uri}}))
140
                toBundle = __ProductInfo(scin, rank, link, productInfo['price'], productInfo['inStock'],productInfo['isCod'], productName, "" ,productInfo['coupon'])
15869 kshitij.so 141
                if len(product) > 0:
15895 kshitij.so 142
                    bundleNewProduct(product[0], toBundle)
143
                else:
144
                    exceptionList.append(toBundle)
15869 kshitij.so 145
        page = page+1
16019 kshitij.so 146
 
147
def populateNegativeDeals():
148
    negativeDeals = get_mongo_connection().Catalog.NegativeDeals.find().distinct('sku')
149
    mc.set("negative_deals", negativeDeals, 600)
150
 
151
def recomputePoints(item, deal):
152
    try:
153
        nlcPoints = getNlcPoints(item, deal['minNlc'], deal['maxNlc'], deal['available_price'])
154
    except:
155
        traceback.print_exc()
156
        nlcPoints = deal['nlcPoints']
157
    if item['manualDealThresholdPrice'] >= deal['available_price']:
158
        dealPoints = item['dealPoints']
159
    else:
160
        dealPoints = 0
161
    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']}})
162
 
163
 
164
def recomputeDeal(item):
165
    """Lets recompute deal for this bundle"""
166
    print "Recomputing for bundleId %d" %(item.get('skuBundleId'))
167
    skuBundleId = item['skuBundleId']
16026 kshitij.so 168
    item['dealFlag'] = 0
169
    item['dealType'] = 0
170
    item['dealPoints'] = 0
171
    item['manualDealThresholdPrice'] = None
172
    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']}))
173
    if len(manualDeals) > 0:
174
        item['dealFlag'] = 1
175
        item['dealType'] =manualDeals[0]['dealType']
176
        item['dealPoints'] = manualDeals[0]['dealPoints']
177
        item['manualDealThresholdPrice'] = manualDeals[0]['dealThresholdPrice']
16019 kshitij.so 178
    similarItems = list(get_mongo_connection().Catalog.Deals.find({'skuBundleId':skuBundleId}).sort([('available_price',pymongo.ASCENDING)]))
179
    bestPrice = float("inf")
180
    bestOne = None
181
    bestSellerPoints = 0
182
    toUpdate = []
183
    prepaidBestPrice = float("inf")
184
    prepaidBestOne = None
185
    prepaidBestSellerPoints = 0
186
    for similarItem in similarItems:
187
        if similarItem['_id'] == item['_id']:
188
            try:
189
                recomputePoints(item, similarItem)
190
            except:
191
                traceback.print_exc()
192
        if similarItem['codAvailable'] ==1:
193
            if mc.get("negative_deals") is None:
194
                populateNegativeDeals()
195
            if similarItem['in_stock'] == 0 or similarItem['maxprice'] is None or similarItem['maxprice'] < similarItem['available_price'] or similarItem['_id'] in mc.get("negative_deals"):
196
                get_mongo_connection().Catalog.Deals.update({ '_id' : similarItem['_id'] }, {'$set':{'showDeal':0, 'prepaidDeal':0 }})
197
                continue
198
            if similarItem['source_id'] == SOURCE_MAP.get('SHOPCLUES.COM') and similarItem['rank']==0:
199
                get_mongo_connection().Catalog.Deals.update({ '_id' : similarItem['_id'] }, {'$set':{'showDeal':0,'prepaidDeal':0 }})
200
                continue
201
            if similarItem['available_price'] < bestPrice:
202
                bestOne = similarItem
203
                bestPrice = similarItem['available_price']
204
                bestSellerPoints = similarItem['bestSellerPoints']
205
            elif similarItem['available_price'] == bestPrice and bestSellerPoints < similarItem['bestSellerPoints']:
206
                bestOne = similarItem
207
                bestPrice = similarItem['available_price']
208
                bestSellerPoints = similarItem['bestSellerPoints']
209
            else:
210
                pass
211
        else:
212
            if mc.get("negative_deals") is None:
213
                populateNegativeDeals()
214
            if similarItem['in_stock'] == 0 or similarItem['maxprice'] is None or similarItem['maxprice'] < similarItem['available_price'] or similarItem['_id'] in mc.get("negative_deals"):
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'] < prepaidBestPrice:
221
                prepaidBestOne = similarItem
222
                prepaidBestPrice = similarItem['available_price']
223
                prepaidBestSellerPoints = similarItem['bestSellerPoints']
224
            elif similarItem['available_price'] == prepaidBestPrice and prepaidBestSellerPoints < similarItem['bestSellerPoints']:
225
                prepaidBestOne = similarItem
226
                prepaidBestPrice = similarItem['available_price']
227
                prepaidBestSellerPoints = similarItem['bestSellerPoints']
228
            else:
229
                pass
16026 kshitij.so 230
    if bestOne is not None or prepaidBestOne is not None:
16019 kshitij.so 231
        for similarItem in similarItems:
232
            toUpdate.append(similarItem['_id'])
16026 kshitij.so 233
        if bestOne is not None:
234
            toUpdate.remove(bestOne['_id'])
235
            get_mongo_connection().Catalog.Deals.update({ '_id' : bestOne['_id'] }, {'$set':{'showDeal':1,'prepaidDeal':0 }})
236
        if prepaidBestOne is not None:
237
            toUpdate.remove(prepaidBestOne['_id'])
238
            get_mongo_connection().Catalog.Deals.update({ '_id' : prepaidBestOne['_id'] }, {'$set':{'showDeal':0,'prepaidDeal':1 }})
16019 kshitij.so 239
    if len(toUpdate) > 0:
240
        get_mongo_connection().Catalog.Deals.update({ '_id' : { "$in": toUpdate } }, {'$set':{'showDeal':0,'prepaidDeal':0 }},upsert=False, multi=True)
241
 
15869 kshitij.so 242
 
243
def bundleNewProduct(existingProduct, toBundle):
15895 kshitij.so 244
    print "Adding new product"
245
    try:
246
        max_id = list(get_mongo_connection().Catalog.MasterData.find().sort([('_id',pymongo.DESCENDING)]).limit(1))
247
        existingProduct['_id'] = max_id[0]['_id'] + 1
248
        existingProduct['addedOn'] = to_java_date(datetime.now())
249
        existingProduct['available_price'] = toBundle.available_price
250
        existingProduct['updatedOn'] = to_java_date(datetime.now())
251
        existingProduct['codAvailable'] = toBundle.codAvailable
252
        existingProduct['coupon'] = toBundle.coupon
253
        existingProduct['identifier'] = toBundle.identifier
254
        existingProduct['in_stock'] = toBundle.in_stock
255
        existingProduct['marketPlaceUrl'] = toBundle.url
256
        existingProduct['rank'] = toBundle.rank
257
        existingProduct['source_product_name'] = toBundle.source_product_name
258
        existingProduct['url'] = toBundle.url
259
        get_mongo_connection().Catalog.MasterData.insert(existingProduct)
260
        return {1:'Data added successfully.'}
261
    except Exception as e:
262
        print e
263
        return {0:'Unable to add data.'}
15869 kshitij.so 264
 
15895 kshitij.so 265
def exceptionItems():
266
    for item in exceptionList:
267
        print vars(item)
268
 
269
 
15869 kshitij.so 270
def main():
271
    scrapeBestSellers()
15895 kshitij.so 272
    exceptionItems()
15869 kshitij.so 273
 
274
if __name__=='__main__':
275
    main()