<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.2.0">Jekyll</generator><link href="https://webscraping.com/rss.xml" rel="self" type="application/atom+xml" /><link href="https://webscraping.com/" rel="alternate" type="text/html" /><updated>2023-12-22T04:48:34+00:00</updated><id>https://webscraping.com/rss.xml</id><title type="html">WebScraping.com</title><subtitle>Scrape the web's information and make it accessible and useful.</subtitle><author><name>WebScraping.com</name><email>contact@webscraping.com</email></author><entry><title type="html">How to intercept secure network traffic from Android</title><link href="https://webscraping.com/blog/how-to-intercept-secure-network-traffic-from-android/" rel="alternate" type="text/html" title="How to intercept secure network traffic from Android" /><published>2018-05-15T00:00:00+00:00</published><updated>2018-05-15T00:00:00+00:00</updated><id>https://webscraping.com/blog/how-to-intercept-secure-network-traffic-from-android</id><content type="html" xml:base="https://webscraping.com/blog/how-to-intercept-secure-network-traffic-from-android/">&lt;p&gt;Often I need to reverse engineer how an Android app loads its data. If I can determine the relevant server endpoints then I can call them directly in future via a script and bypass the app. This process is more complex when the app uses &lt;a href=&quot;https://en.wikipedia.org/wiki/HTTPS&quot;&gt;HTTPS&lt;/a&gt; for network communication, which is becoming more common now that &lt;a href=&quot;https://letsencrypt.org/&quot;&gt;Let’s Encrypt&lt;/a&gt; provides SSL certificates for free.&lt;/p&gt;

&lt;p&gt;To work with secure network traffic I use &lt;a href=&quot;https://mitmproxy.org/&quot;&gt;mitmproxy&lt;/a&gt;, which is an open source interactive HTTPS proxy written in Python. Installation steps are &lt;a href=&quot;https://docs.mitmproxy.org/stable/overview-installation/&quot;&gt;documented here&lt;/a&gt;. Once installed you need to determine the &lt;em&gt;local IP&lt;/em&gt; address assigned by a router to your computer - this is different than the &lt;em&gt;external IP&lt;/em&gt; address seen from the internet. On Mac I use the following to determine the local IP:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;ipconfig getifaddr en0
192.168.0.105&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now start mitmproxy at this local IP and at a port of your choosing, such as &lt;em&gt;4444&lt;/em&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mitmproxy &lt;span class=&quot;nt&quot;&gt;--listen-host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;192.168.0.105 &lt;span class=&quot;nt&quot;&gt;--listen-port&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;4444&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Next step is to setup your Android device to communicate with mitmproxy:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Go to wifi settings and long press your connection&lt;/li&gt;
  &lt;li&gt;Select &lt;em&gt;Modify network&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;Open advanced settings and change &lt;em&gt;Proxy&lt;/em&gt; to &lt;em&gt;Manual&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;Set &lt;em&gt;Proxy hostname&lt;/em&gt; and &lt;em&gt;Proxy port&lt;/em&gt; to the details used in the earlier mitmproxy command&lt;/li&gt;
  &lt;li&gt;Navigate the web browser to &lt;a href=&quot;http://mitm.it&quot;&gt;mitm.it&lt;/a&gt; and you should see a list of certificates to install - if not then the proxy settings are not working&lt;/li&gt;
  &lt;li&gt;Download the Android certificate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the proxy is working then you should start to see requests from the web browser in the mitmproxy console window:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/static/img/blog/mitm_overview.png&quot; class=&quot;center&quot; style=&quot;padding: 10px&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The network activity for Android apps is also viewable. If we open the &lt;a href=&quot;https://play.google.com/store/apps/details?id=net.xelnaga.exchanger&quot;&gt;Exchange Rates app&lt;/a&gt; then the following network activity will be triggered, which loads the exchange rate data used by the app:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/static/img/blog/mitm_response.png&quot; class=&quot;center&quot; style=&quot;padding: 10px&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This is a HTTPS request but we can still observe the internals because of the custom certificate installed.&lt;/p&gt;

&lt;p&gt;Note that this approach will only work up to Android Marshmallow - in Android Nougat the security model was changed so that &lt;a href=&quot;https://android-developers.googleblog.com/2016/07/changes-to-trusted-certificate.html&quot;&gt;user installed certificates are no longer trusted by default&lt;/a&gt;. Also apps that use &lt;a href=&quot;https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning&quot;&gt;certificate pinning&lt;/a&gt; will not work, since this forces the app to only use a hardcoded trusted certificate. In these case more advanced techniques would need to be employed such as modifying the APK or tampering with the app at runtime with &lt;a href=&quot;https://www.frida.re/&quot;&gt;Frida&lt;/a&gt;.&lt;/p&gt;</content><author><name>WebScraping.com</name><email>contact@webscraping.com</email></author><category term="android" /><category term="mobile apps" /><summary type="html">Often I need to reverse engineer how an Android app loads its data. If I can determine the relevant server endpoints then I can call them directly in future via a script and bypass the app. This process is more complex when the app uses HTTPS for network communication, which is becoming more common now that Let’s Encrypt provides SSL certificates for free.</summary></entry><entry><title type="html">How to automate Android apps with Python</title><link href="https://webscraping.com/blog/How-to-automate-Android-Apps/" rel="alternate" type="text/html" title="How to automate Android apps with Python" /><published>2017-12-01T00:00:00+00:00</published><updated>2017-12-01T00:00:00+00:00</updated><id>https://webscraping.com/blog/How-to-automate-Android-Apps</id><content type="html" xml:base="https://webscraping.com/blog/How-to-automate-Android-Apps/">&lt;p&gt;In a &lt;a href=&quot;/blog/How-to-scrape-Android-Apps/&quot;&gt;previous post&lt;/a&gt; I covered a way to monitor network activity in order to scrape the data from an Android application.
Sometimes this appraoch will not work, for example if the data of interest is embedded within the app or perhaps the network traffic is encrypted. For these cases I use &lt;a href=&quot;https://github.com/xiaocong/uiautomator&quot;&gt;UIautomator&lt;/a&gt;, which is a Python wrapper to the &lt;a href=&quot;https://developer.android.com/training/testing/ui-testing/&quot;&gt;Android testing framework&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To setup UIautomator you will need to install the &lt;a href=&quot;https://developer.android.com/studio/#downloads&quot;&gt;Android SDK&lt;/a&gt; and set the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ANDROID_HOME&lt;/code&gt; environment variable.
On Mac I ran the following to install these dependencies:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;brew cask &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;android-sdk android-platform-tools
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ANDROID_HOME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/usr/local/Caskroom/android-platform-tools/28.0.1/&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;pip &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;uiautomator&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;To check whether your setup is working connect your Android device by USB and try the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;info&lt;/code&gt; command to check its status:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;uiautomator&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;device&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'displayRotation'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'displaySizeDpY'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;640&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'displaySizeDpX'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;360&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'screenOn'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'displayWidth'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1080&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'productName'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'hammerhead'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'currentPackageName'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'com.android.settings'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'sdkInt'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;23&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'displayHeight'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1776&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'naturalOrientation'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If you get the exception &lt;em&gt;EnvironmentError: Device not attached&lt;/em&gt;, then you need to enable USB debugging on your Android device in order to connect.&lt;/p&gt;

&lt;p&gt;If the above command works then you are ready to start automating interactions with your Android device.
Note that instead of a physical Android device you can use an emulator such as &lt;a href=&quot;https://www.genymotion.com/desktop/&quot;&gt;Genymotion&lt;/a&gt;, however I have found some popular apps will not run on emulators.&lt;/p&gt;

&lt;p&gt;UIautomator provides a number of ways to select elements such as by text or class. Actions can then be performed on the selected elements such as click, drag, swipe, and keyboard input.
One of the most useful commands is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dump()&lt;/code&gt;, which returns the current XML layout of your Android device:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&amp;gt;&amp;gt;&amp;gt; d.dump()
&lt;span class=&quot;cp&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; ?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;hierarchy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rotation=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;node&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;bounds=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;[0,0][1080,1776]&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;checkable=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;checked=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;android.widget.FrameLayout&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;clickable=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;content-desc=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;enabled=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;focusable=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;focused=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;index=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;long-clickable=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;package=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;com.google.android.googlequicksearchbox&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;password=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;resource-id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;scrollable=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;selected=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;text=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;node&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;bounds=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;[0,0][1080,1776]&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;checkable=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;checked=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;android.widget.LinearLayout&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;clickable=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;content-desc=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;enabled=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;focusable=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;focused=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;index=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;long-clickable=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;package=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;com.google.android.googlequicksearchbox&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;password=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;resource-id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;scrollable=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;selected=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;text=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;node&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;bounds=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;[0,0][1080,1776]&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;checkable=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;checked=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;android.widget.FrameLayout&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;clickable=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;content-desc=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;enabled=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;focusable=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;focused=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;index=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;long-clickable=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;package=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;com.google.android.googlequicksearchbox&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;password=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;resource-id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;android:id/content&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;scrollable=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;selected=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;text=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;nt&quot;&gt;&amp;lt;node&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;bounds=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;[0,0][1080,1776]&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;checkable=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;checked=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;android.widget.FrameLayout&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;clickable=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;content-desc=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;enabled=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;focusable=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;focused=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;index=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;long-clickable=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;package=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;com.google.android.googlequicksearchbox&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;password=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;resource-id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;com.google.android.googlequicksearchbox:id/launcher&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;scrollable=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;selected=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;text=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
                    ...
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/node&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/hierarchy&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This is equivalent to viewing the source of a web page and shows the attributes used by each element, which can be used by selectors to identify the correct element.&lt;/p&gt;

&lt;p&gt;Here is an example script with UIautomator:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;uiautomator&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Device&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Device&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'014E05DE0F02000E'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;press&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;home&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;press&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'Maps'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'Search here'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'NYC'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;press&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;enter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The script will:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;connect to a device with the given serieal number (the shortcut &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;from uiautomator import device&lt;/code&gt; should not be used if multiple devices are connected)&lt;/li&gt;
  &lt;li&gt;navigate to the home screen&lt;/li&gt;
  &lt;li&gt;open an app labelled &lt;em&gt;Maps&lt;/em&gt; (in my case Google Maps)&lt;/li&gt;
  &lt;li&gt;type &lt;em&gt;NYC&lt;/em&gt; in the search bar&lt;/li&gt;
  &lt;li&gt;and press the &lt;em&gt;ENTER&lt;/em&gt; key to show results&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;UIautomator also supports many other features such as event listeners and relative selectors, which are well documented on the &lt;a href=&quot;https://github.com/xiaocong/uiautomator&quot;&gt;github page&lt;/a&gt;.&lt;/p&gt;</content><author><name>WebScraping.com</name><email>contact@webscraping.com</email></author><category term="android" /><category term="mobile apps" /><category term="python" /><summary type="html">In a previous post I covered a way to monitor network activity in order to scrape the data from an Android application. Sometimes this appraoch will not work, for example if the data of interest is embedded within the app or perhaps the network traffic is encrypted. For these cases I use UIautomator, which is a Python wrapper to the Android testing framework.</summary></entry><entry><title type="html">Web scraping with python book published</title><link href="https://webscraping.com/blog/Web-Scraping-book-published/" rel="alternate" type="text/html" title="Web scraping with python book published" /><published>2016-02-01T00:00:00+00:00</published><updated>2016-02-01T00:00:00+00:00</updated><id>https://webscraping.com/blog/Web-Scraping-book-published</id><content type="html" xml:base="https://webscraping.com/blog/Web-Scraping-book-published/">&lt;p&gt;For the last 9 months or so I have been working intermittently on a book covering the web scraping skills I picked up over the years for my work. It is now available on &lt;a href=&quot;https://www.amazon.com/Scraping-Python-Community-Experience-Distilled/dp/1782164367&quot;&gt;Amazon&lt;/a&gt; or &lt;a href=&quot;https://www.packtpub.com/big-data-and-business-intelligence/web-scraping-python&quot;&gt;directly from the publisher&lt;/a&gt;. Or can be found on BitTorrent.&lt;/p&gt;

&lt;div style=&quot;text-align: center&quot;&gt;
    &lt;img src=&quot;/static/img/blog/book_front.jpg&quot; style=&quot;padding: 10px; width: 45%;&quot; /&gt;
    &lt;img src=&quot;/static/img/blog/book_back.jpg&quot; style=&quot;padding: 10px; width: 45%&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Coincidentally another book on &lt;em&gt;web scraping with python&lt;/em&gt; was released at the same time by O'Reilly, &lt;a href=&quot;https://www.amazon.com/Web-Scraping-Python-Collecting-Modern/dp/1491910291&quot;&gt;available here&lt;/a&gt;.&lt;/p&gt;</content><author><name>WebScraping.com</name><email>contact@webscraping.com</email></author><category term="book" /><summary type="html">For the last 9 months or so I have been working intermittently on a book covering the web scraping skills I picked up over the years for my work. It is now available on Amazon or directly from the publisher. Or can be found on BitTorrent.</summary></entry><entry><title type="html">Heading to Oxford</title><link href="https://webscraping.com/blog/Heading-to-Oxford/" rel="alternate" type="text/html" title="Heading to Oxford" /><published>2015-09-01T00:00:00+00:00</published><updated>2015-09-01T00:00:00+00:00</updated><id>https://webscraping.com/blog/Heading-to-Oxford</id><content type="html" xml:base="https://webscraping.com/blog/Heading-to-Oxford/">&lt;p&gt;This year I will be fulfilling a lifelong dream of studying at Oxford University. For the next 11 months I will be completing an MSc in Computer Science, and during this time will work on projects for existing clients but probably need to limit taking on new clients.&lt;/p&gt;

&lt;p&gt;&lt;img style=&quot;width: 100%&quot; src=&quot;/static/img/blog/oxford_panorama.jpg&quot; /&gt;&lt;/p&gt;</content><author><name>WebScraping.com</name><email>contact@webscraping.com</email></author><category term="Oxford" /><summary type="html">This year I will be fulfilling a lifelong dream of studying at Oxford University. For the next 11 months I will be completing an MSc in Computer Science, and during this time will work on projects for existing clients but probably need to limit taking on new clients.</summary></entry><entry><title type="html">How to scrape Android apps</title><link href="https://webscraping.com/blog/How-to-scrape-Android-Apps/" rel="alternate" type="text/html" title="How to scrape Android apps" /><published>2015-07-13T00:00:00+00:00</published><updated>2015-07-13T00:00:00+00:00</updated><id>https://webscraping.com/blog/How-to-scrape-Android-Apps</id><content type="html" xml:base="https://webscraping.com/blog/How-to-scrape-Android-Apps/">&lt;p&gt;Google recently released the &lt;a href=&quot;https://chrome.google.com/webstore/detail/arc-welder/emfinbmielocnlhgmfkkmkngdoccbadn&quot;&gt;Arc Welder&lt;/a&gt; extension for Chrome, which allows an Android app to be run on the desktop. The aim of Arc Welder is to help make testing Android apps easier, but conveniently it also makes scraping Android apps easier too.&lt;/p&gt;

&lt;p&gt;To run an app in Arc Welder we need to first download the app’s APK file. Google Play does not make this straightforward so I would suggest using an alternative such as &lt;a href=&quot;http://www.androiddrawer.com&quot;&gt;androiddrawer.com&lt;/a&gt;. 
I often use the &lt;a href=&quot;https://play.google.com/store/apps/details?id=net.xelnaga.exchanger&amp;amp;hl=en&quot;&gt;Exchange Rates app&lt;/a&gt; when travelling and was curious where they source their currency data. The APK is available for download &lt;a href=&quot;http://www.androiddrawer.com/21578/download-exchange-rates-app-apk/&quot;&gt;here&lt;/a&gt;, and then when loaded in Arc Welder looks like this:&lt;/p&gt;

&lt;div style=&quot;text-align:center&quot;&gt;
    &lt;img src=&quot;/static/img/blog/arcwelder_loaded.png&quot; style=&quot;padding: 10px&quot; /&gt;
    &lt;img src=&quot;/static/img/blog/arcwelder_running.png&quot; style=&quot;padding: 10px&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;(Note that if you get an error saying &lt;strong&gt;WebGL is not supported&lt;/strong&gt; then you need to force Chrome to support WebGL by enabling the &lt;strong&gt;Override software rendering list&lt;/strong&gt; flag: &lt;a href=&quot;chrome://flags/#ignore-gpu-blacklist&quot;&gt;chrome://flags/#ignore-gpu-blacklist&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Now that the Exchange Rates app is running on my computer I used &lt;a href=&quot;https://www.wireshark.org/&quot;&gt;Wireshark&lt;/a&gt; to track network traffic, which showed the following request was made:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/static/img/blog/wireshark_exchange.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This means that this app simply uses the Yahoo Finance API for their currency data, available at: &lt;a href=&quot;http://finance.yahoo.com/webservice/v1/symbols/allcurrencies/quote?format=json&quot;&gt;http://finance.yahoo.com/webservice/v1/symbols/allcurrencies/quote?format=json&lt;/a&gt;. So to scrape the data from the Exchange rate app merely requires calling this API. 
&lt;br /&gt;(If you want to learn more about how to use Wireshark check out their &lt;a href=&quot;https://www.wireshark.org/docs/wsug_html_chunked/&quot;&gt;extensive documentation&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;I chose a non-controversial app for this blog post that uses a public API, but this same technique can be applied to any Android app that loads its content from a backend server, which ought to be most apps with data of interest.&lt;/p&gt;</content><author><name>WebScraping.com</name><email>contact@webscraping.com</email></author><category term="android" /><category term="mobile apps" /><category term="google" /><summary type="html">Google recently released the Arc Welder extension for Chrome, which allows an Android app to be run on the desktop. The aim of Arc Welder is to help make testing Android apps easier, but conveniently it also makes scraping Android apps easier too.</summary></entry><entry><title type="html">Luminati</title><link href="https://webscraping.com/blog/Luminati/" rel="alternate" type="text/html" title="Luminati" /><published>2015-06-24T00:00:00+00:00</published><updated>2015-06-24T00:00:00+00:00</updated><id>https://webscraping.com/blog/Luminati</id><content type="html" xml:base="https://webscraping.com/blog/Luminati/">&lt;p&gt;These days I am often contacted by businesses asking if I want to try a free trial of their service. A recent one was &lt;a href=&quot;https://luminati.io/&quot;&gt;Luminati&lt;/a&gt;, which claimed to have access to millions of IP addresses. They weren’t willing to divulge much over email and their website had less information than it does now, so we set up a Skype call. My contact was a salesman so he wasn’t able to answer technical questions, but gave me a good overview of what they are trying to do. Apparently they are an Israeli startup that built a peer to peer network called &lt;a href=&quot;http://hola.org/&quot;&gt;Hola&lt;/a&gt;, where users install a plugin to access content that is blocked in their region by downloading via other peers in the network. Now that they had millions of users they wanted to monetize this network by reselling it as a proxy service. Great idea, though when I signed up for a test account with Hola this was not clear, so I doubt most users are aware their bandwidth is being resold.&lt;/p&gt;

&lt;p&gt;Unfortunately I found Lumanati’s costs are prohibitive for my typical usage:&lt;br /&gt;
&lt;img src=&quot;/static/img/blog/luminati.png&quot; /&gt;
&lt;br /&gt;A medium scale website requires roughly 50GB of downloading, which would work out at $1000 if downloaded via Luminati, so using this service would only be practical for small websites that quickly block IP’s.&lt;/p&gt;</content><author><name>WebScraping.com</name><email>contact@webscraping.com</email></author><category term="business" /><category term="proxies" /><summary type="html">These days I am often contacted by businesses asking if I want to try a free trial of their service. A recent one was Luminati, which claimed to have access to millions of IP addresses. They weren’t willing to divulge much over email and their website had less information than it does now, so we set up a Skype call. My contact was a salesman so he wasn’t able to answer technical questions, but gave me a good overview of what they are trying to do. Apparently they are an Israeli startup that built a peer to peer network called Hola, where users install a plugin to access content that is blocked in their region by downloading via other peers in the network. Now that they had millions of users they wanted to monetize this network by reselling it as a proxy service. Great idea, though when I signed up for a test account with Hola this was not clear, so I doubt most users are aware their bandwidth is being resold.</summary></entry><entry><title type="html">Phone calls</title><link href="https://webscraping.com/blog/Phone-Calls/" rel="alternate" type="text/html" title="Phone calls" /><published>2015-06-15T00:00:00+00:00</published><updated>2015-06-15T00:00:00+00:00</updated><id>https://webscraping.com/blog/Phone-Calls</id><content type="html" xml:base="https://webscraping.com/blog/Phone-Calls/">&lt;p&gt;I have noticed that if for some reason a new client can not describe what they are after in an email, but want a &lt;em&gt;quick phone call&lt;/em&gt; to clarify, this conversation will rarely develop into an actual project. I guess they want to pick my brain and then implement it internally or hire someone cheaper, so to limit the amount of time wasted I have started insisting an overview of the project be sent before setting up a phone call.&lt;/p&gt;</content><author><name>WebScraping.com</name><email>contact@webscraping.com</email></author><category term="business" /><summary type="html">I have noticed that if for some reason a new client can not describe what they are after in an email, but want a quick phone call to clarify, this conversation will rarely develop into an actual project. I guess they want to pick my brain and then implement it internally or hire someone cheaper, so to limit the amount of time wasted I have started insisting an overview of the project be sent before setting up a phone call.</summary></entry><entry><title type="html">Bitcoin</title><link href="https://webscraping.com/blog/Bitcoin/" rel="alternate" type="text/html" title="Bitcoin" /><published>2015-06-01T00:00:00+00:00</published><updated>2015-06-01T00:00:00+00:00</updated><id>https://webscraping.com/blog/Bitcoin</id><content type="html" xml:base="https://webscraping.com/blog/Bitcoin/">&lt;p&gt;A few years ago I opened a US bank account so that US clients who wanted to pay by bank transfer could avoid needing to make an international transaction. This worked well until last month when clients started reporting their transfers were being rejected. I rang the bank (&lt;a href=&quot;https://www.chase.com/&quot;&gt;Chase&lt;/a&gt;) and after being transferred between a few departments was told I needed to come into a US branch with my passport to discuss the problem, which couldn’t be handled over the phone. Quite inconvenient because I don’t live in the US and didn’t plan to visit in the near future.&lt;/p&gt;

&lt;p&gt;I expect the problem is receiving transactions from multiple client bank accounts raised some automated red flag, but won’t know for sure until next time visit the US. So now my US bank account was frozen without warning or explanation - as you can imagine I was not a happy camper.&lt;/p&gt;

&lt;p&gt;This experience made me more sympathetic to the &lt;a href=&quot;http://en.wikipedia.org/wiki/Bitcoin&quot;&gt;Bitcoin&lt;/a&gt; Libertarian philosophy where there is no centralized authority to get in the way of doing business. Consequently, I researched how the protocol works and added support for Bitcoin to my &lt;a href=&quot;webscraping.com/data/&quot;&gt;data store&lt;/a&gt; and invoice system. I originally budgeted a week of time to figure this all out but found the protocol much simpler than expected and in the end took just a weekend, certainly easier than an earlier integration I did with the &lt;a href=&quot;https://developer.paypal.com/docs/classic/api/&quot;&gt;PayPal API&lt;/a&gt;. The only complexity is that because transactions are anonymous I needed to generate a unique bitcoin address for each client so that I know who the transaction is from. This is how it works:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Find the current exchange rate between the clients currency and Bitcoin&lt;/li&gt;
  &lt;li&gt;Generate a bitcoin address to receive this transaction&lt;/li&gt;
  &lt;li&gt;When expected transaction is received at this address mark as paid&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That’s it. &lt;a href=&quot;https://blockchain.info&quot;&gt;Blockchain.info&lt;/a&gt; has a well documented API that can handle each of these steps. For exchange rates there is the &lt;a href=&quot;https://blockchain.info/ticker&quot;&gt;Ticker API&lt;/a&gt; and for managing and monitoring addresses in steps 2 &amp;amp; 3 there is the &lt;a href=&quot;https://blockchain.info/api/api_receive&quot;&gt;Receive API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Also then to display a QR code for the required transaction I used the &lt;a href=&quot;https://developers.google.com/chart/&quot;&gt;Google Chart API&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://chart.googleapis.com/chart?cht=qr&amp;amp;chs=150x150&amp;amp;chld=L|0&amp;amp;chl=bitcoin:1DUF6WqoAUD6wsL9F5nLheVJEMwfFQ38df?amount=0.44306601&amp;amp;label=WebScraping.com&amp;amp;message=Payment%20for%20Android%20apps%20database&quot; /&gt;&lt;/p&gt;</content><author><name>WebScraping.com</name><email>contact@webscraping.com</email></author><category term="business" /><category term="website" /><summary type="html">A few years ago I opened a US bank account so that US clients who wanted to pay by bank transfer could avoid needing to make an international transaction. This worked well until last month when clients started reporting their transfers were being rejected. I rang the bank (Chase) and after being transferred between a few departments was told I needed to come into a US branch with my passport to discuss the problem, which couldn’t be handled over the phone. Quite inconvenient because I don’t live in the US and didn’t plan to visit in the near future.</summary></entry><entry><title type="html">Android database update</title><link href="https://webscraping.com/blog/Android-Apps-Update/" rel="alternate" type="text/html" title="Android database update" /><published>2015-05-15T00:00:00+00:00</published><updated>2015-05-15T00:00:00+00:00</updated><id>https://webscraping.com/blog/Android-Apps-Update</id><content type="html" xml:base="https://webscraping.com/blog/Android-Apps-Update/">&lt;p&gt;A significant update to the &lt;a href=&quot;http://webscraping.com/data/default/database/11/android-apps&quot;&gt;Android Apps database&lt;/a&gt; is now ready, which now contains over 2 million apps (2,130,732 to be exact). If you have purchased this database previously you can &lt;a href=&quot;http://webscraping.com/data/default/user/login&quot;&gt;login to your account&lt;/a&gt; to download the updated version for free.&lt;/p&gt;</content><author><name>WebScraping.com</name><email>contact@webscraping.com</email></author><category term="database" /><category term="website" /><category term="mobile apps" /><summary type="html">A significant update to the Android Apps database is now ready, which now contains over 2 million apps (2,130,732 to be exact). If you have purchased this database previously you can login to your account to download the updated version for free.</summary></entry><entry><title type="html">Web Scraping or Web Scrapping?</title><link href="https://webscraping.com/blog/Web-Scrapping/" rel="alternate" type="text/html" title="Web Scraping or Web Scrapping?" /><published>2015-04-21T00:00:00+00:00</published><updated>2015-04-21T00:00:00+00:00</updated><id>https://webscraping.com/blog/Web-Scrapping</id><content type="html" xml:base="https://webscraping.com/blog/Web-Scrapping/">&lt;p&gt;I searched my email and found over the last few years I received 76 messages from clients containing the text &lt;em&gt;Web Scrapping&lt;/em&gt; rather than the usual spelling &lt;em&gt;Web Scraping&lt;/em&gt;. And this is not unique to my clients - currently Google has &lt;a href=&quot;https://www.google.com/search?q=\&amp;quot;web+scrapping\&amp;quot;&quot;&gt;122,000 results&lt;/a&gt; for “Web Scrapping” compared to &lt;a href=&quot;https://www.google.com/search?q=\&amp;quot;web+scraping\&amp;quot;&quot;&gt;447,000 results&lt;/a&gt; for “Web Scraping” - the correct spelling returns only 4x the number of results. So in light of this common spelling mistake I registered the domain &lt;a href=&quot;http://webscrapping.com&quot;&gt;webscrapping.com&lt;/a&gt; and redirected it here.&lt;/p&gt;</content><author><name>WebScraping.com</name><email>contact@webscraping.com</email></author><category term="business" /><category term="website" /><summary type="html">I searched my email and found over the last few years I received 76 messages from clients containing the text Web Scrapping rather than the usual spelling Web Scraping. And this is not unique to my clients - currently Google has 122,000 results for “Web Scrapping” compared to 447,000 results for “Web Scraping” - the correct spelling returns only 4x the number of results. So in light of this common spelling mistake I registered the domain webscrapping.com and redirected it here.</summary></entry></feed>