<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="31814" data-post-id="31814">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="veverkap" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/veverkap/120/9563_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  veverkap
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Does floki with either html5ever or mochiweb_html normalize the HTML?</p>
<p>I’ve used nokogiri on the Ruby side and one of my problems with it is that it normalizes the HTML.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="31814" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/web-scraping-tools/4823/12">Post #11</a>
	                </div>
	            </div>
              <div id="likers-container-31814" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="31814"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #11"></div>
  </section>
</div>
    <div class="postbit" id="31817" data-post-id="31817">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="mischov" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/mischov/120/2489_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  mischov
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p><a class="mention" href="/u/veverkap" rel="nofollow">@veverkap</a><br>
I am not exactly sure what you mean by normalizing the HTML, but both <code>html5ever</code> and <code>mochiweb_html</code> attempt to interpret malformed HTML into valid HTML, which means that the result of parsing might not be exactly the HTML you passed in (but generally in a good way).</p>
<p>If that doesn’t answer your question, could you give a more concrete example?</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="31817" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/web-scraping-tools/4823/13">Post #12</a>
	                </div>
	            </div>
              <div id="likers-container-31817" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="31817"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #12"></div>
  </section>
</div>
    <div class="postbit" id="31820" data-post-id="31820">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="veverkap" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/veverkap/120/9563_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  veverkap
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>That’s exactly what I mean.</p>
<p>We have a tool that we use to scrape HTML pages.  When we tried to use Mechanize (which uses Nokogiri under the hood), it would correct the HTML, which sometimes gave different results.</p>
<p>You answered my question, thanks!</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="31820" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/web-scraping-tools/4823/14">Post #13</a>
	                </div>
	            </div>
              <div id="likers-container-31820" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="31820"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #13"></div>
  </section>
</div>
    <div class="postbit" id="32308" data-post-id="32308">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="sntran" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sntran/120/22332_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  sntran
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I also started a little scraping framework based on the Python-based Scrapy. It’s on <a href="https://github.com/sntran/scrapex" class="inline-onebox" rel="noopener nofollow ugc">GitHub - sntran/scrapex: An Elixir open source and collaborative framework for extracting the data you need from websites. In a fast, simple, yet extensible way. Or just an experiment writing a scraper in Elixir to scratch my own itch. Use at your own risk. · GitHub</a></p>
<p>It uses HTTPoison for making HTTP request, and Floki to parse HTML. I tried not to bring the whole headless browser in, so it does not handle SPA.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="32308" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/web-scraping-tools/4823/15">Post #14</a>
	                </div>
	            </div>
              <div id="likers-container-32308" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="32308"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #14"></div>
  </section>
</div>
    <div class="postbit" id="32405" data-post-id="32405">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="adammokan" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/adammokan/120/26407_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  adammokan
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p><a class="mention" href="/u/_russellb" rel="nofollow">@_russellb</a>  - I’ve been using a combo of NightmareJS via ports (using <a href="https://hex.pm/packages/porcelain" rel="nofollow">Porcelain</a>). I’ve been scraping at a pretty large scale since last summer with Elixir. There are some more details in some previous threads of mine if you search.</p>
<p>The only downfall with Nightmare or any JS-capable solution is the CPU/memory resources needed. If you are just needing HTML capabilities, HTTPoison (<em>or swap with HTTPotion, raw hackney, etc</em>) works fine in my experience. Unfortunately, I do not have the HTML only luxury as I’m dealing with single page app, JS required systems. As far as the heavy resource load for JS stuff via headless browsing - I have a distributed elixir/erlang solution in place with dedicated scraping nodes I can bring up dynamically and dispatch work to from a master node. Everything is running headless on linux boxes (some in our own datacenter and some on AWS spot instances).</p>
<p>For parsing the results, I use Floki like most people do. Speed is never an issue here for me so I’ve not bothered with the other parsers out there.</p>
<p>FWIW, we came from a lot of legacy Ruby/Mechanize code. The Elixir stuff is much, much easier to maintain and way more stable. I do have times where Nightmare acts up and doesn’t release resources, but I resolve that with some elixir-based cleanup tasks that run every few minutes to check for zombie processes that get missed. Porcelain helps a lot for the port logic, but is not 100%. I also keep all crawling off my main logic node so I can afford to lose a crawl and just bounce a node without sweating it. I’d recommend something similar if you need large scale throughput. I just assume the job was lost if I do not get a reply back from a crawling node within five minutes and send it to another node.</p>
<p>Good luck!</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="32405" data-batch-url="/posts/batch_likers">
                        5
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/web-scraping-tools/4823/16">Post #15</a>
	                </div>
	            </div>
              <div id="likers-container-32405" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="32405"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #15"></div>
  </section>
</div>
    <div class="postbit" id="32789" data-post-id="32789">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="bzhr" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/bzhr/120/3683_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  bzhr
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I’ve been using Scrapy for a while and it is a nice and mature framework. I am writing Xpath selectors for getting data from htmls and using the built in Scrapy system for following links and building pipelines. There are some things that can be improved in Scrapy though. You need to write your own spider management process, when you have many spiders in a projects this gets complex. Also, today the same url that is crawled can contain frequently updated data. Scrapy is designed to through a bunch of URLs and store the data somewhere, but today the web works differently, I need to know if a field on a web site is updated. Seems like things like these can be managed very well in Elixir. Using xpath selectors (or the mentioned Rust implementation) is easy. Some html diff logic on top of that in order to listen for updates would be nice to have instead of how Scrapy functions.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="32789" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/web-scraping-tools/4823/17">Post #16</a>
	                </div>
	            </div>
              <div id="likers-container-32789" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="32789"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #16"></div>
  </section>
</div>
    <div class="postbit" id="32794" data-post-id="32794">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="bzhr" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/bzhr/120/3683_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  bzhr
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Seems like a nice start, taking some of Scrapy’s strenghts and impplementing in Elixir.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="32794" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/web-scraping-tools/4823/18">Post #17</a>
	                </div>
	            </div>
              <div id="likers-container-32794" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="32794"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #17"></div>
  </section>
</div>
    <div class="postbit" id="131048" data-post-id="131048">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="oltarasenko" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/oltarasenko/120/15709_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  oltarasenko
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I wanted to add this tiny library: <a href="https://github.com/oltarasenko/crawly" class="inline-onebox" rel="noopener nofollow ugc">GitHub - elixir-crawly/crawly: Crawly, a high-level web crawling &amp; scraping framework for Elixir. · GitHub</a> to our discussion list. You might find it useful, for the web scraping case.</p>
<p>I think it’s quite well documented, and could be used as a good starting point. Please find the relevant tutorial here:</p>
<p><a href="https://oltarasenko.github.io/crawly/#/?id=crawly-tutorial" rel="noopener nofollow ugc">Crawly Tutorial</a></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="131048" data-batch-url="/posts/batch_likers">
                        3
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/web-scraping-tools/4823/20">Post #19</a>
	                </div>
	            </div>
              <div id="likers-container-131048" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="131048"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #19"></div>
  </section>
</div>
    <div class="postbit" id="131061" data-post-id="131061">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="jihantoro" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/jihantoro/120/16385_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  jihantoro
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Web scraping is simple, IMHO there is two type of site :</p>
<ol>
<li>Server-Side Rendered page<br>
easy to scrape with curl or any HTTP Client (+ HTML Parser)</li>
<li>Javascript Rendered page<br>
A. You can use Headless / Browser Automation, but, it will be slow (+ HTML Parser)<br>
B. Do “little bit” Reverse Engineering on their Web API (FASTER)</li>
</ol>
<p>Important Point :</p>
<ul>
<li>Make sure your scrapper support Proxy Usage</li>
<li>If your site target has anti-scraper / crawler / bot (Like your bot follow pagination, 1-&gt;2-&gt;3 and so on) and it block your IP, you can use IP Rotation Service like  <a href="http://geosurf.com" rel="noopener nofollow ugc">geosurf.com</a> and <a href="http://luminati.io" rel="noopener nofollow ugc">luminati.io</a></li>
<li>In some Country / Site, Web Scraping are prohibited</li>
</ul> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="131061" data-batch-url="/posts/batch_likers">
                        4
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/web-scraping-tools/4823/21">Post #20</a>
	                </div>
	            </div>
              <div id="likers-container-131061" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="131061"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #20"></div>
  </section>
</div>
    <div class="postbit" id="131193" data-post-id="131193">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="oltarasenko" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/oltarasenko/120/15709_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  oltarasenko
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Thanks for your comment.</p>
<p>I would not say that web scraping is simple. Everything depends on the scale. Probably for very small sites you can use curl or wget. But I am talking about cases when you need to scrape millions of pages. And in these cases, things are way more complex, as you have to solve concurrency and resource management problems. Also, finding a good strategy of crawling a million pages is a challenge (also consider cases when URLS are dynamically generated)!</p>
<p>To answer your comments:</p>
<blockquote>
<ol>
<li>Server-Side Rendered page<br>
easy to scrape with curl or any HTTP Client (+ HTML Parser)</li>
</ol>
</blockquote>
<p>Will not scale. Also, you will have to avoid visiting pages twice and filtering out duplicates</p>
<blockquote>
<ol start="2">
<li>Javascript Rendered page<br>
A. You can use Headless / Browser Automation, but, it will be slow (+ HTML Parser)</li>
</ol>
</blockquote>
<p>In most of the cases, you will be able to find how a web page (e.g. a product page) is fetching data from API, so in most of the cases, you don’t need selenium.</p>
<blockquote>
<p>B. Do “little bit” Reverse Engineering on their Web API (FASTER)</p>
</blockquote>
<p>Unfortunately, this does not work. Most of the web sites do not have API. And those who have, would not provide a full and up to date data. Even more, some of the APIs are just horrible and can’t be used for data extraction.</p>
<blockquote>
<p>Important Point :</p>
<ul>
<li>Make sure your scrapper support Proxy Usage</li>
</ul>
</blockquote>
<p>It does</p>
<blockquote>
<ul>
<li>If your site target has anti-scraper / crawler / bot (Like your bot follow pagination, 1-&gt;2-&gt;3 and so on) and it block your IP, you can use IP Rotation Service like <a href="http://geosurf.com/" rel="noopener nofollow ugc">geosurf.com </a> and <a href="http://luminati.io/" rel="noopener nofollow ugc">luminati.io </a></li>
</ul>
</blockquote>
<p>You’re right. But please take into that proxies management is a complex stand-alone task. There are some quite advanced systems which allow overcoming bans with proxies, and I was developing one of them in the past.<br>
Also nowadays in some cases, it’s just not enough just to perform a request through another proxy, as the most advanced system would also perform 3-4 levels of request fingerprint analysis. With this regards, I would suggest looking at <a href="https://scrapinghub.com/crawlera" rel="noopener nofollow ugc">Crawlera</a></p>
<blockquote>
<ul>
<li>In some Country / Site, Web Scraping are prohibited</li>
</ul>
</blockquote>
<p>Well.. is that correct to assume the internet is also prohibited in these countries? Please take into account that no search engine can work without web scraping. And I don’t see the web without search these days. (But it’s just an opinion).</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="131193" data-batch-url="/posts/batch_likers">
                        4
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/web-scraping-tools/4823/22">Post #21</a>
	                </div>
	            </div>
              <div id="likers-container-131193" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="131193"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #21"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <a class="load-more-button" data-turbo-stream="true" href="/topics/4823/load_more?page=3">Load more posts (25 remaining)</a>
</div></template></turbo-stream>