Subversion Repositories SmartDukaan

Rev

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