Subversion Repositories SmartDukaan

Rev

Rev 16019 | Rev 16026 | 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']
168
 
169
    similarItems = list(get_mongo_connection().Catalog.Deals.find({'skuBundleId':skuBundleId}).sort([('available_price',pymongo.ASCENDING)]))
170
    bestPrice = float("inf")
171
    bestOne = None
172
    bestSellerPoints = 0
173
    toUpdate = []
174
    prepaidBestPrice = float("inf")
175
    prepaidBestOne = None
176
    prepaidBestSellerPoints = 0
177
    for similarItem in similarItems:
178
        if similarItem['_id'] == item['_id']:
179
            try:
180
                recomputePoints(item, similarItem)
181
            except:
182
                traceback.print_exc()
183
        if similarItem['codAvailable'] ==1:
184
            if mc.get("negative_deals") is None:
185
                populateNegativeDeals()
186
            if similarItem['in_stock'] == 0 or similarItem['maxprice'] is None or similarItem['maxprice'] < similarItem['available_price'] or similarItem['_id'] in mc.get("negative_deals"):
187
                get_mongo_connection().Catalog.Deals.update({ '_id' : similarItem['_id'] }, {'$set':{'showDeal':0, 'prepaidDeal':0 }})
188
                continue
189
            if similarItem['source_id'] == SOURCE_MAP.get('SHOPCLUES.COM') and similarItem['rank']==0:
190
                get_mongo_connection().Catalog.Deals.update({ '_id' : similarItem['_id'] }, {'$set':{'showDeal':0,'prepaidDeal':0 }})
191
                continue
192
            if similarItem['available_price'] < bestPrice:
193
                bestOne = similarItem
194
                bestPrice = similarItem['available_price']
195
                bestSellerPoints = similarItem['bestSellerPoints']
196
            elif similarItem['available_price'] == bestPrice and bestSellerPoints < similarItem['bestSellerPoints']:
197
                bestOne = similarItem
198
                bestPrice = similarItem['available_price']
199
                bestSellerPoints = similarItem['bestSellerPoints']
200
            else:
201
                pass
202
        else:
203
            if mc.get("negative_deals") is None:
204
                populateNegativeDeals()
205
            if similarItem['in_stock'] == 0 or similarItem['maxprice'] is None or similarItem['maxprice'] < similarItem['available_price'] or similarItem['_id'] in mc.get("negative_deals"):
206
                get_mongo_connection().Catalog.Deals.update({ '_id' : similarItem['_id'] }, {'$set':{'showDeal':0, 'prepaidDeal':0 }})
207
                continue
208
            if similarItem['source_id'] == SOURCE_MAP.get('SHOPCLUES.COM') and similarItem['rank']==0:
209
                get_mongo_connection().Catalog.Deals.update({ '_id' : similarItem['_id'] }, {'$set':{'showDeal':0,'prepaidDeal':0 }})
210
                continue
211
            if similarItem['available_price'] < prepaidBestPrice:
212
                prepaidBestOne = similarItem
213
                prepaidBestPrice = similarItem['available_price']
214
                prepaidBestSellerPoints = similarItem['bestSellerPoints']
215
            elif similarItem['available_price'] == prepaidBestPrice and prepaidBestSellerPoints < similarItem['bestSellerPoints']:
216
                prepaidBestOne = similarItem
217
                prepaidBestPrice = similarItem['available_price']
218
                prepaidBestSellerPoints = similarItem['bestSellerPoints']
219
            else:
220
                pass
221
    if bestOne is not None and prepaidBestOne is not None:
222
        for similarItem in similarItems:
223
            toUpdate.append(similarItem['_id'])
224
        toUpdate.remove(bestOne['_id'])
225
        toUpdate.remove(prepaidBestOne['_id'])
226
        get_mongo_connection().Catalog.Deals.update({ '_id' : bestOne['_id'] }, {'$set':{'showDeal':1,'prepaidDeal':0 }})
227
        get_mongo_connection().Catalog.Deals.update({ '_id' : prepaidBestOne['_id'] }, {'$set':{'showDeal':0,'prepaidDeal':1 }})
228
    if len(toUpdate) > 0:
229
        get_mongo_connection().Catalog.Deals.update({ '_id' : { "$in": toUpdate } }, {'$set':{'showDeal':0,'prepaidDeal':0 }},upsert=False, multi=True)
230
 
15869 kshitij.so 231
 
232
def bundleNewProduct(existingProduct, toBundle):
15895 kshitij.so 233
    print "Adding new product"
234
    try:
235
        max_id = list(get_mongo_connection().Catalog.MasterData.find().sort([('_id',pymongo.DESCENDING)]).limit(1))
236
        existingProduct['_id'] = max_id[0]['_id'] + 1
237
        existingProduct['addedOn'] = to_java_date(datetime.now())
238
        existingProduct['available_price'] = toBundle.available_price
239
        existingProduct['updatedOn'] = to_java_date(datetime.now())
240
        existingProduct['codAvailable'] = toBundle.codAvailable
241
        existingProduct['coupon'] = toBundle.coupon
242
        existingProduct['identifier'] = toBundle.identifier
243
        existingProduct['in_stock'] = toBundle.in_stock
244
        existingProduct['marketPlaceUrl'] = toBundle.url
245
        existingProduct['rank'] = toBundle.rank
246
        existingProduct['source_product_name'] = toBundle.source_product_name
247
        existingProduct['url'] = toBundle.url
248
        get_mongo_connection().Catalog.MasterData.insert(existingProduct)
249
        return {1:'Data added successfully.'}
250
    except Exception as e:
251
        print e
252
        return {0:'Unable to add data.'}
15869 kshitij.so 253
 
15895 kshitij.so 254
def exceptionItems():
255
    for item in exceptionList:
256
        print vars(item)
257
 
258
 
15869 kshitij.so 259
def main():
260
    scrapeBestSellers()
15895 kshitij.so 261
    exceptionItems()
15869 kshitij.so 262
 
263
if __name__=='__main__':
264
    main()