<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tom Hughes</title>
    <description>The latest articles on DEV Community by Tom Hughes (@thughes24).</description>
    <link>https://dev.to/thughes24</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F102730%2F05f77d71-d3e7-4005-b2d4-d99d566409b1.jpg</url>
      <title>DEV Community: Tom Hughes</title>
      <link>https://dev.to/thughes24</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/thughes24"/>
    <language>en</language>
    <item>
      <title>Building My First Trading Bot (And How It Lost All My Money)</title>
      <dc:creator>Tom Hughes</dc:creator>
      <pubDate>Mon, 25 Jan 2021 21:43:12 +0000</pubDate>
      <link>https://dev.to/thughes24/building-my-first-trading-bot-and-how-it-lost-all-my-money-3dia</link>
      <guid>https://dev.to/thughes24/building-my-first-trading-bot-and-how-it-lost-all-my-money-3dia</guid>
      <description>&lt;p&gt;It was 2017 and I’d just moved to Thailand. I was loving every minute of it; Working from coffee shops, going to events at night and mingling with other people who were also working online, or at least attempting to.&lt;/p&gt;

&lt;p&gt;Life was good. &lt;/p&gt;

&lt;p&gt;The only issue was that I was hemorrhaging money, it was a small hemorrhage (cost of living is low in Thailand), but a hemorrhage nonetheless.&lt;/p&gt;

&lt;p&gt;I had no income source. My justification for this was that I was learning to write code, and soon enough this new knowledge would be able to provide me with all the money I’d ever need. &lt;/p&gt;

&lt;p&gt;I loved the idea of being able to make anything with JUST a laptop and an internet connection, I was determined to make this lifestyle work. &lt;/p&gt;




&lt;h2&gt;
  
  
  The Dream
&lt;/h2&gt;

&lt;p&gt;I had a great idea. I was going to build a program that would automatically place bets for me.&lt;/p&gt;

&lt;p&gt;Furthermore, this bot would be intelligent, it would know exactly how much money I had and would increase / decrease the amount bet accordingly.&lt;/p&gt;

&lt;p&gt;If this worked, I could sit back and drink yai leos (large beers) while my bot diligently printed money. &lt;/p&gt;

&lt;p&gt;The idea was simple, I’d subscribe to lots of different betting ‘tipsters’, and any selections that more than one tipster recommended, I’d bet on it.&lt;/p&gt;

&lt;p&gt;These tipsters were all claiming to be profitable gamblers, so my thinking was that by only betting on the ones that more than one tipster recommended, I’d be increasing the profitability of the bets. &lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Dream
&lt;/h2&gt;

&lt;p&gt;I discovered a pretty clever way to input all the data. Whenever a tipster would send me an email with the days recommended tips, I would forward it to my bot. The bot would then parse out the information and put it into a big database. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FN4jta8B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/34p456hth27gg6aymxge.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FN4jta8B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/34p456hth27gg6aymxge.png" alt="An example email that would be parsed into JSON"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once I had all the day's selections in the database, I needed a way to be able to tell if there were any duplicate tips.&lt;/p&gt;

&lt;p&gt;This is actually harder than it sounds. There was a range of inconsistencies between the way each tipster sent out their tips, such as;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Kempsey 18:30 #5 Little Miss Sunshine &lt;br&gt;
Kempsey 6:30pm #5 Little Ms Sunshine&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Notice the inconsistent use of apostrophes, 24hr time, abbreviations etc. &lt;/p&gt;

&lt;p&gt;All this made it very hard to actually match the data together. This led me into the topic of ‘fuzzy matching’. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Fuzzy Matching&lt;/em&gt; attempts to match datasets that aren’t 100% the same.&lt;/p&gt;

&lt;p&gt;The first thing I did was attempt to normalize all the data, by stripping out all the apostrophes and special characters, and converting everything to lowercase. &lt;/p&gt;

&lt;p&gt;Then I found a library that could detect and convert 12 hour time into 24 hour time, so I used that. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;The beauty about programming is that you don’t need to do everything yourself, there’s public online libraries where you can pull and use other peoples (often much more sophisticated) code. Perfect for a newbie like me!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now the above example looked like this;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;kempsey 18:30 #5 little miss sunshine&lt;br&gt;
kempsey 18:30 #5 little ms sunshine&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Finally I found an algorithm known as the &lt;em&gt;Levenshtein Algorithm&lt;/em&gt;. This is a form of fuzzy matching that compares how many substitutions are required to make two strings the same.&lt;/p&gt;

&lt;p&gt;For example ‘dog’ compared to ‘dag’ has a Levenshtein distance of 1, because all we need to do to make the words match is replace ‘a’ with ‘o’.&lt;/p&gt;

&lt;p&gt;I decided that any two tips that had a Levenshtein distance lower than 5 would be assumed to be the same. &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Input 1&lt;/th&gt;
&lt;th&gt;Input 2&lt;/th&gt;
&lt;th&gt;Levenshtein Distance&lt;/th&gt;
&lt;th&gt;The Same?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;kempsey 18:30 #5 little miss sunshine&lt;/td&gt;
&lt;td&gt;kempsey 18:30 #5 little ms sunshine&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kempsey 18:30 #5 little miss sunshine&lt;/td&gt;
&lt;td&gt;kempsey 15:00 #3 dance monkey&lt;/td&gt;
&lt;td&gt;21&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Now that all the hard stuff was out of the way, all I had to do was implement the actual placing of the bets. &lt;/p&gt;

&lt;p&gt;There’s a lot more technical stuff involved in how this was made, but parsing and normalizing the tips was by far the most challenging part of the build. &lt;/p&gt;

&lt;p&gt;All my bets were going to be placed on Betfair, which is a betting exchange where people can place bets against other punters. Betfair is great because they have a really easy to use API. &lt;/p&gt;

&lt;p&gt;Using the Betfair API to place the bets was pretty straight forward. I ran a query to get a list of all of the horses that were running today, then found the ID of the horse that corresponded to the horse I wanted to bet on (also using the Levenshtein algorithm) and I was off to the races (literally). &lt;/p&gt;

&lt;p&gt;Now, it’s safe to say that this whole codebase was a sloppy mess. I’m no zealot about writing clean efficient code, but this was sloppy even by my standards (to be fair, I was still learning). &lt;/p&gt;

&lt;p&gt;Sloppiness aside, I was done. &lt;/p&gt;

&lt;p&gt;I managed to build a bot that would receive emails, parse data, normalize that data and then query Betfair’s API to place the bets using real money.&lt;/p&gt;

&lt;p&gt;100% automated, no input required by me, brilliant!&lt;/p&gt;

&lt;p&gt;It would even send me an email with the bets it was placing (as shown below). &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QJ2iZBD9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4ih5h6tm9kln1f5mysm6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QJ2iZBD9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4ih5h6tm9kln1f5mysm6.png" alt="An example email the bot would send me with the days bets"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Dream Gone Wrong
&lt;/h2&gt;

&lt;p&gt;Now all there was to do was fund my Betfair account and let the bot work it’s magic!&lt;/p&gt;

&lt;p&gt;As I was still a complete beginner, I decided to only bet a TINY amount of money. &lt;/p&gt;

&lt;p&gt;The amount I was going to bet would be determined by the odds that the horse was suggested at. I would always bet to profit a certain amount of money, around $100.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Odds&lt;/th&gt;
&lt;th&gt;Stake&lt;/th&gt;
&lt;th&gt;Return&lt;/th&gt;
&lt;th&gt;Profit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;$11&lt;/td&gt;
&lt;td&gt;$110&lt;/td&gt;
&lt;td&gt;$100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;$25&lt;/td&gt;
&lt;td&gt;$125&lt;/td&gt;
&lt;td&gt;$100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.5&lt;/td&gt;
&lt;td&gt;$66.6&lt;/td&gt;
&lt;td&gt;$166.6&lt;/td&gt;
&lt;td&gt;$100&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Notice how the lower the odds, the more I bet?&lt;/p&gt;

&lt;p&gt;This is good because I’d be betting more money on the more horses that were more likely to win, and less on the outsiders. &lt;/p&gt;

&lt;p&gt;After a few days of the bot running I received this email.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HjkEwW8J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/wqhoye8c27dp5auva3ds.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HjkEwW8J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/wqhoye8c27dp5auva3ds.png" alt="An Email the bot sent with very strange data"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Oh no. &lt;/p&gt;

&lt;p&gt;I knew something was horribly wrong because I would never bet on a horse at odds of 1.08. &lt;/p&gt;

&lt;p&gt;Because of the way I was staking, I knew that this was likely going to result in my bot betting my ENTIRE BALANCE on this one horse. &lt;/p&gt;

&lt;p&gt;Suddenly the nice message I programmed the bot to send “have a great night” was like a kick in the nuts. &lt;/p&gt;

&lt;p&gt;“Hey Tom, I’ve bet all your money. Have a great night”&lt;/p&gt;

&lt;p&gt;Sure enough, I log into my Betfair account and see the following. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OEuqxfRp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ortaybv5tnmdlpsk3m87.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OEuqxfRp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ortaybv5tnmdlpsk3m87.png" alt="Betslip showing $2304 bet"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ouch, instead of betting a tiny amount of money like I wanted, it bet over $2000. &lt;/p&gt;

&lt;p&gt;Considering I didn’t have an income source, this was a devastating blow. &lt;/p&gt;

&lt;p&gt;What the hell went wrong? &lt;/p&gt;

&lt;h2&gt;
  
  
  The Aftermath
&lt;/h2&gt;

&lt;p&gt;I went back into my emails and found the issue.&lt;/p&gt;

&lt;p&gt;One of the tipsters emails that I was parsing had added in a new column unexpectedly.&lt;/p&gt;

&lt;p&gt;The column that my bot normally would find the suggested odds, was actually a new column called ‘value for money’, a number between 1 and 1.2.&lt;/p&gt;

&lt;p&gt;The ACTUAL suggested odds for this horse was 6.5.&lt;/p&gt;

&lt;p&gt;But not all hope was lost. Betfair is a market where you can buy AND sell bets. &lt;/p&gt;

&lt;p&gt;Maybe I could just sell the bet back to the market? Not quite it turns out. &lt;/p&gt;

&lt;p&gt;Betfair operates like an exchange. People put in their orders that they are willing to buy and sell tips at. Because my bot put $2304 on this horse at odds of 1.08, Betfair matched my bet with ANY order that was higher than 1.08.&lt;/p&gt;

&lt;p&gt;Considering the market odds for this horse was actually 6.5, I accepted pretty much every order that was available. No price was too low for me! I chowed through that order book like Pacman. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QBd2nGmd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/m654l5gsuvk9lfk4bjlo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QBd2nGmd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/m654l5gsuvk9lfk4bjlo.gif" alt="Pacman gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This can sometimes happen in the stock market, and is known as a ‘fat thumb’ (lol).&lt;/p&gt;

&lt;p&gt;Literally because someone with a ‘fat thumb’ accidentally hits the wrong key on the keyboard (because of their enormous thumb) and buys/sells WAY more than they want to.&lt;/p&gt;

&lt;p&gt;This has the result of eating through the order book, much like my bet did. Below is an example of what this looks like;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BRIl2TNj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/it1eppnrqhebr7l0mrjj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BRIl2TNj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/it1eppnrqhebr7l0mrjj.png" alt="An example of a fat thumb error"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice the big long red line? That’s a textbook fat thumb. Someone with a lot of money accidentally sold $10 million of something instead of $10,000. &lt;/p&gt;

&lt;p&gt;After a ‘fat thumb’ event, the market quickly re-stabilizes as seen above. It’s nothing more than a blip. &lt;/p&gt;

&lt;p&gt;Because of this phenomenon, the odds for the horse that I bet $2304 on quickly rose back up to the market average of 6.5. &lt;/p&gt;

&lt;p&gt;Given that I got average odds of 2.56, there was no way I could sell the bet without guaranteeing a massive loss. I decided to ride the bet.&lt;/p&gt;

&lt;p&gt;I thought about writing a big paragraph about how nervous and excited I was to watch the race, imagining the glory if it won, but it’s not really the point of this post. Long story short, the horse lost and with it went my $2304. &lt;/p&gt;

&lt;p&gt;I deactivated the bot pretty quickly after this. &lt;/p&gt;

&lt;h2&gt;
  
  
  The Postmortem
&lt;/h2&gt;

&lt;p&gt;Looking back now as an experienced developer, there’s literally infinite things I could have done to prevent this. &lt;/p&gt;

&lt;p&gt;The most obvious (and simple) one is implementing what’s known as a guard clause. &lt;/p&gt;

&lt;p&gt;A guard clause is a boolean expression that HAS to evaluate to true in order for a function to continue executing. &lt;/p&gt;

&lt;p&gt;As an example, a function that fails if any of its inputs are negative might have a guard clause like;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s a simple check that everything is as it should be before running. &lt;/p&gt;

&lt;p&gt;Below is the function I wrote that is responsible for placing the bet (written in ruby);&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;place_bet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;market&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;horse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stake&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;odds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;place_orders&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="ss"&gt;marketId: &lt;/span&gt;&lt;span class="n"&gt;market&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;instructions: &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;
            &lt;span class="ss"&gt;orderType: &lt;/span&gt;&lt;span class="s2"&gt;"LIMIT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="ss"&gt;selectionId: &lt;/span&gt;&lt;span class="n"&gt;horse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="ss"&gt;side: &lt;/span&gt;&lt;span class="s2"&gt;"BACK"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="ss"&gt;limitOrder: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="ss"&gt;size: &lt;/span&gt;&lt;span class="n"&gt;stake&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="ss"&gt;price: &lt;/span&gt;&lt;span class="n"&gt;odds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="ss"&gt;persistenceType: &lt;/span&gt;&lt;span class="s2"&gt;"MARKET_ON_CLOSE"&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}]&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="vi"&gt;@order&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice there’s no checks or anything. This could place a bet for $1,000,000 and my bot wouldn’t bat an eyelid. &lt;/p&gt;

&lt;p&gt;I could add one line of code to fix that;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;stake&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it. Now any bet &amp;gt; $200 would be considered invalid and wouldn't be placed.&lt;/p&gt;

&lt;p&gt;That simple, obvious line of code could have saved me $2304. &lt;/p&gt;

&lt;p&gt;That is, until the next bug comes along. &lt;/p&gt;

&lt;p&gt;Thanks for reading, if you enjoyed this post please subscribe to my blog (&lt;a href="https://tomhughes.cc"&gt;https://tomhughes.cc&lt;/a&gt;). I write about my experiences as a solo developer, what it’s like living overseas, gambling/investing as an income and more :)&lt;/p&gt;

</description>
      <category>projects</category>
      <category>ruby</category>
      <category>trading</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How To Turn Your VPN Into A Proxy Using Python</title>
      <dc:creator>Tom Hughes</dc:creator>
      <pubDate>Thu, 02 Jul 2020 23:32:27 +0000</pubDate>
      <link>https://dev.to/thughes24/how-to-turn-your-vpn-into-a-proxy-using-python-28ag</link>
      <guid>https://dev.to/thughes24/how-to-turn-your-vpn-into-a-proxy-using-python-28ag</guid>
      <description>&lt;p&gt;I love scraping data. &lt;/p&gt;

&lt;p&gt;I can write a script that in a few seconds can pull data from a site, filter out all the html tags and javascript mumbo jumbo, and spit out the exact data that I want in a beautiful, useable format (preferably JSON).&lt;/p&gt;

&lt;p&gt;Without web scraping that would take me HOURS of copy and pasting.&lt;/p&gt;

&lt;p&gt;One frustrating part about web scraping though is that generally site owners don't want you scraping their site. Which is totally fair enough.&lt;/p&gt;

&lt;p&gt;However, if you're still hell bent on web scraping, you can use what's known as a 'proxy' to hide your IP address.&lt;/p&gt;

&lt;p&gt;This makes it much harder for websites to stop you scraping them. &lt;/p&gt;

&lt;p&gt;A proxy works by tunnelling all your requests through a seperate server.&lt;/p&gt;

&lt;p&gt;For the site owner, it looks like it's the seperate server that's making the request, and they are. But then they are relaying that request right back to you, sneaky!&lt;/p&gt;

&lt;p&gt;Today I'm going to show you how to use any commercial VPN (NordVPN, ExpressVPN etc) with the requests library in Python to level up your web scraping game. &lt;/p&gt;




&lt;p&gt;First off, we're going to import the libraries we want to use. In this tutorial we're just going to use the requests library.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Using a proxy with the requests library is done with the following structure;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;proxies&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That's it. How damn easy is that!&lt;/p&gt;

&lt;p&gt;So what is that 'proxy' object we passed into the get function?&lt;/p&gt;

&lt;p&gt;The proxy object is a dictionary that maps each protocol (http, https, ftp etc) to a specific proxy in the following format;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="n"&gt;proxy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;http&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;username:password@host&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;username:password@host&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now we just need to fill in the blanks here. I'm using NordVPN but any popular VPN service will work (ExpressVPN, SurfShark etc). &lt;/p&gt;

&lt;p&gt;Your username and password will be the same as the one you use to login to your VPN. &lt;/p&gt;

&lt;p&gt;Notice in the proxy string, the characters : and @ are used to seperate the username, password and host. If you have these characters in your username or password, the interpreter will get confused and the proxy won't work. &lt;/p&gt;

&lt;p&gt;For this reason we need to encode our username and password, more info can be found on that &lt;a href="https://www.w3schools.com/tags/ref_urlencode.asp" rel="noopener noreferrer"&gt;here&lt;/a&gt;. For reference, @ becomes %40 and : becomes %3A. &lt;/p&gt;

&lt;p&gt;Now we just need to fill in the 'host' part of the string. &lt;/p&gt;

&lt;p&gt;Navigating to your VPN providers website, there should be a section that lists all their servers, with NordVPN there's a 'servers' link on the homepage that gives you all the information you need;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdoi4xrv50tlc7gdvmvun.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdoi4xrv50tlc7gdvmvun.png" alt="NordVPN Server Selection Page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using the above information, the host we're going to use is &lt;code&gt;au473.nordvpn.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So our full proxy object becomes;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="n"&gt;proxy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;http&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tom%40gmail.com:password123@au473.nordvpn.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tom%40gmail.com:password123@au473.nordvpn.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;em&gt;These aren't my real login details, but you knew that.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Putting it all together we get;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="n"&gt;proxy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;http&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tom%40gmail.com:password123@au473.nordvpn.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tom%40gmail.com:password123@au473.nordvpn.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https://google.com&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;proxies&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;And that's it! Now all the requests you make will LOOK like they're coming from NordVPN, cool huh!&lt;/p&gt;

&lt;p&gt;We've managed to turn any VPN service into a proxy with a few short lines of code.&lt;/p&gt;

&lt;p&gt;Hopefully you've learnt something new today :)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you want to be EVEN more stealthy when web scraping, I'll be writing more articles here on the topic, so be sure to follow me to stay updated!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>webscraping</category>
      <category>proxy</category>
      <category>nordvpn</category>
    </item>
    <item>
      <title>3 Painful Lessons I’ve Learnt As A Solo Developer</title>
      <dc:creator>Tom Hughes</dc:creator>
      <pubDate>Wed, 01 Jul 2020 02:31:06 +0000</pubDate>
      <link>https://dev.to/thughes24/3-painful-lessons-i-ve-learnt-as-a-solo-developer-j3o</link>
      <guid>https://dev.to/thughes24/3-painful-lessons-i-ve-learnt-as-a-solo-developer-j3o</guid>
      <description>&lt;p&gt;I’ve flirted with the idea of calling myself a developer for years now. Yet, whenever the words come out of my mouth, it just doesn’t feel right.&lt;/p&gt;

&lt;p&gt;I don’t have a computer science background, I’m largely self taught and I don’t work in a team. &lt;/p&gt;

&lt;p&gt;I learnt to code almost exclusively from youtube tutorials, blog posts and stack overflow.&lt;/p&gt;

&lt;p&gt;While that’s good, there’s definitely some ‘gotchas’ that I wish I’d known before starting out. This article is written for anyone hacking it on their own, I hope I can save you some time. &lt;/p&gt;




&lt;h2&gt;
  
  
  Avoid &lt;em&gt;Tutorial Hell&lt;/em&gt; at all costs.
&lt;/h2&gt;

&lt;p&gt;Tutorial hell is the syndrome where you're perpetually completing tutorials, without ever making any meaningful progress.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Once I learn React I’ll have more job prospects, and Angular couldn’t hurt!”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In my early days, I felt this insidious loop all too personally. CSS tutorials, Ruby on Rails tutorials, DevOps tutorials, you name it.&lt;/p&gt;

&lt;p&gt;The dangerous thing about this is that you’re never actually implementing anything you're learning.&lt;/p&gt;

&lt;p&gt;The likelihood of ANY of this information sticking is next to none. It’s the equivalent of an overweight person reading weight loss book after weight loss book, without ever exercising. &lt;/p&gt;

&lt;p&gt;The only time things really started to stick was when I was banging my head against the wall building my own project. This will likely be the case for you, too. &lt;/p&gt;




&lt;h2&gt;
  
  
  Prioritise development speed over everything.
&lt;/h2&gt;

&lt;p&gt;This is the single biggest source of wasted time for me, and I imagine many others.&lt;/p&gt;

&lt;p&gt;I’m a perfectionist at heart. When I launch a website, I want users to be able to reset their passwords, chat with other users in real-time and so much more. 100% test coverage would be nice, too. &lt;/p&gt;

&lt;p&gt;As a solo developer, I don’t have the time to implement all these features. Especially when 99% of my projects fail. I’ve now learnt to write remarkably ugly code that ships at least 5 times faster than my prior self.&lt;/p&gt;

&lt;p&gt;Does it incur a lot of technical debt? Sure. I’d rather that then spend time building unnecessary features that no one uses.&lt;/p&gt;

&lt;p&gt;If a project ever sees traction, then and only then will I go back and clean it all up. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Side note, there should be a word to describe the hours of wasted time building features that are never used (technical waste?)&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Learn one or two languages, and learn them well.
&lt;/h2&gt;

&lt;p&gt;Have you ever found yourself googling the most basic of things? I have, many times. The amount of google searches I’ve done for “How to find the length of an array in [insert language here]” is embarrassing. These searches are not only a waste of time, but an unnecessary context switch.&lt;/p&gt;

&lt;p&gt;By deciding to focus on only one or two languages, you can gain a better grasp of the fundamentals and syntax of said languages, avoiding these costly searches. For example, I only code in Python and Javascript (and some SQL). This decision has improved my overall developer experience and speed greatly. &lt;/p&gt;




&lt;p&gt;So there’s the 3 main things I’ve learnt as a solo developer. The hardest point for me to implement was sticking to two languages. It can feel like you’re falling behind when you see all these articles popping up about a language or framework you have never even heard of.&lt;/p&gt;

&lt;p&gt;Let me know in the comments the things that you’ve done to improve your experience as a developer, I’d love to hear them. &lt;/p&gt;

</description>
      <category>beginners</category>
      <category>mistakes</category>
      <category>selftaught</category>
      <category>solodeveloper</category>
    </item>
  </channel>
</rss>
