<?xml version="1.0" encoding="utf-8"?> 
<rss version="2.0">

<channel>

<title>LEFT JOIN: blog on analytics, visualisation &amp; data science, posts tagged: web-crawling</title>
<link>https://en.leftjoin.ru/tags/web-crawling/</link>
<description></description>
<generator>E2 (v3386; Aegea)</generator>

<item>
<title>Collecting data from hypermarket receipts on Python</title>
<guid isPermaLink="false">6</guid>
<link>https://en.leftjoin.ru/all/collecting-receipts-with-python-p1/</link>
<comments>https://en.leftjoin.ru/all/collecting-receipts-with-python-p1/</comments>
<description>
&lt;p&gt;Recently, once again buying products in a hypermarket, I recalled that, according to the Russian Federal Act FZ-54, any trade operator, that issues a receipt, is obliged to send the data thereof to the Tax Service.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://en.leftjoin.ru/pictures/lenta-receipt@2x.jpg" width="787" height="762" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Receipt from “Lenta” hypermarket. The QR-code of our interest is circled.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;So, what does it mean for us, data analysts? It means that we can know ourselves and our needs better, and also acquire interesting data on own purchases.&lt;/p&gt;
&lt;p&gt;Let’s try to assemble a small prototype of an app that will allow to make a dynamic of our purchases within the framework of blog posts’ series. So, we’ll start from the fact, that each receipt has a QR-code, and if you identify it, you’ll receive the following line:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;i&gt;t=20190320T2303&amp;s=5803.00&amp;fn=9251440300007971&amp;i=141637&amp;fp=4087570038&amp;n=1&lt;/i&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This line comprises:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;i&gt;t&lt;/i&gt; – timestamp, the time when you made a purchase&lt;br /&gt;
&lt;i&gt;s&lt;/i&gt; – sum of the receipt&lt;br /&gt;
&lt;i&gt;fn&lt;/i&gt; – code number of fss, will be needed further in a request to API&lt;br /&gt;
&lt;i&gt;i&lt;/i&gt; – receipt number, will be needed further in a request to API&lt;br /&gt;
&lt;i&gt;fp&lt;/i&gt; – fiscalsign parameter, will be needed further in a request to API&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Within the solution of the first step, we will parse the receipt data and collect it in &lt;i&gt;pandas&lt;/i&gt; dataframe, using Python modules.&lt;/p&gt;
&lt;p&gt;We will use &lt;a href="https://habr.com/ru/post/358966/"&gt;API&lt;/a&gt;, that provides data on the receipt from the Tax Service website.&lt;/p&gt;
&lt;p&gt;Initially, we will receive authentication data:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code&gt;import requests
your_phone = '+7XXXYYYZZZZ' #you need to state your phone number, SMS with password will arrive thereon
r = requests.post('https://proverkacheka.nalog.ru:9999/v1/mobile/users/signup', json = {&amp;quot;email&amp;quot;:&amp;quot;email@email.com&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;USERNAME&amp;quot;,&amp;quot;phone&amp;quot;:your_phone})&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As a result of performing POST request we receive a password in SMS to the indicated phone number. Further on, we will be using it in a variable &lt;i&gt;&lt;b&gt;pwd&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;Now we’ll parse our line with values from QR-code:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code&gt;import re
qr_string='t=20190320T2303&amp;amp;s=5803.00&amp;amp;fn=9251440300007971&amp;amp;i=141637&amp;amp;fp=4087570038&amp;amp;n=1'
t=re.findall(r't=(\w+)', qr_string)[0]
s=re.findall(r's=(\w+)', qr_string)[0]
fn=re.findall(r'fn=(\w+)', qr_string)[0]
i=re.findall(r'i=(\w+)', qr_string)[0]
fp=re.findall(r'fp=(\w+)', qr_string)[0]&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We’ll use the variables obtained in order to extract the data.&lt;br /&gt;
One &lt;a href="https://habr.com/ru/post/358966/"&gt;Habr post&lt;/a&gt; pretty thoroughly examines status of errors at formation of API request, therefore I won’t repeat this information.&lt;/p&gt;
&lt;p&gt;In the beginning, we need to verify the presence of data on this receipt, so we form a GET request.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code&gt;headers = {'Device-Id':'', 'Device-OS':''}
payload = {'fiscalSign': fp, 'date': t,'sum':s}
check_request=requests.get('https://proverkacheka.nalog.ru:9999/v1/ofds/*/inns/*/fss/'+fn+'/operations/1/tickets/'+i,params=payload, headers=headers,auth=(your_phone, pwd))
print(check_request.status_code)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In the request one needs to indicate headers, at least empty ones. In my case, GET request returns error 406, thus I get that such receipt is found (why GET request returns 406 remains a mystery to me, so I will be glad to receive some clues in comments). If not indicating sum or date, GET request returns error 400 – bad request.&lt;/p&gt;
&lt;p&gt;Let’s move on to the most interesting part, receiving data of the receipt:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code&gt;request_info=requests.get('https://proverkacheka.nalog.ru:9999/v1/inns/*/kkts/*/fss/'+fn+'/tickets/'+i+'?fiscalSign='+fp+'&amp;amp;sendToEmail=no',headers=headers,auth=(your_phone, pwd))
print(request_info.status_code)
products=request_info.json()&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We should receive code 200 (successful execution of the request), and in the variable &lt;i&gt;products&lt;/i&gt; – everything, that applies to our receipt.&lt;/p&gt;
&lt;p&gt;In order to further work with this data, let’s use &lt;i&gt;pandas&lt;/i&gt; and transform everything in dataframe.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code&gt;import pandas as pd
from datetime import datetime
my_products=pd.DataFrame(products['document']['receipt']['items'])
my_products['price']=my_products['price']/100
my_products['sum']=my_products['sum']/100
datetime_check = datetime.strptime(t, '%Y%m%dT%H%M') #((https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior formate the date))
my_products['date']=datetime_check
my_products.set_index('date',inplace=True)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now we have working pandas.dataframe with receipts, visually it looks as follows:&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://en.leftjoin.ru/pictures/2019-03-22_17-14-33@2x.png" width="679" height="374" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;“Header” of receipt data&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You can construct a bar chart of purchases or observe everything as a box plot:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code&gt;import matplotlib.pyplot as plt
%matplotlib inline
my_products['sum'].plot(kind='hist', bins=20)
plt.show()
my_products['sum'].plot(kind='box')
plt.show()&lt;/code&gt;&lt;/pre&gt;&lt;div class="e2-text-picture"&gt;
&lt;img src="https://en.leftjoin.ru/pictures/hist_cheques.png" width="386" height="252" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;boxplot_cheques.png&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In conclusion, we will simply get descriptive statistics as text, using a command &lt;i&gt;.describe()&lt;/i&gt;:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code&gt;my_products.describe()&lt;/code&gt;&lt;/pre&gt;&lt;div class="e2-text-picture"&gt;
&lt;img src="https://en.leftjoin.ru/pictures/2019-03-22_17-27-06@2x.png" width="362" height="268" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;It’s convenient to write down data as .csv file, so that the next time you can amend the statistics:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code&gt;with open('hyper_receipts.csv', 'a') as f:
             my_products.to_csv(f, header=True)&lt;/code&gt;&lt;/pre&gt;</description>
<pubDate>Fri, 22 Mar 2019 17:41:37 +0300</pubDate>
</item>


</channel>
</rss>