Subversion Repositories SmartDukaan

Rev

Rev 13576 | Rev 13603 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
13569 amit.gupta 1
'''
2
Created on Jan 15, 2015
3
 
4
@author: amit
5
'''
13576 amit.gupta 6
from BeautifulSoup import BeautifulSoup
13569 amit.gupta 7
from bson.binary import Binary
8
from dtr import main
13576 amit.gupta 9
from dtr.dao import AffiliateInfo, Order, SubOrder
13569 amit.gupta 10
from dtr.main import getBrowserObject, ScrapeException, getStore, ParseException
11
from pymongo import MongoClient
12
import datetime
13
import json
14
import pymongo
15
import re
16
import urllib
13576 amit.gupta 17
from pprint import pprint
13569 amit.gupta 18
USERNAME='saholic1@gmail.com'
19
PASSWORD='spice@2020'
20
AFFILIATE_URL='http://affiliate.snapdeal.com'
21
POST_URL='https://api-p03.hasoffers.com/v3/Affiliate_Report.json'
22
ORDER_TRACK_URL='https://m.snapdeal.com/orderSummary'
23
CONFIG_URL='http://affiliate.snapdeal.com/publisher/js/config.php'
24
 
25
 
26
class Store(main.Store):
27
 
28
    '''
29
    This is to map order statuses of our system to order statuses of snapdeal.
30
    And our statuses will change accordingly.
31
 
32
    '''
33
    OrderStatusMap = {
34
                      main.Store.ORDER_PLACED : ['In Progress','N/A'],
35
                      main.Store.ORDER_DELIVERED : ['Delivered'],
36
                      main.Store.ORDER_SHIPPED : ['In Transit'],
37
                      main.Store.ORDER_CANCELLED : ['Closed For Vendor Reallocation']
38
 
39
                      }
40
    def __init__(self,store_id):
13576 amit.gupta 41
        client = MongoClient('mongodb://localhost:27017/')
13582 amit.gupta 42
        self.db = client.Dtr
13569 amit.gupta 43
        super(Store, self).__init__(store_id)
44
 
45
    def getName(self):
46
        return "snapdeal"
47
 
48
    def scrapeAffiliate(self, startDate=None, endDate=None):
49
        br = getBrowserObject()
50
        br.open(AFFILIATE_URL)
51
        br.select_form(nr=0)
52
        br.form['data[User][password]'] = PASSWORD 
53
        br.form['data[User][email]'] = USERNAME
54
        br.submit()
55
        response = br.open(CONFIG_URL)
56
 
57
        token =  re.findall('"session_token":"(.*?)"', ungzipResponse(response, br), re.IGNORECASE)[0]
58
 
59
        allOffers = self._getAllOffers(br, token)
60
 
61
        allPyOffers = [self.covertToObj(offer).__dict__ for offer in allOffers]
62
        self._saveToAffiliate(allPyOffers)
63
 
64
 
13576 amit.gupta 65
    def parseOrderRawHtml(self, orderId, subTagId, userId, rawHtml, orderSuccessUrl):
13582 amit.gupta 66
        try:
67
            br = getBrowserObject()
68
            url = ORDER_TRACK_URL + re.findall('.*(\?.*?)$', orderSuccessUrl,re.IGNORECASE)[0]
69
            response = br.open(url)
70
            page = ungzipResponse(response, br)
71
            #page=page.decode("utf-8")
72
            soup = BeautifulSoup(page,convertEntities=BeautifulSoup.HTML_ENTITIES)
73
            #orderHead = soup.find(name, attrs, recursive, text)
74
            sections = soup.findAll("section")
75
 
76
            #print sections
77
 
78
            order = sections[1]
79
            orderTrs = order.findAll("tr")
80
 
81
            placedOn = str(orderTrs[0].findAll("td")[1].text)
82
 
83
            #Pop two section elements
84
            sections.pop(0) 
85
            sections.pop(0)
86
            subOrders = sections
87
 
88
 
89
            merchantSubOrders = []
90
 
91
            merchantOrder = Order(orderId, userId, subTagId, self.store_id, orderSuccessUrl)
92
            merchantOrder.merchantOderId = re.findall(r'\d+', str(soup.find("div", {"class":"deals_heading"})))[1]
93
            for orderTr in orderTrs:
94
                orderTrString = str(orderTr)
95
                if "Total Amount" in orderTrString:
96
                    merchantOrder.totalAmount = re.findall(r'\d+', orderTrString)[0]
97
                elif "Delivery Charges" in orderTrString:
98
                    merchantOrder.deliveryCharges = re.findall(r'\d+', orderTrString)[0]
99
                elif "Discount Applied" in orderTrString:
100
                    merchantOrder.discountApplied = re.findall(r'\d+', orderTrString)[0]
101
                elif "Paid Amount" in orderTrString:
102
                    merchantOrder.paidAmount = re.findall(r'\d+', orderTrString)[0]
103
 
104
            for subOrderElement in subOrders:
105
                productUrl = str(subOrderElement.find("a")['href'])
106
                subTable = subOrderElement.find("table", {"class":"lrPad"})
107
                subTrs = subTable.findAll("tr")
108
                unitPrice=None
109
                offerDiscount = None
110
                deliveryCharges = None
111
                amountPaid = None
112
                for subTr in subTrs:
113
                    subTrString = str(subTr)
114
                    if "Unit Price" in subTrString:
115
                        unitPrice = re.findall(r'\d+', subTrString)[0]
116
                    if "Quantity" in subTrString:
117
                        qty = re.findall(r'\d+', subTrString)[0]
118
                    elif "Offer Discount" in subTrString:
119
                        offerDiscount =   re.findall(r'\d+', subTrString)[0]
120
                    elif "Delivery Charges" in subTrString:
121
                        deliveryCharges =   re.findall(r'\d+', subTrString)[0]
122
                    elif "Subtotal" in subTrString:
123
                        amountPaid =   str(int(re.findall(r'\d+', subTrString)[0])/int(qty))
124
 
125
                divs = subOrderElement.findAll("div", {"class": "blk lrPad subordrs"})
126
                if len(divs)<=0:
127
                    raise ParseException("subOrder", "Could not Parse suborders for Snapdeal")
128
 
129
                for div in divs:
130
                    productTitle = str(subOrderElement.find("a").text)
131
                    productUrl = "http://m.snapdeal.com/" + productUrl 
132
                    subOrder = SubOrder(productTitle, productUrl, placedOn, amountPaid)
133
 
134
                    subOrder.amountPaid = amountPaid
135
                    subOrder.deliveryCharges = deliveryCharges
136
                    subOrder.offerDiscount = offerDiscount
137
                    subOrder.unitPrice = unitPrice
138
                    subOrder.productCode = re.findall(r'\d+$', productUrl)[0]
13569 amit.gupta 139
 
13582 amit.gupta 140
                    trackAnchor = div.find("a")   
141
                    if trackAnchor is not None:
142
                        subOrder.tracingkUrl = str(trackAnchor['href'])
143
 
144
                    divStr = str(div)
145
                    divStr = divStr.replace("\n","").replace("\t", "")
146
 
147
                    for line in divStr.split("<br />"):
148
                        if "Suborder ID" in line:
149
                            subOrder.merchantSubOrderId = re.findall(r'\d+', line)[0]   
150
                        elif "Status" in line:
151
                            subOrder.detailedStatus = re.findall('>(.*?)</span>', line, re.IGNORECASE)[0]
152
                        elif "Est. Shipping Date" in line:
153
                            subOrder.estimatedShippingDate = line.split(":")[1].strip()
154
                        elif "Est. Delivery Date" in line:
155
                            subOrder.estimatedDeliveryDate = line.split(":")[1].strip()
156
                        elif "Courier Name" in line:
157
                            subOrder.courierName = line.split(":")[1].strip()
158
                        elif "Tracking No" in line:
159
                            subOrder.trackingNumber = line.split(":")[1].strip()
160
 
161
                merchantSubOrders.append(subOrder)   
13569 amit.gupta 162
 
13582 amit.gupta 163
            merchantOrder.subOrders = merchantSubOrders
164
            #print merchantOrder
165
 
166
            self._saveToOrder(todict(merchantOrder))
167
            return True
168
        except:
169
            print "Error occurred"
13569 amit.gupta 170
 
13582 amit.gupta 171
        return False
13569 amit.gupta 172
        #soup = BeautifulSoup(rawHtml,convertEntities=BeautifulSoup.HTML_ENTITIES)
173
        #soup.find(name, attrs, recursive, text)
174
 
13576 amit.gupta 175
 
176
 
177
    def _getStatusFromDetailedStatus(self, detailedStatus):
178
        for key, value in Store.OrderStatusMap.iteritems():
179
            if detailedStatus in value:
180
                return key
181
        raise ParseException("_getStatusFromDetailedStatus", "Found new order status" + detailedStatus)
13569 amit.gupta 182
 
183
    def scrapeStoreOrders(self,):
13576 amit.gupta 184
        orders = self._getActiveOrders()
185
        br = getBrowserObject()
186
        for order in orders:
187
            url = ORDER_TRACK_URL + re.findall('.*(\?.*?)$', order['orderSuccessUrl'],re.IGNORECASE)[0]
188
            response = br.open(url)
189
            page = ungzipResponse(response, br)
190
            #page=page.decode("utf-8")
191
            soup = BeautifulSoup(page,convertEntities=BeautifulSoup.HTML_ENTITIES)
192
            sections = soup.findAll("section")
193
            sections.pop(0)
194
            sections.pop(0)
195
 
196
            subOrders = sections
197
            bulk = self.db.merchantOrder.initialize_ordered_bulk_op()
198
            for subOrderElement in subOrders:
199
                closed = True
200
                divs = subOrderElement.findAll("div", {"class": "blk lrPad subordrs"})
201
                if len(divs)<=0:
202
                    raise ParseException("subOrder", "Could not Parse suborders for Snapdeal")
203
 
204
                for div in divs:
205
                    trackAnchor = div.find("a")   
206
                    if trackAnchor is not None:
207
                        tracingkUrl = str(trackAnchor['href'])
208
 
209
                    divStr = str(div)
210
                    divStr = divStr.replace("\n","").replace("\t", "")
211
                    updateMap = {}
212
                    for line in divStr.split("<br />"):
213
                        if "Suborder ID" in line:
214
                            merchantSubOrderId = re.findall(r'\d+', line)[0]   
215
                            findMap = {"id": order['id'], "subOrders.merchantSubOrderId": merchantSubOrderId}
216
                        elif "Status" in line:
217
                            detailedStatus = re.findall('>(.*?)</span>', line, re.IGNORECASE)[0]
218
                            detailedStatus = re.findall('>(.*?)</span>', line, re.IGNORECASE)[0]
219
                            updateMap["subOrders.$.detailedStatus"] = detailedStatus
220
                            status = self._getStatusFromDetailedStatus(detailedStatus) 
221
                            if closed:
222
                                closed = status in [Store.ORDER_PLACED, Store.ORDER_CANCELLED]
223
                        elif "Est. Shipping Date" in line:
224
                            estimatedShippingDate = line.split(":")[1].strip()
225
                            updateMap["subOrders.$.estimatedShippingDate"] = estimatedShippingDate
226
                        elif "Est. Delivery Date" in line:
227
                            estimatedDeliveryDate = line.split(":")[1].strip()
228
                            updateMap["subOrders.$.estimatedDeliveryDate"] = estimatedDeliveryDate
229
                        elif "Courier Name" in line:
230
                            courierName = line.split(":")[1].strip()
231
                            updateMap["subOrders.$.courierName"] = courierName
232
                        elif "Tracking No" in line:
233
                            trackingNumber = line.split(":")[1].strip()
234
                            updateMap["subOrders.$.trackingNumber"] = trackingNumber
235
 
236
                    updateMap["subOrders.$.closed"] = closed
237
                    bulk.find(findMap).update({'$set' : updateMap})
238
            result = bulk.execute()
239
            pprint(result)        
240
 
13569 amit.gupta 241
    """
242
    This will insert records with changes only 
243
    """
13576 amit.gupta 244
 
245
    def _getActiveOrders(self):
246
        collection = self.db.merchantOrder
247
        stores = collection.find({"closed": False, "storeId" : self.store_id}, {"orderSuccessUrl":1, "id":1})
248
        return [store for store in stores]
249
 
250
 
251
 
13569 amit.gupta 252
    def _saveToAffiliate(self, offers):
13576 amit.gupta 253
        collection = self.db.snapdealOrderAffiliateInfo
13569 amit.gupta 254
        try:
255
            collection.insert(offers,continue_on_error=True)
256
        except pymongo.errors.DuplicateKeyError as e:
257
            print e.details
258
 
13576 amit.gupta 259
    def _saveToOrder(self, order):
260
        collection = self.db.merchantOrder
261
        try:
262
            order = collection.insert(order)
263
            #merchantOder 
264
        except Exception as e:
265
            print todict(e)
13569 amit.gupta 266
 
267
    def _getAllOffers(self, br, token):
268
        allOffers = []
269
        nextPage = 1  
270
        while True:
271
            data = getPostData(token, nextPage)
272
            response = br.open(POST_URL, data)
273
            rmap = json.loads(ungzipResponse(response, br))
274
            if rmap is not None:
275
                rmap = rmap['response']
276
                if rmap is not None and len(rmap['errors'])==0:
277
                    allOffers += rmap['data']['data']
278
                    print allOffers
279
            nextPage += 1
280
            if rmap['data']['pageCount']<nextPage:
281
                break
282
 
283
        return allOffers
284
 
285
    def covertToObj(self,offer):
286
        offerData = offer['Stat']
287
        offer1 = AffiliateInfo(offerData['affiliate_info1'], self.store_id, offerData['conversion_status'], offerData['ad_id'], 
288
                              offerData['datetime'], offerData['payout'], offer['Offer']['name'], offerData['ip'], offerData['conversion_sale_amount'])
289
        return offer1
290
def getPostData(token, page = 1, limit= 20, startDate=None, endDate=None):
291
    endDate=datetime.date.today() + datetime.timedelta(days=1)
292
    startDate=endDate - datetime.timedelta(days=31)
293
 
294
    parameters = (
295
        ("page",str(page)),
296
        ("limit",str(limit)),
297
        ("fields[]","Stat.offer_id"),
298
        ("fields[]","Stat.datetime"),
299
        ("fields[]","Offer.name"),
300
        ("fields[]","Stat.conversion_status"),
301
        ("fields[]","Stat.conversion_sale_amount"),
302
        ("fields[]","Stat.payout"),
303
        ("fields[]","Stat.ip"),
304
        ("fields[]","Stat.ad_id"),
305
        ("fields[]","Stat.affiliate_info1"),
306
        ("sort[Stat.datetime]","desc"),
307
        ("filters[Stat.date][conditional]","BETWEEN"),
308
        ("filters[Stat.date][values][]",startDate.strftime('%Y-%m-%d')),
309
        ("filters[Stat.date][values][]",endDate.strftime('%Y-%m-%d')),
310
        ("data_start",startDate.strftime('%Y-%m-%d')),
311
        ("data_end",endDate.strftime('%Y-%m-%d')),
312
        ("Method","getConversions"),
313
        ("NetworkId","jasper"),
314
        ("SessionToken",token),
315
    )
316
    #Encode the parameters
317
    return urllib.urlencode(parameters)
318
 
319
def main():
320
    store = getStore(3)
13576 amit.gupta 321
    store.scrapeStoreOrders()
13569 amit.gupta 322
    #store.scrapeAffiliate()
323
    #with open ("data.txt", "r") as myfile:
324
    #    data=myfile.read()
325
    #    myfile.close()
326
 
13576 amit.gupta 327
    #store.parseOrderRawHtml(12345, "subtagId", 122323,  "html", 'https://m.snapdeal.com/purchaseMobileComplete?code=1f4166d13ea799b65aa9dea68b3e9e70&order=4509499363')
13569 amit.gupta 328
 
329
def ungzipResponse(r,b):
330
    headers = r.info()
331
    if headers['Content-Encoding']=='gzip':
332
        import gzip
333
        print "********************"
334
        print "Deflating gzip response"
335
        print "********************"
336
        gz = gzip.GzipFile(fileobj=r, mode='rb')
337
        html = gz.read()
338
        gz.close()
339
        return html
340
 
341
if __name__ == '__main__':
342
    main()
13576 amit.gupta 343
 
344
def todict(obj, classkey=None):
345
    if isinstance(obj, dict):
346
        data = {}
347
        for (k, v) in obj.items():
348
            data[k] = todict(v, classkey)
349
        return data
350
    elif hasattr(obj, "_ast"):
351
        return todict(obj._ast())
352
    elif hasattr(obj, "__iter__"):
353
        return [todict(v, classkey) for v in obj]
354
    elif hasattr(obj, "__dict__"):
355
        data = dict([(key, todict(value, classkey)) 
356
            for key, value in obj.__dict__.iteritems() 
357
            if not callable(value) and not key.startswith('_')])
358
        if classkey is not None and hasattr(obj, "__class__"):
359
            data[classkey] = obj.__class__.__name__
360
        return data
361
    else:
362
        return obj